La norme ANSI SQL définit (chapitre 6.5, spécification des fonctions de définition) le comportement suivant pour les fonctions d'agrégation sur des jeux de résultats vides:
COUNT(...) = 0
AVG(...) = NULL
MIN(...) = NULL
MAX(...) = NULL
SUM(...) = NULL
Renvoyer NULL pour AVG, MIN et MAX est parfaitement logique, car la moyenne, le minimum et le maximum d'un ensemble vide ne sont pas définis.
Le dernier, cependant, me dérange: Mathématiquement, la somme d'un ensemble vide est bien défini: 0
. L'utilisation de 0, l' élément neutre de l'addition, comme cas de base rend tout cohérent:
SUM({}) = 0 = 0
SUM({5}) = 5 = 0 + 5
SUM({5, 3}) = 8 = 0 + 5 + 3
SUM({5, NULL}) = NULL = 0 + 5 + NULL
Définir SUM({})
comme null
fait essentiellement "pas de lignes" un cas spécial qui ne correspond pas aux autres:
SUM({}) = NULL = NULL
SUM({5}) = 5 != NULL + 5 (= NULL)
SUM({5, 3}) = 8 != NULL + 5 + 3 (= NULL)
Y a-t-il un avantage évident du choix qui a été fait (SUM étant NULL) que j'ai manqué?
Réponses:
Je crains que la raison en soit simplement que les règles ont été définies de manière ad hoc (comme beaucoup d'autres "fonctionnalités" de la norme ISO SQL) à une époque où les agrégations SQL et leur connexion avec les mathématiques étaient moins comprises qu'elles ne le sont maintenant. (*).
Ce n'est qu'une des nombreuses incohérences du langage SQL. Ils rendent la langue plus difficile à enseigner, plus difficile à apprendre, plus difficile à comprendre, plus difficile à utiliser, plus difficile à tout ce que vous voulez, mais c'est exactement ainsi que les choses sont. Les règles ne peuvent pas être changées "à froid" et "juste comme ça", pour des raisons évidentes de rétrocompatibilité (si le comité ISO publie une version finale de la norme, et que les fournisseurs se mettent ensuite à appliquer cette norme, alors ces fournisseurs n'apprécieront pas c'est très bien si dans une version ultérieure, les règles sont modifiées de telle sorte que les implémentations existantes (conformes) de l'ancienne version de la norme "ne parviennent pas automatiquement à se conformer" à la nouvelle version ...)
(*) Il est désormais mieux compris que les agrégations sur un ensemble vide se comportent de manière plus cohérente si elles renvoient systématiquement la valeur d'identité (= ce que vous appelez «l'élément neutre») de l'opérateur binaire sous-jacent à portée de main. Cet opérateur binaire sous-jacent pour COUNT et SUM est un ajout et sa valeur d'identité est zéro. Pour MIN et MAX, cette valeur d'identité est respectivement la valeur la plus élevée et la plus basse du type en question, si les types concernés sont finis. Des cas comme la moyenne, les moyennes harmoniques, les médianes, etc. sont cependant extrêmement complexes et exotiques à cet égard.
la source
HIGHEST()
beaucoup ne sont pas un élément du type de données, comme pour Reals où l'identité serait le-Infinity
(et+Infinity
pourLOWEST()
)Dans un sens pragmatique, le résultat existant de
NULL
est utile. Considérez le tableau et les instructions suivants:La première instruction renvoie NULL et la seconde renvoie zéro. Si un ensemble vide renvoyait zéro car
SUM
nous aurions besoin d'un autre moyen pour distinguer une vraie somme de zéro d'un ensemble vide, peut-être en utilisant count. Si nous voulons en effet zéro pour l'ensemble vide, un simpleCOALESCE
fournira cette exigence.la source
COALESCE()
comme celle-ci ne distinguera pas la0
somme ( ) d'un ensemble vide de laNULL
somme () (disons que la table avait une(10, NULL)
ligne.SUM
une colonne et que je reviens à zéro, je le sais sans avoir à vérifier qu'il y a au moins une ligne non NULL utilisée pour me montrer le résultat.DECODE(count(c2),0,NULL,sum(c2))
quand il l'est.La principale différence que je peux voir concerne le type de données. COUNT a un type de retour bien défini: un nombre entier. Tous les autres dépendent du type de colonne / expression qu'ils regardent. Leur type de retour doit être compatible avec tous les membres de l'ensemble (think float, currency, decimal, bcd, timepan, ...). Puisqu'il n'y a aucun ensemble, vous ne pouvez pas impliquer un type de retour, donc NULL est votre meilleure option.
Remarque: Dans la plupart des cas, vous pouvez impliquer un type de retour à partir du type de colonne que vous regardez, mais vous pouvez faire des SUM non seulement sur des colonnes mais sur toutes sortes de choses. Impliquer un type de retour peut devenir très difficile, voire impossible, dans certaines circonstances, en particulier lorsque vous pensez à des extensions possibles de la norme (les types dynamiques viennent à l'esprit).
la source
SUM(column)
expression? N'avons-nous pas des tables vides - et là toutes les colonnes ont des types définis? Pourquoi devrait-il en être différemment pour un jeu de résultats vide?24 + 56.07 + '2012-10-05' + 'Red'
? Je veux dire qu'il n'y a aucune pinte à s'inquiéter de la façon dontSUM()
se comportera lorsque nous aurons un problème à définir l'ajout.