Czy specyfikacja SQL wymaga GROUP BY w EXISTS ()

11

Microsoft obecnie zezwala na tę składnię.

SELECT *
FROM ( VALUES (1) ) AS g(x)
WHERE EXISTS (
  SELECT *
  FROM ( VALUES (1),(1) )
    AS t(x)
  WHERE g.x = t.x
  HAVING count(*) > 1
);

Zauważ, że nie ma GROUP BYw tej EXISTSklauzuli, czy jest to poprawny ANSI SQL. A może po prostu ujawnia szczegół implementacji.

Dla porównania, ta sama składnia nie jest dozwolona w PostgreSQL.

BŁĄD: kolumna „tx” musi pojawić się w klauzuli GROUP BY lub być użyta w funkcji agregującej

Ale ta składnia jest dozwolona.

SELECT *
FROM ( VALUES (1) ) AS g(x)
WHERE EXISTS (
  SELECT 1  -- This changed from the first query
  FROM ( VALUES (1),(1) )
    AS t(x)
  WHERE g.x = t.x
  HAVING count(*) > 1
);

I ta składnia jest dozwolona.

SELECT *
FROM ( VALUES (1) ) AS g(x)
WHERE EXISTS (
  SELECT *
  FROM ( VALUES (1),(1) )
    AS t(x)
  WHERE g.x = t.x
  GROUP BY t.x  -- This changed from the first query
  HAVING count(*) > 1
);

Pytanie powstaje w wyniku rozmowy z @ErikE na czacie

Evan Carroll
źródło

Odpowiedzi:

11

Znalazłem to w specyfikacji SQL 2011 ...

Jeśli <select list>„*” jest po prostu zawarte w ciągu, <table subquery>który jest natychmiast zawarty w ciągu <exists predicate>, wówczas <select list>jest ono równoważne <value expression>dowolnemu, który jest dowolny <literal>.

Potwierdza to, że *nie będąc odpowiednikiem arbitralnego literału w tym kontekście, w rzeczywistości PostgreSQL łamie specyfikację.

Pamiętaj, że jest to odrębny problem

SELECT *
FROM ( VALUES (1),(2),(3) ) AS t(x)
HAVING count(*) > 1

Które obie bazy danych odrzucają.

PostgreSQL,

BŁĄD: kolumna „tx” musi pojawić się w klauzuli GROUP BY lub być użyta w funkcji agregującej

SQL Server,

Kolumna „tx” jest niepoprawna na liście wyboru, ponieważ nie jest zawarta ani w funkcji agregującej, ani w klauzuli GROUP BY.

Dlaczego ten błąd utrzymuje się w PostgreSQL

Podziękowania dla RhodiumToad na irc.freenode.net/#PostgreSQL za pomoc w rozwiązywaniu tego problemu. Wskazuje także na trudności w rozwiązaniu tej sytuacji

20:33 <RhodiumToad> jedynym problemem jest to, że w pg można zrobić istnieje (wybierz func () z ... gdzie func () jest SRF, który może zwrócić 0 wierszy

SRF to funkcja zwracająca zestaw.

W PostgreSQL możemy na przykład użyć SRF do wygenerowania serii od 1 do 10 ( generate_seriesjest w rdzeniu)

SELECT * FROM generate_series(1,10); 

I my również możemy to tutaj umieścić.

SELECT generate_series(1,10);

Dwa z nich dają nam połączenie krzyżowe (produkt kartezjański)

SELECT generate_series(1,10), generate_series(1,2);

Ale jeśli którykolwiek z tych zwróci 0-wierszy, nic nie dostaniesz. W rzeczywistości to samo

SELECT * FROM ( VALUES (1) ) AS t(x)
CROSS JOIN ( SELECT 1 LIMIT 0 ) AS g;

I to jest problem z całkowitą optymalizacją tego. Możesz mieć SRF na liście wyboru w instrukcji EXIST, która zwraca 0 wierszy i zmusza EXISTS do oceny na false.

Evan Carroll
źródło