Tại sao SQL ANSI định nghĩa SUM (không có hàng) là NULL?


28

Các định nghĩa ANSI SQL tiêu chuẩn (chương 6.5, bộ chức năng đặc điểm kỹ thuật) các hành vi sau đây cho các chức năng tổng hợp về bộ kết quả rỗng:

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

Trả lại NULL cho AVG, MIN và MAX có ý nghĩa hoàn hảo, vì mức trung bình, tối thiểu và tối đa của một tập hợp trống không được xác định.

Tuy nhiên, cái cuối cùng làm phiền tôi: Về mặt toán học, SUM của một tập hợp trống được xác định rõ : 0. Sử dụng 0, phần tử trung tính của phép cộng, như trường hợp cơ sở làm cho mọi thứ nhất quán:

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

Xác định SUM({})như nullvề cơ bản làm cho "không có hàng" một trường hợp đặc biệt không phù hợp với những người khác:

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

Có một số lợi thế rõ ràng của sự lựa chọn đã được thực hiện (SUM là NULL) mà tôi đã bỏ lỡ?


Lưu ý: Đây là phiên bản tổng quát của câu hỏi tôi đã hỏi trên StackOverflow cụ thể về SQL Server .
Heinzi

5
Có, tôi đồng ý: COUNT và SUM không hành xử nhất quán.
AK

Câu trả lời:


20

Tôi e rằng lý do đơn giản là các quy tắc được đặt theo kiểu adhoc (giống như nhiều "tính năng" khác của tiêu chuẩn SQL SQL) tại thời điểm các tập hợp SQL và kết nối của chúng với toán học ít được hiểu hơn so với bây giờ (*).

Nó chỉ là một trong rất nhiều sự không nhất quán trong ngôn ngữ SQL. Chúng làm cho ngôn ngữ khó dạy hơn, khó học hơn, khó hiểu hơn, khó sử dụng hơn, khó hơn với bất cứ điều gì bạn muốn, nhưng đó chỉ là cách mọi thứ diễn ra. Các quy tắc không thể thay đổi "lạnh" và "giống như vậy", vì lý do rõ ràng về khả năng tương thích ngược (Nếu ủy ban ISO công bố phiên bản cuối cùng của tiêu chuẩn và sau đó các nhà cung cấp bắt đầu thực hiện tiêu chuẩn đó, thì các nhà cung cấp đó sẽ không đánh giá cao rất nhiều nếu trong phiên bản tiếp theo, các quy tắc được thay đổi sao cho việc triển khai (tuân thủ) hiện có của phiên bản cũ của tiêu chuẩn "tự động không tuân thủ" phiên bản mới ...)

(*) Nó bây giờ được hiểu rõ hơn rằng quy tụ trên một bộ cư xử có sản phẩm nào phù hợp hơn nếu họ có hệ thống trả lại giá trị bản sắc (= những gì bạn gọi là 'yếu tố trung lập') của toán tử nhị phân tiềm ẩn trong tầm tay. Toán tử nhị phân cơ bản cho COUNT và SUM là phép cộng và giá trị nhận dạng của nó bằng không. Đối với MIN và MAX, giá trị nhận dạng đó là giá trị cao nhất và thấp nhất của loại trong tay, tương ứng, nếu các loại liên quan là hữu hạn. Các trường hợp như trung bình, phương tiện hài hòa, trung bình, vv là cực kỳ phức tạp và kỳ lạ về mặt này, mặc dù.


Tôi nghĩ null có ý nghĩa đối với một tập hợp trống với min và max. Bạn có thể nói một giá trị danh tính thực sự không xác định, nhưng tổng không có giá trị nào là 0 vì cùng lý do n * 0 luôn bằng 0. Nhưng min và max khác nhau. Tôi không nghĩ rằng kết quả được xác định chính xác chạy qua không có hồ sơ.
Chris Travers

Ngoài ra avg () trên tập hợp null có nghĩa là null vì 0/0 không được xác định đúng trong ngữ cảnh này.
Chris Travers

5
MIN và MAX không quá khác nhau. Lấy một toán tử nhị phân cơ bản là LowESTOF (x, y) và HIGHESTOF (x, y) tương ứng. Các toán tử nhị phân này có một giá trị nhận dạng. Bởi vì trong cả hai trường hợp (nếu loại liên quan là hữu hạn), thực sự tồn tại một số giá trị z sao cho for x: LOWESTOF (z, x) = x và forall y: HIGHESTOF (y, z) = y. (Giá trị nhận dạng không giống nhau cho cả hai trường hợp, nhưng nó tồn tại cho cả hai trường hợp.) Tôi đồng ý rằng kết quả trông cực kỳ phản trực giác, nhưng không thể phủ nhận thực tế toán học.
Erwin Smout

@Erwin: Tôi đồng ý với tất cả các điểm của bạn, ngoại trừ rằng danh tính của một số thao tác, giống như HIGHEST()nhiều yếu tố không phải là một yếu tố của kiểu dữ liệu, giống như đối với Reals trong đó danh tính sẽ là -Infinity(và +Infinitycho LOWEST())
ypercubeᵀᴹ

1
@ Kiwi kiwi. Bạn đang quên về kiểm tra loại tĩnh? Nếu các biểu thức như SUM () được xử lý bởi trình kiểm tra kiểu tĩnh như thể chúng luôn trả về một số nguyên, thì rõ ràng việc gọi SUM () đôi khi không thể trả về một số nguyên không phải là số nguyên (ví dụ: quan hệ trống).
Erwin Smout

3

