Mengapa ANSI SQL mendefinisikan SUM (tanpa baris) sebagai NULL?

28

Standar ANSI SQL mendefinisikan (bab 6.5, mengatur spesifikasi fungsi) perilaku berikut untuk fungsi agregat pada set hasil kosong:

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

Mengembalikan NULL untuk AVG, MIN, dan MAX sangat masuk akal, karena rata-rata, minimum, dan maksimum dari set kosong tidak ditentukan.

Yang terakhir, bagaimanapun, mengganggu saya: Secara matematis, SUM dari himpunan kosong adalah didefinisikan dengan baik: 0. Menggunakan 0, elemen netral penambahan, karena casing dasar membuat semuanya konsisten:

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

Mendefinisikan SUM({})sebagai nulldasarnya membuat "tidak ada baris" kasus khusus yang tidak cocok dengan orang lain:

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

Apakah ada beberapa keuntungan nyata dari pilihan yang dibuat (SUM sedang NULL) yang saya lewatkan?

Heinzi
sumber
5
Ya saya setuju: COUNT dan SUM tidak berperilaku konsisten.
AK

Jawaban:

20

Saya takut bahwa alasannya adalah hanya karena aturan ditetapkan secara adhoc (seperti "fitur" standar ISO SQL lainnya) pada saat agregasi SQL dan hubungannya dengan matematika kurang dipahami daripada sekarang. (*).

Itu hanya salah satu dari banyak inkonsistensi dalam bahasa SQL. Mereka membuat bahasa lebih sulit untuk diajarkan, lebih sulit untuk dipelajari, lebih sulit untuk dipahami, lebih sulit untuk digunakan, lebih sulit untuk apa pun yang Anda inginkan, tetapi hanya seperti itu keadaannya. Aturan tidak dapat diubah "dingin" dan "begitu saja", untuk alasan yang jelas dari kompatibilitas ke belakang (Jika komite ISO menerbitkan versi final dari standar, dan vendor kemudian mulai menerapkan standar itu, maka vendor tersebut tidak akan menghargai itu sangat banyak jika dalam versi berikutnya, aturan diubah sedemikian rupa sehingga implementasi (compliant) versi lama dari standar "secara otomatis gagal memenuhi" versi baru ...)

(*) Sekarang lebih baik dipahami bahwa agregasi atas set kosong berperilaku lebih konsisten jika mereka secara sistematis mengembalikan nilai identitas (= apa yang Anda sebut 'elemen netral') dari operator biner yang mendasarinya. Operator biner yang mendasari untuk COUNT dan SUM adalah tambahan, dan nilai identitasnya adalah nol. Untuk MIN dan MAX, nilai identitas itu adalah nilai tertinggi dan terendah dari jenis yang ada, masing-masing, jika jenis yang bersangkutan terbatas. Kasus-kasus seperti rata-rata, cara harmonis, median, dll sangat rumit dan eksotis dalam hal ini.

Erwin Smout
sumber
Saya pikir nol masuk akal atas set kosong dengan min dan maks. Anda mungkin mengatakan bahwa nilai identitas memang tidak diketahui, tetapi jumlah tanpa nilai adalah 0 karena alasan yang sama bahwa n * 0 selalu 0. Tetapi min dan maks berbeda. Saya tidak berpikir hasilnya didefinisikan dengan benar berjalan di tanpa catatan.
Chris Travers
Juga avg () di atas set nol masuk akal sebagai nol karena 0/0 tidak didefinisikan dengan benar dalam konteks ini.
Chris Travers
5
MIN dan MAX tidak jauh berbeda. Ambil masing-masing operator binary LOWESTOF (x, y) dan HIGHESTOF (x, y). Operator biner ini memang memiliki nilai identitas. Karena dalam kedua kasus (jika jenis yang terlibat adalah terbatas), memang ada beberapa nilai z sedemikian sehingga untuk semua x: LOWESTOF (z, x) = x dan untuk semua y: HIGHESTOF (y, z) = y. (Nilai identitas tidak sama untuk kedua kasus, tetapi memang ada untuk kedua kasus.) Saya setuju bahwa hasilnya terlihat sangat berlawanan dengan intuisi pada pandangan pertama, tetapi tidak dapat disangkal kenyataan matematika.
Erwin Smout
@ Erwin: Saya setuju pada semua poin Anda, kecuali bahwa identitas beberapa operasi, seperti HIGHEST()banyak tidak menjadi elemen dari tipe data, seperti untuk Reals di mana identitas akan menjadi -Infinity(dan +Infinityuntuk LOWEST())
ypercubeᵀᴹ
1
@SQL kiwi. Apakah Anda lupa tentang pemeriksaan tipe statis? Jika ekspresi seperti SUM () ditangani oleh pemeriksa tipe statis seolah-olah mereka selalu mengembalikan bilangan bulat, maka jelas tidak mungkin bagi permintaan SUM () untuk terkadang mengembalikan sesuatu yang bukan bilangan bulat (misalnya relasi kosong).
Erwin Smout
3

Dalam arti pragmatis, hasil yang ada NULLberguna. Pertimbangkan tabel dan pernyataan berikut:

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

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

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

