Dlaczego MySQL pozwala HAVING na użycie SELECT aliasów?

14

O ile mi wiadomo, kolejność przetwarzania kwerend logicznych, która jest konceptualną kolejnością interpretacji, zaczyna się od FROM w następujący sposób:

  1. OD
  2. GDZIE
  3. GRUPUJ WEDŁUG
  4. MAJĄCY
  5. WYBIERZ
  6. ZAMÓW PRZEZ

Po tej liście łatwo jest zrozumieć, dlaczego nie można wybrać WYBIERAJ aliasów w klauzuli WHERE, ponieważ alias nie został jeszcze utworzony. T-SQL (SQL Server) ściśle przestrzega tego i nie możesz używać aliasów SELECT, dopóki nie przejdziesz SELECT.

Ale w MySQL możliwe jest użycie aliasów SELECT w klauzuli HAVING, mimo że powinno (logicznie) być przetwarzane przed klauzulą ​​SELECT. Jak to mozliwe?

Dać przykład:

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

Instrukcja jest niepoprawna w języku T-SQL (ponieważ HAVING odnosi się do aliasu SELECT Amount) ...

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

... ale działa dobrze w MySQL.

W oparciu o to zastanawiam się:

  • Czy MySQL używa skrótu w regułach SQL, aby pomóc użytkownikowi? Może przy użyciu pewnego rodzaju analizy wstępnej?
  • Czy też MySQL używa innej pojęciowej kolejności interpretacji niż ta, którą przestrzegałem wszystkich RDBMS?
Ohlin
źródło
1
Domyślam się, że to twój drugi punkt.
a_horse_w_no_name
3
Sądzę, że nie powoduje to żadnych dwuznaczności ani zamieszania, dopóki nie obsługują funkcji rankingu. Wtedy SELECT C, ROW_NUMBER() OVER (ORDER BY X) AS RN FROM T GROUP BY C HAVING RN = 1będzie problematyczne, jak ROW_NUMBERbiegnie poHAVING
Martin Smith
Nie jestem pewien, jakie funkcje rankingu są obsługiwane przez MySQL. Jeśli chcesz numer wiersza trzeba utworzyć go w ten sposób: SELECT @rownum:=@rownum + 1 as row .... Być może powodem, dla którego obsługują aliasy SELECT, jest po prostu fakt, że mogą, ponieważ nie obsługują rzeczy, które uniemożliwiłyby ... kto wie? :)
Ohlin,
Jak wyjaśnia @MartinSmith, dopóki nie ma funkcji okna / rankingu, logiczna kolejność wykonywania HAVINGi SELECTklauzula mogą być zamienione. Tak więc nie ma w tym dwuznaczności i może uprościć wygląd kodu, gdy występują potworne wyrażenia SELECT.
ypercubeᵀᴹ
Mam nadzieję, że jest to nieco temat na temat, że odpowiedziałem na pytanie Tutaj cieszy się szybszymi wynikami (z distincts) ... z Alias in the Havingtym samym Explainwynikiem. Tak więc dzieje się trochę zmian w Optymalizatorze.
Drew

Odpowiedzi:

13

Cóż, jeśli masz takie pytanie, najlepszym źródłem informacji IMHO jest dokumentacja MySQL. Teraz do rzeczy. Jest to zachowanie rozszerzenia MySql, GROUP BYktóre jest domyślnie włączone.

Rozszerzenia MySQL do GROUP BY
MySQL rozszerza to zachowanie, aby umożliwić użycie aliasu w klauzuli HAVING dla kolumny zagregowanej

Jeśli chcesz mieć standardowe zachowanie, możesz wyłączyć to rozszerzenie za pomocą sql_mode ONLY_FULL_GROUP_BY

SET [SESSION | GLOBAL] sql_mode = ONLY_FULL_GROUP_BY;

Jeśli spróbujesz wykonać wyżej wymienione zapytanie w ONLY_FULL_GROUP_BYtrybie_sql, pojawi się następujący komunikat o błędzie:

Pole nie grupujące „Kwota” jest używane w klauzuli HAVING: WYBIERZ ROK (data zamówienia), LICZBA (*) jako Kwota Z GRUP ZGODNIE Z ROKIEM (data zamówienia) MAJĄC Kwota> 1

Oto wersja demonstracyjna SQLFiddle

Dlatego to od Ciebie zależy, jak skonfigurować i używać instancji MySQL.

peterm
źródło
Masz całkowitą rację co do dokumentacji. Po prostu nigdy nie myślałem, że może być napisane tak jasno, jak to zacytowałeś powyżej :) Dzięki za znalezienie ...
Ohlin,
Ta odpowiedź nie odpowiada: „Czy MySQL przeprowadza wstępną analizę, czy MySQL używa innej interpretacji pojęciowej?”.
Pacerier
2
@Pacerier MySQL „oczywiście dokonuje wstępnej analizy”, ponieważ optymalizator zapytań uwzględnia wszystkie aspekty zapytania, wybierając jednocześnie najlepszy plan zapytań. Pojęcie „innej interpretacji pojęciowej” zdradza nieporozumienie dotyczące faktu, że serwer może dowolnie wdrażać model koncepcyjny w dowolny sposób, który daje prawidłowy wynik. ORDER BY, na przykład może być obsługiwany znacznie wcześniej niż teoretycznie, jeśli optymalizator stwierdzi, że wiersze można początkowo odczytać w kolejności z indeksu, który jest już w pożądanej kolejności.
Michael - sqlbot
4

Dobre pytanie.

Myślę, że powinieneś uruchomić te zapytania

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

i sprawdź, w jaki sposób zapytanie jest przepisywane. jestem całkiem pewien, że optymalizator zapytań zastąpił Kwotę COUNT (*)

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

Tak jak robi to z

select 
 *
from 
 test
where 
 id = 5 - 3

po optymalizacji kwerendy jest coś takiego.

select 
 test.id as 'id'
from 
 test
where 
 test.id = 2
Raymond Nijland
źródło