Benötigt die SQL-Spezifikation eine GROUP BY in EXISTS ()

11

Microsoft erlaubt diese Syntax derzeit.

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
);

Beachten Sie, dass GROUP BYdie EXISTSKlausel kein gültiges ANSI-SQL enthält. Oder wird lediglich ein Implementierungsdetail angezeigt?

Als Referenz ist dieselbe Syntax in PostgreSQL nicht zulässig.

FEHLER: Die Spalte "tx" muss in der GROUP BY-Klausel erscheinen oder in einer Aggregatfunktion verwendet werden

Diese Syntax ist jedoch zulässig.

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
);

Und diese Syntax ist erlaubt.

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
);

Die Frage ergibt sich aus einem Gespräch mit @ErikE im Chat

Evan Carroll
quelle

Antworten:

11

Ich habe es in der SQL 2011-Spezifikation gefunden ...

Wenn das <select list>"*" einfach in einem enthalten <table subquery>ist, das unmittelbar in einem enthalten ist <exists predicate>, dann <select list>ist das äquivalent zu einem <value expression>, das willkürlich ist <literal>.

Dies bestätigt, dass PostgreSQL tatsächlich die Spezifikation bricht, indem es* in diesem Zusammenhang keinem beliebigen Literal entspricht .

Denken Sie daran, dass dies ein unterschiedliches Problem ist

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

Was beide Datenbanken ablehnen.

PostgreSQL,

FEHLER: Die Spalte "tx" muss in der GROUP BY-Klausel erscheinen oder in einer Aggregatfunktion verwendet werden

SQL Server,

Die Spalte 'tx' ist in der Auswahlliste ungültig, da sie weder in einer Aggregatfunktion noch in der GROUP BY-Klausel enthalten ist.

Warum dieser Fehler in PostgreSQL weiterhin besteht

Vielen Dank an RhodiumToad auf irc.freenode.net/#PostgreSQL für seine Hilfe bei der Fehlerbehebung. Er weist auch auf die Schwierigkeit hin, diese Situation zu lösen

20:33 <RhodiumToad> Das einzige Problem ist, dass in pg, das Sie tun können, vorhanden ist (wählen Sie func () aus ... wobei func () eine SRF ist, die möglicherweise 0 Zeilen zurückgibt

Ein SRF ist eine Set-Return-Funktion.

In PostgreSQL können wir beispielsweise eine SRF verwenden, um eine Reihe von 1-10 zu generieren ( generate_seriesbefindet sich im Kern).

SELECT * FROM generate_series(1,10); 

Und wir können es auch hier richtig stellen.

SELECT generate_series(1,10);

Zwei von ihnen zusammen geben uns eine Querverbindung (kartesisches Produkt)

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

Wenn jedoch eine dieser Zeilen 0-Zeilen zurückgibt, erhalten Sie nichts

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

Und das ist das Problem bei der vollständigen Optimierung. Sie können eine SRF in einer Auswahlliste innerhalb einer EXIST-Anweisung haben, die 0 Zeilen zurückgibt und die EXISTS zwingt, auf false auszuwerten.

Evan Carroll
quelle