O padrão ANSI SQL define (capítulo 6.5, definir especificação de função) o seguinte comportamento para funções agregadas em conjuntos de resultados vazios:
COUNT(...) = 0
AVG(...) = NULL
MIN(...) = NULL
MAX(...) = NULL
SUM(...) = NULL
Retornar NULL para AVG, MIN e MAX faz todo o sentido, pois a média, o mínimo e o máximo de um conjunto vazio são indefinidos.
O último, no entanto, me incomoda: Matematicamente, a soma de um conjunto vazio é bem definida: 0
. Usando 0, o elemento neutro de adição, como o caso base, torna tudo consistente:
SUM({}) = 0 = 0
SUM({5}) = 5 = 0 + 5
SUM({5, 3}) = 8 = 0 + 5 + 3
SUM({5, NULL}) = NULL = 0 + 5 + NULL
Definir SUM({})
como null
basicamente torna "sem linhas" um caso especial que não se encaixa nos outros:
SUM({}) = NULL = NULL
SUM({5}) = 5 != NULL + 5 (= NULL)
SUM({5, 3}) = 8 != NULL + 5 + 3 (= NULL)
Existe alguma vantagem óbvia da escolha que foi feita (SUM sendo NULL) que eu perdi?
Respostas:
Receio que o motivo seja simplesmente o fato de as regras terem sido definidas de forma ad-hoc (como muitas outras "características" do padrão ISO SQL) em um momento em que as agregações SQL e sua conexão com a matemática eram menos compreendidas do que são agora. (*)
É apenas uma das extremamente inconsistências na linguagem SQL. Eles tornam o idioma mais difícil de ensinar, mais difícil de aprender, mais difícil de entender, mais difícil de usar, mais difícil para o que você quiser, mas é assim que as coisas são. As regras não podem ser alteradas como "frias" e "exatamente assim", por razões óbvias de compatibilidade com versões anteriores (se o comitê da ISO publicar uma versão final do padrão e os fornecedores começarem a implementar esse padrão, esses fornecedores não apreciarão muito se, em uma versão subsequente, as regras forem alteradas para que as implementações existentes (compatíveis) da versão anterior do padrão "falhem automaticamente em cumprir" a nova versão ...)
(*) Agora é melhor entender que agregações em um conjunto vazio se comportam de maneira mais consistente se retornarem sistematicamente o valor da identidade (= o que você chama de 'elemento neutro') do operador binário subjacente em questão. Esse operador binário subjacente para COUNT e SUM é uma adição e seu valor de identidade é zero. Para MIN e MAX, esse valor de identidade é o valor mais alto e mais baixo do tipo em questão, respectivamente, se os tipos em questão são finitos. Casos como média, meios harmônicos, medianas etc. são extremamente intricados e exóticos a esse respeito.
fonte
HIGHEST()
muitos não ser um elemento do tipo de dados, como por reais, onde a identidade seria o-Infinity
(e+Infinity
paraLOWEST()
)Num sentido pragmático, o resultado existente
NULL
é útil. Considere a seguinte tabela e instruções:A primeira instrução retorna NULL e a segunda retorna zero. Se um conjunto vazio retornasse zero
SUM
, precisaríamos de outros meios para distinguir uma soma verdadeira de zero de um conjunto vazio, talvez usando count. Se realmente queremos zero para o conjunto vazio, um simplesCOALESCE
fornecerá esse requisito.fonte
COALESCE()
como isso não vai distinguir o (0
soma) de um conjunto vazio do (NULL
soma) (dizem que a mesa tinha uma(10, NULL)
linha.SUM
coluna e volto a zero, sei sem precisar verificar se há pelo menos uma linha que não seja NULL sendo usada para me mostrar o resultado.DECODE(count(c2),0,NULL,sum(c2))
quando é.A principal diferença que posso ver é em relação ao tipo de dados. COUNT tem um tipo de retorno bem definido: um número inteiro. Todos os outros dependem do tipo de coluna / expressão que estão visualizando. Seu tipo de retorno deve ser compatível com todos os membros do conjunto (pense em float, moeda, decimal, bcd, período de tempo, ...). Como não existe um conjunto, você não pode sugerir um tipo de retorno, portanto, NULL é sua melhor opção.
Nota: Na maioria dos casos, você pode sugerir um tipo de retorno do tipo de coluna que está visualizando, mas é possível fazer SUMs não apenas nas colunas, mas em todos os tipos de coisas. Implicar um tipo de retorno pode ficar muito difícil, se não impossível, sob certas circunstâncias, especialmente quando você pensa em possíveis expansões do padrão (tipos dinâmicos vêm à mente).
fonte
SUM(column)
expressão? Não temos tabelas vazias - e todas as colunas têm tipos definidos? Por que deveria ser diferente para um conjunto de resultados vazio?24 + 56.07 + '2012-10-05' + 'Red'
? Quero dizer, não há nenhuma preocupação em comoSUM()
se comportará quando tivermos um problema ao definir a adição.