Frage

Ich versuche, Funktionen einer bereits existierenden Anwendung hinzuzufügen und ich kam in einer MySQL-Ansicht etwas wie folgt aus:

SELECT
     AVG(table_name.col1),
     AVG(table_name.col2),
     AVG(table_name.col3),
     table_name.personID,
     table_name.col4
FROM table_name
GROUP BY table_name.personID;

OK, so gibt es ein paar Aggregatfunktionen. Sie können personID wählen, weil Sie durch sie sind zu gruppieren. Aber es ist die Auswahl auch eine Spalte, die nicht in einer Aggregatfunktion und ist nicht ein Teil der GROUP BY-Klausel. Wie ist das möglich??? Ist es nur einen zufälligen Wert auswählen, da die Werte auf jeden Fall nicht eindeutig zuzuordnen sind pro Gruppe?

Wenn ich von (MSSQL Server) kommen, das ist ein Fehler. Kann jemand dieses Verhalten uns erklären, und warum es in MySQL erlaubt?

War es hilfreich?

Lösung

Es ist wahr, dass diese Funktion einiger mehrdeutigen Abfragen ermöglicht, und gibt leise ein Ergebnis mit einem beliebigen Wert aus der Spalte gepflückt eingestellt. In der Praxis neigt es der Wert aus der Reihe innerhalb der Gruppe zu sein, die physisch zuerst gespeichert wird.

Diese Abfragen sind nicht mehrdeutig, wenn Sie Spalten auswählen, die funktional abhängig von der Spalte (n) in der GROUP BY-Kriterien sind. Mit anderen Worten, wenn kann es nur ein eindeutiger Wert der „mehrdeutig“ Spalte pro Wert sein, der die Gruppe definiert, dann ist es kein Problem. Diese Abfrage würde in Microsoft SQL Server illegal sein (und ANSI SQL), auch wenn es nicht logisch in Zweideutigkeit führen kann:

SELECT AVG(table1.col1), table1.personID, persons.col4
FROM table1 JOIN persons ON (table1.personID = persons.id)
GROUP BY table1.personID;

Auch MySQL hat einen SQL-Modus, um es per Standard zu machen verhalten: ONLY_FULL_GROUP_BY

FWIW, SQLite erlaubt auch diese mehrdeutigen GROUP BY-Klausel, aber es wählt den Wert aus der letzten Zeile in der Gruppe.


Zumindest in der Version, die ich getestet. Was es bedeutet, zu sein beliebigen ist, dass entweder MySQL oder SQLite deren Umsetzung in der Zukunft ändern könnte, und haben einige unterschiedliche Verhalten. Sie sollten daher nicht auf das Verhalten verlassen, bleiben sie, wie es zur Zeit wie dies in Zweifelsfällen ist. Es ist besser, Ihre Fragen zu umschreiben deterministisch und nicht mehrdeutig zu sein. Deshalb 5.7 MySQL jetzt ONLY_FULL_GROUP_BY standardmäßig ermöglicht.

Andere Tipps

Ich sollte nur ein bisschen länger gegoogelt haben ... Es scheint, dass ich gefunden meine Antwort .

  

MySQL erweitert die Verwendung von GROUP BY so   dass Sie nicht aggregierten Spalten verwenden   oder Berechnungen in der Liste SELECT   dass erscheinen nicht in der GROUP BY   Klausel. Sie können diese Funktion verwenden, um   eine bessere Leistung durch die Vermeidung von   unnötige Spaltensortierung und   Gruppierung. Zum Beispiel müssen Sie nicht   zur Gruppe auf customer.name in der   folgende Abfrage

     

Im Standard-SQL, würden Sie müssen hinzufügen   customer.name BY-Klausel an die Gruppe.   In MySQL ist der Name überflüssig.

Dennoch, dass nur scheint ... falsch.

select * from personel where p_id IN(select
min(dbo.personel.p_id)
FROM
personel
GROUP BY dbo.personel.p_adi)

Angenommen, Sie haben eine Abfrage wie folgt:

SELECT g, v 
FROM t
GROUP BY g;

