MySQL
Fehler 1055: ONLY_FULL_GROUP_BY: etwas ist nicht in der GROUP BY-Klausel enthalten ...
Suche…
Einführung
GROUP BY
, oder es zumindest zu erschweren, dass Entwickler von Abfrageschreiben davon gebrannt werden.
Bemerkungen
MySQL enthält seit langem eine notorische, nicht standardmäßige Erweiterung für GROUP BY
, die ein seltsames Verhalten im Namen der Effizienz ermöglicht. Diese Erweiterung hat es unzähligen Entwicklern auf der ganzen Welt ermöglicht, GROUP BY
im Produktionscode zu verwenden, ohne vollständig zu verstehen, was sie tun.
Es ist insbesondere nicht SELECT *
, SELECT *
in einer GROUP BY
Abfrage zu verwenden, da eine Standard- GROUP BY
Klausel das Auflisten der Spalten erfordert. Viele Entwickler haben das leider getan.
Lesen Sie dies. https://dev.mysql.com/doc/refman/5.7/de/group-by-handling.html
Das MySQL-Team hat versucht, dieses Missverständnis zu beheben, ohne den Produktionscode zu beeinträchtigen. In sql_mode
ein sql_mode
Flag mit dem Namen ONLY_FULL_GROUP_BY
, um das Standardverhalten zu erzwingen. In einer kürzlich veröffentlichten Version wurde das Flag standardmäßig aktiviert. Wenn Sie Ihr lokales MySQL auf 5.7.14 aktualisiert haben, wurde das Flag aktiviert und Ihr Produktionscode, abhängig von der alten Erweiterung, funktioniert nicht mehr.
Wenn Sie vor kurzem begonnen haben, 1055 Fehler zu erhalten, welche Entscheidungen treffen Sie?
- Korrigieren Sie die fehlerhaften SQL-Abfragen, oder fordern Sie die Autoren dazu auf.
- Führen Sie mit der von Ihnen verwendeten Anwendungssoftware eine Version von MySQL-kompatibel aus
- Ändern Sie den
sql_mode
Ihres Servers, um den neu eingestelltenONLY_FULL_GROUP_BY
Modus zuONLY_FULL_GROUP_BY
.
Sie können den Modus durch einen SET
Befehl ändern.
SET sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'
Sie sollten den Trick ausführen, wenn Sie es tun, nachdem Ihre Anwendung eine Verbindung zu MySQL hergestellt hat.
Sie können die init-Datei auch in Ihrer MySQL-Installation finden, die sql_mode=
und in ONLY_FULL_GROUP_BY
auslassen und den Server neu starten.
Verwendung und Missbrauch von GROUP BY
SELECT item.item_id, item.name, /* not SQL-92 */
COUNT(*) number_of_uses
FROM item
JOIN uses ON item.item_id, uses.item_id
GROUP BY item.item_id
zeigt die Zeilen in einer Tabelle namens item
und die Anzahl der zugehörigen Zeilen in einer Tabelle mit dem Namen uses
. Das funktioniert gut, aber leider nicht Standard-SQL-92.
Warum nicht? weil die SELECT
Klausel (und die ORDER BY
Klausel) in GROUP BY
Abfragen Spalten enthalten müssen, die sind
- in der
GROUP BY
Klausel erwähnt, oder - Aggregatfunktionen wie
COUNT()
,MIN()
und dergleichen.
Die SELECT
Klausel dieses Beispiels erwähnt item.name
, eine Spalte, die keines dieser Kriterien erfüllt. MySQL 5.6 und frühere ONLY_FULL_GROUP_BY
lehnen diese Abfrage ab, wenn der SQL-Modus ONLY_FULL_GROUP_BY
enthält.
Diese Beispielabfrage kann so gemacht werden, dass sie dem SQL-92-Standard entspricht, indem die GROUP BY
Klausel wie GROUP BY
wird.
SELECT item.item_id, item.name,
COUNT(*) number_of_uses
FROM item
JOIN uses ON item.item_id, uses.item_id
GROUP BY item.item_id, item.name
Der spätere SQL-99-Standard ermöglicht einer SELECT
Anweisung, nicht aggregierte Spalten aus dem Gruppenschlüssel auszulassen, wenn das DBMS eine funktionale Abhängigkeit zwischen diesen und den Gruppenschlüsselspalten nachweisen kann. Da item.name
funktional von item.item_id
, ist das ursprüngliche Beispiel gültiges SQL-99. MySQL hat in Version 5.7 einen funktionellen Abhängigkeitsbeweiser erhalten . Das ursprüngliche Beispiel funktioniert unter ONLY_FULL_GROUP_BY
.
Missbrauch von GROUP BY zur Rückgabe unvorhersehbarer Ergebnisse: Murphy's Law
SELECT item.item_id, uses.category, /* nonstandard */
COUNT(*) number_of_uses
FROM item
JOIN uses ON item.item_id, uses.item_id
GROUP BY item.item_id
zeigt die Zeilen in einer Tabelle namens item und die Anzahl der zugehörigen Zeilen in einer Tabelle mit dem Namen use an. Es zeigt auch den Wert einer Spalte mit der Bezeichnung " uses.category
.
Diese Abfrage funktioniert in MySQL (bevor das Flag ONLY_FULL_GROUP_BY
). Es verwendet die nicht standardmäßige Erweiterung von MySQL für GROUP BY
.
Aber die Abfrage hat ein Problem: wenn mehrere Zeilen in der uses
die übereinstimmen ON
Zustand in der JOIN
- Klausel, MySQL gibt die category
Spalte von nur einer dieser Zeilen. Welche reihe Der Verfasser der Abfrage und der Benutzer der Anwendung erfahren dies nicht im Voraus. Formal gesehen ist es unvorhersehbar : MySQL kann jeden gewünschten Wert zurückgeben.
Unvorhersehbar ist wie zufällig, mit einem signifikanten Unterschied. Man könnte erwarten, dass sich eine zufällige Wahl von Zeit zu Zeit ändert. Wenn eine Auswahl zufällig war, können Sie sie daher beim Debuggen oder Testen finden. Das unvorhersehbare Ergebnis ist schlimmer: MySQL gibt jedes Mal dasselbe Ergebnis zurück, wenn Sie die Abfrage verwenden, bis dies nicht der Fall ist. Manchmal führt eine neue Version des MySQL-Servers zu einem anderen Ergebnis. Manchmal ist es eine wachsende Tabelle, die das Problem verursacht. Was schief gehen kann, wird schief gehen und wenn Sie es nicht erwarten. Das nennt man Murphys Gesetz .
Das MySQL-Team hat daran gearbeitet, dass Entwickler diesen Fehler noch schwieriger machen können. Neuere Versionen von MySQL in der 5.7-Sequenz haben ein sql_mode
Flag namens ONLY_FULL_GROUP_BY
. Wenn dieses Flag gesetzt ist, gibt der MySQL-Server den Fehler 1055 zurück und lehnt die Ausführung dieser Art von Abfrage ab.
Missbrauch von GROUP BY mit SELECT * und deren Behebung.
Manchmal sieht eine Abfrage mit einem *
in der SELECT
Klausel so aus.
SELECT item.*, /* nonstandard */
COUNT(*) number_of_uses
FROM item
JOIN uses ON item.item_id, uses.item_id
GROUP BY item.item_id
Eine solche Abfrage muss ONLY_FULL_GROUP_BY
werden, um den Standard ONLY_FULL_GROUP_BY
erfüllen.
Dazu benötigen wir eine Unterabfrage, die GROUP BY
korrekt verwendet, um den Wert number_of_uses
für jede item_id
. Diese Unterabfrage ist kurz und süß, weil es nur auf suchen braucht uses
Tabelle.
SELECT item_id, COUNT(*) number_of_uses
FROM uses
GROUP BY item_id
Dann können wir diese Unterabfrage mit der Join - item
- Tabelle.
SELECT item.*, usecount.number_of_uses
FROM item
JOIN (
SELECT item_id, COUNT(*) number_of_uses
FROM uses
GROUP BY item_id
) usecount ON item.item_id = usecount.item_id
Dadurch kann die GROUP BY
Klausel einfach und korrekt sein, und wir können auch den *
-Spezifizierer verwenden.
Hinweis: Trotzdem vermeiden kluge Entwickler die Verwendung des *
-Spezifizierers auf jeden Fall. Es ist normalerweise besser, die gewünschten Spalten in einer Abfrage aufzulisten.
ANY_VALUE ()
SELECT item.item_id, ANY_VALUE(uses.tag) tag,
COUNT(*) number_of_uses
FROM item
JOIN uses ON item.item_id, uses.item_id
GROUP BY item.item_id
Zeigt die Zeilen in einer Tabelle mit dem Namen item
, die Anzahl der zugehörigen Zeilen und einen der Werte in der zugehörigen Tabelle mit dem Namen uses
.
Sie können sich diese ANY_VALUE()
Funktion als eine Art Aggregatfunktion ANY_VALUE()
. Anstatt einen Zähler, eine Summe oder ein Maximum zurückzugeben, weist es den MySQL-Server an, beliebig einen Wert aus der betreffenden Gruppe auszuwählen. Es ist eine Möglichkeit, den Fehler 1055 zu umgehen.
Seien Sie vorsichtig, wenn Sie ANY_VALUE()
in Abfragen in Produktionsanwendungen verwenden.
Es sollte wirklich SURPRISE_ME()
heißen. Es gibt den Wert einer Zeile in der GROUP BY-Gruppe zurück. Welche Zeile zurückgegeben wird, ist unbestimmt. Das heißt, es liegt vollständig am MySQL-Server. Formal gibt es einen unvorhersehbaren Wert zurück.
Der Server wählt keinen zufälligen Wert, der ist schlimmer. Bei jeder Ausführung der Abfrage wird derselbe Wert zurückgegeben, bis dies nicht der Fall ist. Sie kann sich ändern oder nicht, wenn eine Tabelle wächst oder schrumpft oder wenn der Server mehr oder weniger RAM hat oder wenn sich die Serverversion ändert oder wenn der Mars sich im Hintergrund befindet (was immer dies bedeutet) oder ohne Grund.
Du wurdest gewarnt.