Tę zagadkę natrafiłem w komentarzach tutaj
CREATE TABLE r (b INT);
SELECT 1 FROM r HAVING 1=1;
SQL Server i PostgreSQL zwracają 1 wiersz.
MySQL i Oracle zwracają zero wierszy.
Który jest poprawny? Czy oba są równie ważne?
aggregate
sql-standard
Martin Smith
źródło
źródło
SELECT COUNT(*) FROM r;
zwraca 1 wiersz (z0
), aSELECT COUNT(*) FROM r GROUP BY ();
nie zwraca wierszy.SELECT 1 WHERE 1=0 HAVING 1=1;
. SQL Server i PostgreSQL nadal zwracają jeden wiersz. Oracle chce OD DUALU i nie zwraca wierszy. MySQL nie kompiluje się ani z FROM DUAL, ani bez niego .SELECT 1 AS t FROM (SELECT 1) tmp WHERE 1=0 HAVING 1=1;
1-wiersz-bez-podwójnego i zwraca 0 wierszy.<group by clause>
,“GROUP BY ()”
oznacza to domniemaną.”. Czy oba zapytania nie powinny zwracać tych samych wyników?HAVING
Odpowiedzi:
Zgodnie ze standardem:
znaczy
Odniesienie ISO / IEC 9075-2: 2011 7.10 Reguła składniowa 1 (Część definicji klauzuli HAVING):
Ok, więc wszystko jest całkiem jasne.
Twierdzenie:
1=1
jest prawdziwym warunkiem wyszukiwania. Nie podam za to żadnego cytatu.Teraz
jest równoważne z
Odniesienie ISO / IEC 9075-2: 2011 7.10 Zasada ogólna 1:
Logika: Ponieważ warunek wyszukiwania jest zawsze prawdziwy, wynikiem jest wynik
R
, który jest wynikiem grupy według wyrażenia.Poniżej znajduje się fragment Ogólnych zasad 7.9 (definicja GRUPY WEDŁUG KLAUZULI)
Możemy zatem dojść do wniosku
daje zgrupowaną tabelę, składającą się z jednej grupy, z zerowymi wierszami (ponieważ R jest puste).
Fragment Zasad ogólnych z 7.12, który definiuje specyfikację zapytania (zwaną także instrukcją SELECT):
Dlatego, ponieważ tabela ma jedną grupę, musi mieć jeden wiersz wyników.
A zatem
powinien zwrócić zestaw wyników z 1 wierszem.
CO BYŁO DO OKAZANIA
źródło
Gdy istnieje
HAVING
klauzula bezWHERE
klauzuli:... to
GROUP BY ()
jest dorozumiane. Tak więc zapytanie powinno być równoważne z:... która powinna zgrupować wszystkie wiersze tabeli w jedną grupę (nawet jeśli tabela w ogóle nie ma wierszy - nadal jest to jedna grupa 0 wierszy) i zwrócić 1 wiersz. Po
HAVING
tymTrue
warunek nie powinien już mieć żadnego efektu.Pod innym kątem, ile wierszy powinno zwrócić takie zapytanie?
Jeden, zero lub „zero lub jeden, w zależności od tego, czy tabela jest pusta czy nie”?
Myślę, że jeden wiersz, bez względu na liczbę wierszy
r
.źródło
Z tego, co widzę, wygląda na to, że SQLServer i PostgerSQL wcale nie przejmują się przeglądaniem tabeli:
zwraca również tylko jeden wiersz. Nawet jeśli dokumentacja SQLServer mówi
to nie jest prawda w tym przypadku -
WHERE 1=1
zamiastHAVING
zwraca odpowiednią liczbę wierszy. Powiedziałbym, że to błąd optymalizatora (a przynajmniej błąd dokumentacji) ... Plan SQLServer pokazuje „Ciągłe skanowanie” w przypadkuHAVING
i „skanowanie tabeli” dlaWHERE
...Zachowanie Oracle i Mysql wydaje mi się bardziej logiczne i poprawne ...
źródło
explain
„Wynik (wiersze = 1) ...” dla posiadania i „Skanowanie sekwencji” dla „GDZIE”, również nie zagląda do tabeli. .. Myślę, że jest to w jakiś sposób związane z faktem, że „FROM” nie jest obowiązkowy w TSQL i PostgreSQL. Wiem, że Mysql również tego nie wymaga, ale ponieważ obsługujądual
, prawdopodobnie analizują zapytanie nieco inaczej. Zgadzam się, to brzmi jak spekulacja, ale mam nadzieję, że ma to jakiś sens.