La specifica SQL richiede un GROUP BY in EXISTS ()


11

Microsoft attualmente consente questa sintassi.

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

Si noti che GROUP BYnella EXISTSclausola non è presente , è valido ANSI SQL valido. O sta semplicemente esponendo un dettaglio di implementazione.

Per riferimento, questa stessa sintassi non è consentita in PostgreSQL.

ERRORE: la colonna "tx" deve apparire nella clausola GROUP BY o essere utilizzata in una funzione aggregata

Ma questa sintassi è consentita ..

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

E questa sintassi è consentita.

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

La domanda nasce da una conversazione con @ErikE in chat

Risposte:


11

L'ho trovato nelle specifiche di SQL 2011 ...

Se il <select list>"*" è semplicemente contenuto in un <table subquery>che è immediatamente contenuto in un <exists predicate>, allora <select list>è equivalente a un <value expression>che è arbitrario <literal>.

Ciò conferma che, *non essendo equivalente a un letterale arbitrario in questo contesto , PostgreSQL sta di fatto infrangendo le specifiche.

Tieni presente che questo è un problema distinto da

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

Che entrambi i database rifiutano.

PostgreSQL,

ERRORE: la colonna "tx" deve apparire nella clausola GROUP BY o essere utilizzata in una funzione aggregata

Server SQL,

La colonna 'tx' non è valida nell'elenco di selezione perché non è contenuta né in una funzione aggregata né nella clausola GROUP BY.

Perché questo bug persiste in PostgreSQL

Grazie a RhodiumToad su irc.freenode.net/#PostgreSQL per il suo aiuto nel risolvere questo problema. Sottolinea inoltre la difficoltà nel risolvere questa situazione

20:33 <RhodiumToad> l'unico problema è che in pg si può fare esiste (selezionare func () da ... dove il func () è un SRF che potrebbe restituire 0 righe

Un SRF è una funzione di ritorno impostata.

In PostgreSQL, possiamo ad esempio usare un SRF per generare una serie da 1-10 ( generate_seriesè nel core)

SELECT * FROM generate_series(1,10); 

E allo stesso modo possiamo metterlo qui.

SELECT generate_series(1,10);

Due di loro insieme ci danno un cross-join (prodotto cartesiano)

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

Ma, se uno di questi restituisce 0 righe non ottieni nulla .. In realtà lo stesso di questo

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

E questo è il problema con l'ottimizzazione del tutto. È possibile avere un SRF in un elenco di selezione all'interno di un'istruzione EXIST che restituisce 0 righe e forza gli EXISTS a valutare su false.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.