Pernyataan pertama mengembalikan NULL dan yang kedua mengembalikan nol. Jika set kosong mengembalikan nol untuk SUMkita akan membutuhkan cara lain untuk membedakan jumlah sebenarnya dari nol dari set kosong, mungkin menggunakan hitungan. Jika kita memang menginginkan nol untuk set kosong maka sederhana COALESCEakan melengkapi persyaratan itu.

SELECT COALESCE(SUM(C2),0) FROM T1 WHERE C1 > 9;
Leigh Riffel
sumber
1
sebagai hasilnya., SUM (gabungan set1 dan set2) <> SUM (set1) + SUM (set2), karena angka apa saja + NULL = NULL. Apakah masuk akal untuk Anda?
AK
2
@Leigh: Menggunakan COALESCE()seperti ini tidak akan membedakan ( 0) jumlah set kosong dari ( NULL) jumlah (katakanlah tabel memiliki (10, NULL)baris.
ypercubeᵀᴹ
Selain itu, kami masih tidak dapat membedakan SUM (set kosong) dari SUM (set satu atau lebih NULL). Apakah kita perlu membedakan sama sekali?
AK
@AlexKuznetsov - Kita dapat membedakan jumlah set kosong dari jumlah set yang berisi satu atau lebih nol selama setidaknya satu baris berisi nilai. Anda benar bahwa jika set hanya berisi NULL maka kami tidak dapat membedakan set NULL dari set semua nilai NULL ini. Maksud saya bukan bahwa itu berguna dalam setiap kasus, hanya itu bisa bermanfaat. Jika saya SUMkolom dan kembali nol saya tahu tanpa harus memeriksa bahwa setidaknya ada satu baris NULL yang digunakan untuk menunjukkan kepada saya hasilnya.
Leigh Riffel
@Ypercude - Anda benar sekali. Maksud saya adalah bahwa perilaku SUM saat ini memang membedakan himpunan kosong dari himpunan yang berisi nilai (bahkan jika ada yang nol). Lebih mudah menggunakan COALESCE ketika perbedaan tidak diperlukan daripada menggunakan sesuatu seperti DECODE(count(c2),0,NULL,sum(c2))ketika itu.
Leigh Riffel
-1

Perbedaan utama yang bisa saya lihat adalah terkait dengan tipe data. COUNT memiliki jenis pengembalian yang didefinisikan dengan baik: Seluruh nomor. Yang lainnya tergantung pada jenis kolom / ekspresi yang mereka lihat. Jenis pengembalian mereka harus kompatibel dengan semua anggota set (bayangkan float, mata uang, desimal, bcd, rentang waktu, ...). Karena tidak ada set Anda tidak dapat menyiratkan tipe kembali, sehingga NULL adalah pilihan terbaik Anda.

Catatan: Dalam kebanyakan kasus, Anda dapat menyiratkan tipe kembali dari jenis kolom yang Anda lihat, tetapi Anda dapat melakukan SUM tidak hanya pada kolom tetapi pada semua jenis hal. Mengimplikasikan tipe pengembalian mungkin menjadi sangat sulit jika bukan tidak mungkin dalam keadaan tertentu, terutama ketika Anda memikirkan kemungkinan perluasan standar (tipe dinamis muncul di pikiran).

TToni
sumber
5
Mengapa kita tidak bisa menyiratkan tipe pengembalian dalam SUM(column)ekspresi? Bukankah kita memiliki tabel kosong - dan di sana semua kolom memiliki tipe yang didefinisikan? Mengapa harus berbeda untuk set hasil kosong?
ypercubeᵀᴹ
5
Anda salah ketika mengatakan "karena TIDAK ADA SET ". Ada satu set. Himpunan semua nilai yang mungkin dari tipe yang dinyatakan dari kolom atau ekspresi yang terlibat. Tipe yang dideklarasikan ada bahkan jika tabel yang Anda lihat kosong. Bahkan meja kosong masih memiliki tajuk. Dan tipe yang dideklarasikan itu persis "tipe pengembalian tersirat" Anda.
Erwin Smout
Apakah Anda berdua benar-benar membaca catatan saya? Ya, itu akan berfungsi untuk SUM berbasis kolom seperti yang sekarang. Tapi begitu Anda menemukan kolom datatype variabel (tidak dalam SQL Server - belum), Anda kurang beruntung.
TToni
2
Bagaimana Anda menentukan jumlah dalam kasus itu? Apa hasilnya 24 + 56.07 + '2012-10-05' + 'Red'? Maksud saya tidak ada masalah dalam mengkhawatirkan bagaimana SUM()akan berperilaku ketika kita memiliki masalah mendefinisikan penambahan.
ypercubeᵀᴹ
1
@TToni: "terutama ketika Anda berpikir tentang kemungkinan perluasan standar" bukanlah konteks yang dirujuk OP. OP sangat jelas mengacu pada versi standar saat ini, yang tidak termasuk pengertian "tipe dinamis" atau semacamnya. (Oh, dan saya hanya berkomentar, tetapi tidak downvote. Terlepas dari slip kecil yang saya ambil masalah, tidak ada dalam jawaban Anda yang cukup salah untuk menjamin downvote. IMO.)
Erwin Smout