In diesem Fall wird für jeden möglichen Wert für g, mysql nimmt eine der entsprechenden Werte von v.

Allerdings, die man gewählt wird, hängt von Umständen.

Ich habe irgendwo gelesen, dass für jede Gruppe von g, wird der erste Wert von v gehalten, in der Reihenfolge, wie die Datensätze wurden in die Tabelle t eingefügt.

Dies ziemlich hässlich ist, weil die Datensätze in einer Tabelle sollte als Satz behandelt werden, , wo die Reihenfolge der Elemente sollte keine Rolle spielen. Dies ist so, "mysql-ish" ...

Wenn Sie, welcher Wert bestimmen, wollen für v zu halten, benötigen Sie einen subselect für t wie folgt anzuwenden:

SELECT g, v 
FROM (
    SELECT * 
        FROM t 
        ORDER BY g, v DESC
) q
GROUP BY g;

So können Sie definieren, welche die Datensätze der Subquery bestellen werden durch die externe Abfrage verarbeitet, so können Sie darauf vertrauen, welcher Wert von v es für die einzelnen Werte von g abholt.

Wenn Sie jedoch einige WHERE-Bedingungen, dann müssen sehr vorsichtig sein. Wenn Sie die WHERE-Bedingung zu der Unterabfrage hinzufügen, dann wird es um das Verhalten zu halten, wird es immer den Wert zurückgeben Sie erwarten:

SELECT g, v 
FROM (
    SELECT * 
        FROM t 
        WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9' 
        ORDER BY g, v DESC
) q
GROUP BY g;

Dies ist, was Sie erwarten, die subselect Filter und Aufträge der Tabelle. Es hält die Datensätze, in denen g den angegebenen Wert und die externe Abfrage zurück hat, die und den ersten Wert für g v.

Wenn Sie jedoch die gleiche hinzufügen WHERE-Bedingung zu der äußeren Abfrage dann erhalten Sie ein nicht-deterministisches Ergebnis:

SELECT g, v 
FROM (
    SELECT * 
        FROM t 
        -- WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9' 
        ORDER BY g, v DESC
) q
WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
GROUP BY g;

Überraschenderweise können Sie verschiedene Werte für v erhalten, wenn die gleiche Abfrage immer wieder ausgeführt wird, die ... seltsam. Das erwartete Verhalten ist, alle Datensätze in der entsprechenden Reihenfolge von der Unterabfrage zu erhalten, filtert sie in der äußeren Abfrage und dann Kommissionierung die gleichen wie im vorherigen Beispiel gepflückt. Aber es funktioniert nicht.

Er nimmt einen Wert für v scheinbar zufällig. Die gleiche Abfrage zurückgegeben unterschiedliche Werte für v, wenn ich mehr (~ 20) mal ausgeführt, sondern die Verteilung war nicht einheitlich.

Wenn Sie stattdessen eine äußere der Zugabe WHERE Sie eine HAVING Bedingung wie folgt an:

SELECT g, v 
FROM (
    SELECT * 
        FROM t1 
        -- WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9' 
        ORDER BY g, v DESC
) q
-- WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
GROUP BY g
HAVING g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9';

Sie dann ein konsistentes Verhalten bekommen wieder.

Fazit: Ich würde vorschlagen, überhaupt nicht auf diese Technik verlassen können. Wenn Sie wirklich wollen / müssen, um dann WHERE-Bedingungen in der äußeren Abfrage zu vermeiden. Verwenden Sie es in der inneren Abfrage, wenn Sie können oder eine in der äußeren Abfrage HAVING-Klausel.

Ich habe es getestet mit diesen Daten:

CREATE TABLE t1 (
    v INT,
    g VARCHAR(36)
);

INSERT INTO t1 VALUES (1, '737a8783-110c-447e-b4c2-1cbb7c6b72c9');
INSERT INTO t1 VALUES (2, '737a8783-110c-447e-b4c2-1cbb7c6b72c9');

in mysql 5.6.41.

Vielleicht ist es nur ein Fehler ist, der / wurde in neueren Versionen behoben wird, bitte geben Sie Feedback, wenn Sie Erfahrung mit neueren Versionen haben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top