ANSI SQL neden SUM (satır yok) NULL olarak tanımlar?


28

ANSI SQL standart tanımlar (bölüm 6.5, ayarlanan fonksiyon şartname) boş sonuç kümeleri üzerinde toplama işlevleri için aşağıdaki davranış:

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

AVG, MIN ve MAX için NULL döndürmek mükemmel bir anlam ifade eder, çünkü boş bir setin ortalama, minimum ve maksimum değerleri tanımsızdır.

Sonuncusu ise rahatsız ediyor beni: Matematiksel olarak boş bir setin SUM iyi tanımlanır: 0. 0 kullanarak , ilave durumun nötr elemanı , temel durum olarak her şeyi tutarlı kılar:

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

Tanımlanması SUM({})olarak nulltemelde "hayır" Satırları başkalarıyla sığmayan özel bir durum yapar:

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

Yaptığım seçimin (NUM OLMAKTAN) kaçırmış olduğumun belirgin bir avantajı var mı?



5
Evet katılıyorum: COUNT ve SUM tutarlı davranmıyor.
AK

Yanıtlar:


20

Ben korkuyorum nedeni kuralları (oldukça çok diğer "özellikler" gibi bir geçici moda konulmaması basitçe ISO şimdi olduklarından daha SQL toplamaları ve matematik ile bağlantı az anlaşılan ne zaman bir anda SQL standardı) (*).

