¿Requiere la especificación SQL un GROUP BY en EXISTS ()

11

Microsoft actualmente permite esta sintaxis.

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

Tenga en cuenta que no hay GROUP BYen la EXISTScláusula, es ese ANSI SQL válido. ¿O es simplemente exponer un detalle de implementación?

Como referencia, esta misma sintaxis no está permitida en PostgreSQL.

ERROR: la columna "tx" debe aparecer en la cláusula GROUP BY o usarse en una función agregada

Pero esta sintaxis está permitida.

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

Y esta sintaxis está permitida.

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 pregunta surge de una conversación con @ErikE en el chat

Evan Carroll
fuente

Respuestas:

11

Lo encontré en la especificación SQL 2011 ...

Si el <select list>"*" simplemente está contenido en un <table subquery>que está contenido inmediatamente en un <exists predicate>, entonces el <select list>es equivalente a un <value expression>que es arbitrario <literal>.

Esto confirma que al *no ser equivalente a un literal arbitrario en este contexto , de hecho, PostgreSQL está rompiendo la especificación.

Tenga en cuenta que este es un problema distinto de

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

Que ambas bases de datos rechazan.

PostgreSQL,

ERROR: la columna "tx" debe aparecer en la cláusula GROUP BY o usarse en una función agregada

Servidor SQL,

La columna 'tx' no es válida en la lista de selección porque no está contenida ni en una función agregada ni en la cláusula GROUP BY.

Por qué este error persiste en PostgreSQL

Gracias a RhodiumToad en irc.freenode.net/#PostgreSQL por su ayuda para solucionar este problema. También señala la dificultad para resolver esta situación.

20:33 <RhodiumToad> el único problema es que en pg puede hacer existe (seleccione func () de ... donde func () es un SRF que podría devolver 0 filas

Un SRF es una función de retorno establecida.

En PostgreSQL, podemos usar, por ejemplo, un SRF para generar una serie del 1 al 10 ( generate_seriesestá en el núcleo)

SELECT * FROM generate_series(1,10); 

Y, también podemos ponerlo aquí.

SELECT generate_series(1,10);

Dos de ellos juntos nos dan una unión cruzada (producto cartesiano)

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

Pero, si alguno de esos devuelve 0 filas, no obtienes nada ... Efectivamente lo mismo

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

Y ese es el problema de optimizar esto por completo. Puede tener un SRF en una lista de selección dentro de una declaración EXIST que devuelve 0 filas y obliga a los EXISTS a evaluar a falso.

Evan Carroll
fuente