Me deparei com este quebra-cabeça nos comentários aqui
CREATE TABLE r (b INT);
SELECT 1 FROM r HAVING 1=1;
SQL Server e PostgreSQL retornam 1 linha.
MySQL e Oracle retornam zero linhas.
Qual é correto? Ou ambos são igualmente válidos?
aggregate
sql-standard
Martin Smith
fonte
fonte
SELECT COUNT(*) FROM r;
retorna 1 linha (com0
), enquantoSELECT COUNT(*) FROM r GROUP BY ();
não retorna nenhuma linha.SELECT 1 WHERE 1=0 HAVING 1=1;
. O SQL Server e o PostgreSQL ainda retornam uma linha. O Oracle quer FROM DUAL e não retorna linhas. O MySQL não compila nem com FROM DUAL nem sem ele .SELECT 1 AS t FROM (SELECT 1) tmp WHERE 1=0 HAVING 1=1;
1 linha-no-dual e retorna 0 linhas.<group by clause>
, então“GROUP BY ()”
está implícito." As duas consultas não deveriam retornar os mesmos resultados?HAVING
diferente): SQL-fiddle 2: TENDO torna as coisas diferentesRespostas:
De acordo com o padrão:
significa
Citação ISO / IEC 9075-2: 2011 7.10 Regra de sintaxe 1 (parte da definição da cláusula HAVING):
Ok, então isso é bem claro.
Afirmação:
1=1
é verdadeira condição de pesquisa. Não fornecerei nenhuma citação para isso.Agora
é equivalente a
Citação ISO / IEC 9075-2: 2011 7.10 Regra Geral 1:
Lógica: como a condição de pesquisa é sempre verdadeira, o resultado é
R
, que é o resultado do grupo por expressão.A seguir, um trecho das Regras Gerais de 7.9 (a definição do GRUPO POR CLÁUSULA)
Assim, podemos concluir que
resulta em uma tabela agrupada, composta por um grupo, com zero linhas (já que R está vazio).
Um trecho das Regras Gerais da 7.12, que define uma Especificação de Consulta (também conhecida como instrução SELECT):
Portanto, como a tabela possui um grupo, ela deve ter uma linha de resultado.
portanto
deve retornar um conjunto de resultados de 1 linha.
QED
fonte
Quando existe uma
HAVING
cláusula, sem umaWHERE
cláusula:... então
GROUP BY ()
está implícito. Portanto, a consulta deve ser equivalente a:... que deve agrupar todas as linhas da tabela em um grupo (mesmo que a tabela não tenha linhas - ainda é um grupo de 0 linhas) e retorna 1 linha. O
HAVING
com aTrue
condição não deve ter efeito algum depois disso.De um ângulo diferente, quantas linhas uma consulta como essa deve retornar?
Um, zero ou "zero ou um, dependendo se a tabela está vazia ou não"?
Eu acho que uma linha, não importa quantas linhas
r
tem.fonte
Pelo que vejo, parece que o SQLServer e o PostgerSQL não se incomodam em olhar para a tabela:
também retorna apenas uma linha. Embora os documentos do SQLServer digam
isso não é verdade neste caso - em
WHERE 1=1
vez deHAVING
retornar o número adequado de linhas. Eu diria que é um bug do otimizador (ou pelo menos um bug na documentação) ... O plano do SQLServer mostra 'Constant scan' no caso deHAVING
e 'table scan' forWHERE
...O comportamento do Oracle e Mysql parece mais lógico e correto para mim ...
fonte
explain
"Resultado (linhas = 1) ..." por ter e "Seq Scan" por "WHERE", também não olha para a tabela. .. Eu acho que está de alguma forma relacionado ao fato de que "FROM" não é obrigatório no TSQL e no PostgreSQL. Eu sei que o Mysql também não exige, mas como eles suportamdual
, provavelmente analisam a consulta um pouco diferente. Concordo, parece uma especulação, mas espero que faça algum sentido.