SQL dilinde son derece tutarsızlıklardan sadece biri. Dili öğretmeyi zorlaştırır, öğrenmeyi zorlaştırır, anlaşılmayı zorlaştırır, kullanmayı zorlaştırır, istediğinizi zorlaştırır, ancak bu tam olarak böyledir. Kurallar "soğuk" ve "aynen böyle" değiştirilemez, geriye dönük uyumluluk nedeniyle barizdir (ISO komitesi standardın son bir versiyonunu yayınlarsa ve o zaman bu standardın uygulanması için belirlenen satıcılar, o zaman bu satıcılar takdir etmez. daha sonraki bir sürümde, kurallar, standardın eski sürümünün mevcut (uyumlu) uygulamalarının "yeni sürüme otomatik olarak uymaz" şeklinde değiştirilip değiştirilmediğini gösterir.

(*) Eldeki boş bir küme üzerindeki toplamaların , altta yatan ikili operatörün kimlik değerini (= 'nötr element' olarak adlandırdığınız şey) sistematik olarak döndürmeleri durumunda daha tutarlı davrandığı daha iyi anlaşılmıştır . Bu COUNT ve SUM için kullanılan ikili işlevin eklenmesi ve kimlik değerinin sıfır olması. MIN ve MAX için, söz konusu tipler sonlu ise, bu kimlik değeri eldeki tipin sırasıyla en yüksek ve en düşük değeridir. Ortalama, harmonik araçlar, medyanlar, vb. Gibi durumlar, bu açıdan oldukça karmaşık ve egzotiktir.


Boş değerin min ve max ile boş bir küme üzerinde anlamlı olduğunu düşünüyorum. Bir kimlik değerinin gerçekten bilinmediğini söyleyebilirsiniz, ancak hiçbir değerin toplamı, n * 0 her zaman 0 olduğu için 0'dır. Fakat min ve max farklıdır. Sonuçların kayıtlar arasında düzgün bir şekilde tanımlandığını sanmıyorum.
Chris Travers

Ayrıca boş bir küme üzerindeki avg (), boş olarak anlamlıdır, çünkü 0/0 bu bağlamda doğru bir şekilde tanımlanmamıştır.
Chris Travers

5
MIN ve MAX farklı değildir. Sırasıyla bir LOWESTOF (x, y) ve HIGHESTOF (x, y) ikili operatörünü kullanın. Bu ikili operatörlerin bir kimlik değeri vardır. Çünkü her iki durumda da (ilgili tür sonlu ise), x: LOWESTOF (z, x) = x ve forall y: HIGHESTOF (y, z) = y şeklinde bir z değeri vardır. (Kimlik değeri her iki durumda da aynı değildir, ancak her iki durumda da vardır.) Sonuçların ilk bakışta son derece sezgisel göründüğü, ancak matematiksel gerçeği inkar etmediği konusunda hemfikirim.
Erwin Smout,

@Erwin: Bazı işlemlerin kimliğinin ( HIGHEST()çoğu için veri -Infinity+InfinityLOWEST()
tipinin

1
@ SQL kivi. Statik tip kontrolünü unuttun mu? SUM () gibi ifadeler statik tür denetleyicisi tarafından her zaman bir tamsayı döndürdüğü gibi işlenirse, SUM () çağrısının bazen tamsayı olmayan bir şey (örneğin boş bir ilişki) döndürmesi imkansız olmalıdır .
Erwin Smout,

3

Pragmatik bir anlamda mevcut sonucu NULLfaydalıdır. Aşağıdaki tablo ve ifadeleri göz önünde bulundurun:

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

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

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

İlk ifade NULL, ikinci ifade sıfır döndürür. Boş bir küme sıfıra SUMdönerse, gerçek bir sıfır toplamını boş bir kümeden ayırmak için başka bir araca ihtiyacımız olur, belki de sayı kullanarak. Eğer gerçekten boş set için sıfır istiyorsak, o zaman basit bir COALESCEgereksinimi karşılayacaktır.

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

1
sonuç olarak., SUM (set1 ve set2 birleşimi) <> SUM (set1) + SUM (set2), çünkü herhangi bir sayı + NULL = NULL. Size mantıklı geliyor mu?
AK

2
@Leigh: Kullanılması COALESCE()böyle (ayırt etmeyecek 0(gelen boş kümesinin) toplamı NULL) toplamına (tablo bir vardı ki (10, NULL). Satır
ypercubeᵀᴹ

Ayrıca, SUM (boş kümeyi) SUM'dan (bir veya daha fazla NULL'lar kümesi) ayırt edemiyoruz. Ayırt etmek zorunda mıyız?
AK

@AlexKuznetsov - Boş bir kümenin toplamını, en az bir satır bir değer içerdiği sürece bir veya daha fazla boş değer içeren bir kümenin toplamından ayırabiliriz. Eğer set sadece NULL içeriyorsa, NULL setini tüm NULL değerler setinden ayırt edemeyeceğimiz doğrudur. Demek istediğim, her durumda yararlı olması değildi, sadece yararlı olması. Eğer SUMbir sütunu ve sıfırı geri alırsam, bana sonucu göstermek için en az bir tane NULL satırın kullanıldığını kontrol etmek zorunda kalmadan biliyorum.
Leigh Riffel

@ypercude - Kesinlikle haklısın. Demek istediğim, SUM'un şu anki davranışının boş bir seti değerleri içeren bir kümeden ayırdığıydı (bazıları boş olsa bile). Ayrılma gerektiğinde olduğu gibi bir şey kullanmak yerine gerekli olmadığında COALESCE kullanmak daha kolaydır DECODE(count(c2),0,NULL,sum(c2)).
Leigh Riffel

-1

Görebildiğim en büyük fark, veri türü ile ilgili. COUNT'ın iyi tanımlanmış bir geri ödeme türü var: Bir tam sayı. Diğerleri, baktıkları sütun / ifade türüne bağlıdır. Geri dönüş tipleri, setin tüm üyeleri ile uyumlu olmalıdır (bence float, para birimi, ondalık, bcd, zaman aralığı, ...). Küme olmadığından, geri dönüş türünü ima edemezsiniz, bu nedenle NULL en iyi seçeneğinizdir.

Not: Çoğu durumda, bakmakta olduğunuz sütun türünden bir dönüş türü ima edebilirsiniz ancak SUM'ları yalnızca sütunlarda değil her türlü şeyde de yapabilirsiniz. Belirli standartlarda, özellikle standardın olası genişlemelerini düşündüğünüzde (dinamik tipler akla geliyor) imkansız değilse, bir geri dönüş tipi uygulamak çok zor olabilir.


5
Neden bir SUM(column)ifadede bir dönüş türü ima edemiyoruz ? Boş tablolarımız yok mu - ve tüm sütunların tanımlanmış türleri var mı? Boş bir sonuç için neden farklı olsun ki?
ypercubeᵀᴹ

5
" NO SET olduğundan beri" dediğini yanlış anlıyorsun . Bir dizi var. İlgili sütunların veya ifadenin bildirilen türünün tüm olası değerleri kümesi. Belirtilen tür, aradığınız tablo boş olsa bile mevcuttur. Boş masaların bile hala bir başlığı var. Ve bu ilan edilen tip tam olarak sizin "zımni iade tipiniz" dir.
Erwin Smout,

İkiniz de notumu okudunuz mu? Evet, şu an itibariyle sütun tabanlı SUM'lar için işe yarayacaktı. Ancak değişken bir veri türü sütunu ile karşılaştığınızda (SQL Server'da değil - henüz), şansınız tükenir.
TToni

2
Bu durumda toplamı nasıl tanımlayacaksınız? Sonuç ne olacak 24 + 56.07 + '2012-10-05' + 'Red'? Demek istediğim, ilaveyi SUM()tanımlamakta bir sorunumuz olduğunda nasıl davranacağımızdan endişe etmenin bir anlamı yok .
ypercubeᵀᴹ

1
@TToni: “özellikle standardın olası genişlemelerini düşündüğünüzde” OP'nin bahsettiği bağlam değildir. OP, herhangi bir tür “dinamik tür” kavramını içermeyen standartların mevcut sürümüne çok açık bir şekilde bakıyordu. (Oh, ve ben sadece yorumda bulundum, ama oy kullanmadım. Sorunu çözdüğüm ufak kayma dışında, cevabınızdaki hiçbir şey bir oy kullanmamak için yeterince yanlış değildi. IMO.)
Erwin Smout
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.