ANSI SQLがSUM(行なし)をNULLとして定義するのはなぜですか?


28

ANSI SQL標準定義(章6.5、セット機能仕様)空の結果セット上の集約関数の次の動作:

COUNT(...) = 0
AVG(...) = NULL
MIN(...) = NULL
MAX(...) = NULL
SUM(...) = NULL

空のセットの平均、最小、最大は定義されていないため、AVG、MIN、MAXにNULLを返すことは完全に理にかなっています。

ただし、最後の1つは気になります。数学的には、空のセットのSUMは明確に定義されています0。基本ケースがすべての一貫性を保つため、加算の中立要素である0を使用します。

SUM({})        = 0    = 0
SUM({5})       = 5    = 0 + 5
SUM({5, 3})    = 8    = 0 + 5 + 3
SUM({5, NULL}) = NULL = 0 + 5 + NULL

定義SUM({})として、null基本的に「何行」他の人とでは収まらない特殊なケースになりません。

SUM({})     = NULL  = NULL
SUM({5})    = 5    != NULL + 5 (= NULL)
SUM({5, 3}) = 8    != NULL + 5 + 3 (= NULL)

私が見逃した選択(SUMがNULL)の明らかな利点はありますか?


注:これは、特にSQL Serverに関してStackOverflowで質問した一般的なバージョンです。
ハインジ

5
はい、同意します:COUNTとSUMは一貫して動作しません。
AK

回答:


20

私はそれを怖い理由は、(非常に多くの他の同様の「特徴」ルールはアドホックな方法で設定されたことを単にであるISO SQLの集計と数学との接続が少ない彼らは今よりよく理解された時にSQL標準) (*)。

これは、SQL言語における非常に多くの矛盾の1つにすぎません。彼らは言語を教えるのを難しくし、学びにくくし、理解しにくく、使いにくく、あなたが望むものに難しくしますが、それは物事がそうである方法です。後方互換性の明らかな理由により、ルールを「コールド」および「そのように」変更することはできません(ISO委員会が標準の最終バージョンを公開し、ベンダーがその標準を実装しようとすると、それらのベンダーは高く評価されません後続のバージョンで、以前のバージョンの標準の既存の(準拠)実装が「自動的に新しいバージョンに準拠しない」ようにルールが変更された場合は非常に重要です...)

(*)現在の空のセットの集計は、基礎となる二項演算子のID値(=「中立要素」と呼ぶもの)を体系的に返す場合、より一貫して動作することがよりよく理解されるようになりました。COUNTおよびSUMの基礎となる二項演算子は加算であり、そのID値はゼロです。MINおよびMAXの場合、関係するタイプが有限である場合、そのID値はそれぞれ、手元のタイプの最高値と最低値です。ただし、平均化、調和平均、中央値などの場合は、この点で非常に複雑でエキゾチックです。


nullは、minとmaxの空のセットに対して意味があると思います。アイデンティティ値は実際には不明であると言うかもしれませんが、n * 0が常に0であるのと同じ理由で、値の合計は0です。しかし、minとmaxは異なります。結果がレコードなしで適切に定義されているとは思わない。
クリス・トラヴァース

また、nullセットに対するavg()は、0/0がこのコンテキストで適切に定義されていないため、nullとして意味があります。
ラバーズ

5
MINとMAXはそれほど違いはありません。基礎となる二項演算子LOWESTOF(x、y)およびHIGHESTOF(x、y)をそれぞれ取ります。これらの二項演算子にはID値があります。どちらの場合も(関係する型が有限の場合)、forall x:LOWESTOF(z、x)= xおよびforall y:HIGHESTOF(y、z)= yのような値zが実際に存在するためです。(ID値は両方の場合で同じではありませんが、両方の場合に存在します。)結果は一見非常に直感に反するように見えますが、数学的現実を否定することはできません。
アーウィンスモート