Trong một ý nghĩa thực tế, kết quả hiện tại NULLlà hữu ích. Hãy xem xét bảng và các tuyên bố sau:

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

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

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

Câu lệnh đầu tiên trả về NULL và câu lệnh thứ hai trả về 0. Nếu một tập hợp trống trả về 0 cho SUMchúng ta sẽ cần một phương tiện khác để phân biệt một tổng bằng 0 thực sự với một tập hợp trống, có lẽ sử dụng số đếm. Nếu chúng ta thực sự muốn không cho tập hợp trống thì một đơn giản COALESCEsẽ cung cấp yêu cầu đó.

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

1
là kết quả., SUM (liên kết của set1 và set2) <> SUM (set1) + SUM (set2), bởi vì bất kỳ số nào + NULL = NULL. Liệu nó có ý nghĩa đối với bạn?
AK

2
@Leigh: Sử dụng COALESCE()như thế này sẽ không phân biệt tổng ( 0) của một tập hợp trống với tổng ( NULL) (giả sử bảng có một (10, NULL)hàng.
ypercubeᵀᴹ

Ngoài ra, chúng tôi vẫn không thể phân biệt SUM (bộ trống) với SUM (bộ một hoặc nhiều NULL). Chúng ta có cần phân biệt gì không?
AK

@AlexKuznetsov - Chúng ta có thể phân biệt một tổng của một tập hợp trống với một tập hợp có chứa một hoặc nhiều null miễn là ít nhất một hàng chứa một giá trị. Bạn đúng rằng nếu tập hợp chỉ chứa NULL thì chúng ta không thể phân biệt tập NULL với tập hợp tất cả các giá trị NULL này. Quan điểm của tôi không phải là nó hữu ích trong mọi trường hợp, chỉ đơn thuần là nó có thể hữu ích. Nếu tôi SUMmột cột và lấy lại số 0, tôi biết mà không cần phải kiểm tra rằng có ít nhất một hàng không phải là NULL được sử dụng để hiển thị cho tôi kết quả.
Leigh Riffel

@ypercude - Bạn hoàn toàn chính xác. Quan điểm của tôi là hành vi hiện tại của SUM phân biệt một tập hợp trống với một tập hợp có chứa các giá trị (ngay cả khi một số là null). Sử dụng COALESCE đơn giản hơn khi không cần phân biệt hơn là sử dụng một cái gì đó giống như DECODE(count(c2),0,NULL,sum(c2))khi nó được.
Leigh Riffel

-1

Sự khác biệt chính mà tôi có thể thấy là liên quan đến kiểu dữ liệu. COUNT có một returntype được xác định rõ: Một số nguyên. Tất cả những cái khác phụ thuộc vào loại cột / biểu thức mà họ đang xem. Kiểu trả về của chúng phải tương thích với tất cả các thành viên của tập hợp (nghĩ float, tiền tệ, thập phân, bcd, timespan, ...). Vì không có tập hợp nào, bạn không thể ngụ ý loại trả về, do đó NULL là tùy chọn tốt nhất của bạn.

Lưu ý: Trong hầu hết các trường hợp, bạn có thể ngụ ý loại trả về từ loại cột bạn đang xem, nhưng bạn có thể thực hiện SUM không chỉ trên các cột mà trên tất cả các loại. Việc ngụ ý một kiểu trả về có thể trở nên rất khó khăn nếu không phải là không thể trong một số trường hợp nhất định, đặc biệt là khi bạn nghĩ về việc mở rộng có thể của tiêu chuẩn (các kiểu động xuất hiện trong tâm trí).


5
Tại sao chúng ta không thể ngụ ý một kiểu trả về trong một SUM(column)biểu thức? Chúng ta không có các bảng trống - và tất cả các cột có các loại được xác định? Tại sao nó phải là bất kỳ khác nhau cho một tập kết quả trống?
ypercubeᵀᴹ

5
Bạn hiểu sai khi bạn nói "vì KHÔNG CÓ THIẾT LẬP ". Có một bộ. Tập hợp tất cả các giá trị có thể có của kiểu khai báo của các cột hoặc biểu thức liên quan. Loại khai báo đó tồn tại ngay cả khi bảng bạn đang xem trống. Ngay cả các bảng trống vẫn có một tiêu đề. Và kiểu khai báo đó chính xác là "kiểu trả về ngụ ý" của bạn.
Erwin Smout

Cả hai bạn có thực sự đọc ghi chú của tôi không? Có, nó sẽ hoạt động cho SUM dựa trên cột ngay bây giờ. Nhưng ngay khi bạn gặp một cột kiểu dữ liệu thay đổi (không phải trong SQL Server - chưa), bạn đã hết may mắn.
TToni

2
Làm thế nào bạn sẽ xác định tổng trong trường hợp đó? Kết quả của 24 + 56.07 + '2012-10-05' + 'Red'sẽ là gì? Tôi có nghĩa là không có pint trong lo lắng SUM()sẽ hành xử như thế nào khi chúng ta có một vấn đề xác định bổ sung.
ypercubeᵀᴹ

1
@TToni: "đặc biệt là khi bạn nghĩ về việc mở rộng có thể của tiêu chuẩn" không phải là bối cảnh mà OP đã đề cập. OP đã đề cập rất rõ ràng đến phiên bản hiện tại của tiêu chuẩn, không bao gồm bất kỳ khái niệm nào về "các loại động" hoặc một số loại như vậy. (. Oh, và tôi chỉ nhận xét, nhưng không downvote Ngoài ra trượt nhỏ tôi đã đặt vấn đề với, không có gì trong câu trả lời của bạn là đủ để đảm bảo sai một downvote IMO..)
Erwin Smout
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.