Warum erlaubt MySQL, dass HAVING SELECT-Aliase verwendet?


14

In SQL beginnt die logische Abfrageabarbeitungsreihenfolge, die die konzeptionelle Interpretationsreihenfolge darstellt, meines Wissens mit FROM auf folgende Weise:

  1. VON
  2. WO
  3. GRUPPIERE NACH
  4. HABEN
  5. WÄHLEN
  6. SORTIEREN NACH

Anhand dieser Liste können Sie leicht erkennen, warum in einer WHERE-Klausel keine SELECT-Aliase enthalten sind, da der Alias ​​noch nicht erstellt wurde. T-SQL (SQL Server) befolgt dies genau und Sie können SELECT-Aliase erst verwenden, wenn Sie SELECT bestanden haben.

In MySQL ist es jedoch möglich, SELECT-Aliase in der HAVING-Klausel zu verwenden, obwohl sie (logischerweise) vor der SELECT-Klausel verarbeitet werden sollten. Wie kann das möglich sein?

Um ein Beispiel zu geben:

SELECT YEAR(orderdate), COUNT(*) as Amount
FROM Sales.Orders
GROUP BY YEAR(orderdate) 
HAVING Amount>1;

Die Anweisung ist in T-SQL ungültig (da HAVING auf den SELECT-Alias ​​verweist Amount) ...

Msg 207, Level 16, State 1, Line 5
Invalid column name 'Amount'.

... funktioniert aber gut in MySQL.

Aufgrund dessen frage ich mich:

  • Übernimmt MySQL eine Verknüpfung in den SQL-Regeln, um dem Benutzer zu helfen? Vielleicht mit einer Art Voranalyse?
  • Oder verwendet MySQL eine andere konzeptionelle Interpretationsreihenfolge als die, der ich, obwohl alle RDBMS folgten?

1
Meine Vermutung ist, es ist Ihr zweiter Aufzählungspunkt.
a_horse_with_no_name

3
Nun, ich denke, es verursacht keine Mehrdeutigkeit oder Verwirrung, bis sie Ranking-Funktionen unterstützen. Dann SELECT C, ROW_NUMBER() OVER (ORDER BY X) AS RN FROM T GROUP BY C HAVING RN = 1wird es problematisch wie die ROW_NUMBERLäufe nach demHAVING
Martin Smith

Ich bin nicht sicher, welche Ranking-Funktionen von MySQL unterstützt werden. Wenn Sie die Zeilennummer wollen , müssen Sie es auf diese Weise erstellen: SELECT @rownum:=@rownum + 1 as row .... Vielleicht liegt der Grund, warum sie SELECT-Aliase unterstützen, einfach darin, dass sie dies können, weil sie keine Dinge unterstützen, die es unmöglich machen würden ... wer weiß? :)
Ohlin

Wie @MartinSmith erklärt, kann die logische Reihenfolge der Ausführung für HAVINGund der SELECTKlausel vertauscht werden , solange es keine Fenster- / Ranglistenfunktionen gibt . Dies ist also nicht mehr eindeutig und kann das Erscheinungsbild des Codes vereinfachen, wenn monströse Ausdrücke enthalten sind SELECT.
ypercubeᵀᴹ

Hoffentlich ist dies etwas themenbezogen zu sagen, dass ich eine Frage beantwortet habe. Hier werden schnellere Ergebnisse (mit distincts) ... mit Alias in the Havingder gleichen ExplainAusgabe erzielt . Es gibt also einige Variationen mit dem Optimierer.
Drew

Antworten:


13

Nun, wenn Sie eine Frage dieser Art haben, ist die beste Informationsquelle IMHO die MySQL-Dokumentation. Nun zum Punkt. Dies ist das Verhalten der MySQL-Erweiterung, für GROUP BYdie standardmäßig aktiviert ist.

MySQL-Erweiterungen für GROUP BY
MySQL erweitern dieses Verhalten , um die Verwendung eines Alias ​​in der HAVING-Klausel für die aggregierte Spalte zu ermöglichen

Wenn Sie Standardverhalten möchten, können Sie diese Erweiterung mit deaktivieren sql_mode ONLY_FULL_GROUP_BY

SET [SESSION | GLOBAL] sql_mode = ONLY_FULL_GROUP_BY;

Wenn Sie versuchen, die oben genannte Abfrage in ONLY_FULL_GROUP_BYsql_mode auszuführen, wird die folgende Fehlermeldung angezeigt:

Das nicht gruppierte Feld 'Betrag' wird in der HAVING-Klausel verwendet: SELECT YEAR (Bestelldatum), COUNT (*) als Betrag FROM Orders GROUP BY YEAR (Bestelldatum) HAVING Amount> 1

Hier ist die SQLFiddle- Demo

Daher liegt es an Ihnen, wie Sie Ihre Instanz von MySQL konfigurieren und verwenden.


Sie haben absolut Recht mit der Dokumentation. Ich hätte einfach nie gedacht, dass es so klar geschrieben sein könnte, wie Sie es oben zitiert haben :) Danke, dass Sie es gefunden haben ...
Ohlin

Diese Antwort gibt keine Antwort auf "Führt MySQL eine Voranalyse durch oder verwendet MySQL eine andere konzeptionelle Interpretation?".
Pacerier

2
@Pacerier MySQL führt natürlich eine "Voranalyse" durch, da das Abfrageoptimierungsprogramm alle Facetten der Abfrage berücksichtigt, während es auswählt, was seiner Meinung nach der beste Abfrageplan ist. Die Vorstellung einer "anderen konzeptuellen Interpretation" verrät ein Missverständnis der Tatsache, dass es dem Server freigestellt ist, das konzeptuelle Modell auf irgendeine Weise zu implementieren, die zu einem gültigen Ergebnis führt. ORDER BYDies kann beispielsweise viel früher als theoretisch angenommen geschehen, wenn das Optimierungsprogramm feststellt, dass die Zeilen zunächst in der Reihenfolge aus einem Index gelesen werden können, der bereits in der gewünschten Reihenfolge vorliegt.
Michael - sqlbot

4

Gute Frage.

Ich denke, Sie sollten diese Abfragen ausführen

EXPLAIN SELECT YEAR(orderdate), COUNT(*) as Amount
FROM Sales.Orders
GROUP BY YEAR(orderdate) 
HAVING Amount>1;
SHOW WARNINGS;

und überprüfen Sie, wie die Abfrage neu geschrieben wird. Ich bin mir ziemlich sicher, dass das Abfrageoptimierungsprogramm Amount durch COUNT (*) ersetzt.

SELECT YEAR(orderdate), COUNT(*) as Amount
FROM Sales.Orders
GROUP BY YEAR(orderdate) 
HAVING COUNT(*)>1;

Wie es geht mit

select 
 *
from 
 test
where 
 id = 5 - 3

After Query Optimizer ist so etwas.

select 
 test.id as 'id'
from 
 test
where 
 test.id = 2
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.