@Erwinは:のように私は、いくつかの操作の身元ことを除いて、すべてのあなたのポイントに同意HIGHEST()の多くは、のようなアイデンティティのようになりレアルのために、データ型の要素ではない-Infinity(と+InfinityのためにLOWEST()
ypercubeᵀᴹ

1
@SQLキウイ。静的型チェックを忘れていますか?SUM()のような式が常に整数を返すかのように静的型チェッカーによって処理される場合、SUM()呼び出しが整数でないもの(例:空のリレーション)を返すことは不可能であることは明らかです。
アーウィンSmout

3

実用的な意味では、の既存の結果NULLは有用です。次の表とステートメントを考慮してください。

C1 C2
-- --
 1  3 
 2 -1 
 3 -2 

SELECT SUM(C2) FROM T1 WHERE C1 > 9;

SELECT SUM(C2) FROM T1 WHERE C1 < 9;

最初のステートメントはNULLを返し、2番目のステートメントはゼロを返します。空のセットがゼロを返した場合SUM、おそらくカウントを使用して、真のゼロの合計を空のセットと区別する別の手段が必要になります。空のセットに実際にゼロCOALESCEが必要な場合は、単純なものがその要件を満たします。

SELECT COALESCE(SUM(C2),0) FROM T1 WHERE C1 > 9;

1
結果として、SUM(set1とset2の結合)<> SUM(set1)+ SUM(set2)。これは、任意の数値+ NULL = NULLであるためです。あなたにとって理にかなっていますか?
AK

2
@Leigh:このCOALESCE()ように使用して0も、空のセットの()合計と()合計は区別されませんNULL(テーブルに(10, NULL)行があったとします。
ypercubeᵀᴹ12年

また、SUM(空のセット)とSUM(1つ以上のNULLのセット)を区別することはできません。まったく区別する必要がありますか?
AK

@AlexKuznetsov-少なくとも1つの行に値が含まれている限り、空のセットの合計と1つ以上のNULLを含むセットの合計を区別できます。セットにNULLのみが含まれている場合、このNULLセットをすべてのNULL値のセットと区別することはできません。私のポイントは、すべての場合に役立つということではなく、単に役立つことができるということです。私の場合SUM、カラム、私に結果を表示するために使用されている少なくとも一つのNULLでない行があることを確認しなくても、私が知って戻ってゼロを取得します。
リーリッフェル

@ypercude-あなたは絶対に正しいです。私の要点は、SUMの現在の動作では、空のセットと値を含むセットを区別するということです(一部がヌルであっても)。区別が必要でない場合は、COALESCEを使用するほうが、必要な場合などを使用するよりも簡単DECODE(count(c2),0,NULL,sum(c2))です。
リーリッフェル

-1

私が見ることができる主な違いは、データ型に関するものです。COUNTには、明確に定義された戻り値型:整数があります。他のすべては、調べている列/式のタイプに依存します。戻り値の型は、セットのすべてのメンバーと互換性がある必要があります(float、currency、decimal、bcd、timespanなど)。セットがないため、戻り値の型を示すことはできないため、NULLが最適なオプションです。

注:ほとんどの場合、表示している列の型から戻り値の型を暗示できますが、列だけでなくあらゆる種類のSUMを実行できます。戻り値の型を暗示することは、特定の状況下では不可能ではないにしても、非常に難しくなる可能性があります。


5
式で戻り値の型を意味できないのはなぜSUM(column)ですか?空のテーブルはありませんか?そして、すべての列に型が定義されていますか?空の結果セットではどうして違うのですか?
ypercubeᵀᴹ

5
あなたは「があるので、言うところそれは誤解NO SET」。セットがあります。関連する列または式の宣言された型のすべての可能な値のセット。見ているテーブルが空であっても、その宣言された型は存在します。空のテーブルにも見出しがあります。そして、宣言された型はまさに「暗黙の戻り型」です。
アーウィンスモート

二人とも実際に私のメモを読みましたか?はい、現在は列ベースのSUMで機能します。ただし、可変データ型列(SQL Serverにはまだありません)に遭遇するとすぐに、運が悪くなります。
TToni

2
その場合、どのように合計を定義しますか?結果はどうなり24 + 56.07 + '2012-10-05' + 'Red'ますか?つまり、SUM()追加の定義に問題がある場合の動作を心配することはありません。
ypercubeᵀᴹ

1
@TToni:「特に標準の拡張の可能性について考えるとき」は、OPが参照していたコンテキストではありません。OPは、標準の現行バージョンを非常に明確に参照していました。これには、「動的タイプ」などの概念は含まれていません。(ああ、私だけコメントしたが、downvoteしませんでしたそれを除けば、小さなスリップから私はあなたの答えでは何もdownvoteを保証するために間違って十分ではなかった、との問題を取っIMO。。。)
アーウィンSmout
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.