Không bằng <>! = Toán tử trên NULL


271

Ai đó có thể vui lòng giải thích các hành vi sau đây trong SQL?

SELECT * FROM MyTable WHERE MyColumn != NULL (0 Results)
SELECT * FROM MyTable WHERE MyColumn <> NULL (0 Results)
SELECT * FROM MyTable WHERE MyColumn IS NOT NULL (568 Results)

Câu trả lời:


308

<>là tiêu chuẩn SQL-92; !=là tương đương của nó. Cả hai đánh giá cho các giá trị, mà NULLkhông -NULL là một trình giữ chỗ để nói rằng không có giá trị.

Đó là lý do tại sao bạn chỉ có thể sử dụng IS NULL/IS NOT NULL làm vị ngữ cho các tình huống như vậy.

Hành vi này không dành riêng cho SQL Server. Tất cả các phương ngữ SQL tuân thủ tiêu chuẩn hoạt động theo cùng một cách.

Lưu ý : Để so sánh nếu giá trị của bạn không phải là null , bạn sử dụng IS NOT NULL, trong khi để so sánh với giá trị không null , bạn sử dụng <> 'YOUR_VALUE'. Tôi không thể nói nếu giá trị của tôi bằng hoặc không bằng NULL, nhưng tôi có thể nói nếu giá trị của tôi là NULL hay KHÔNG NULL. Tôi có thể so sánh nếu giá trị của tôi là một cái gì đó khác với NULL.


4
Trên thực tế, tôi tin rằng đó là <>trong 92 thông số kỹ thuật nhưng hầu hết các nhà cung cấp đều hỗ trợ !=và / hoặc nó được bao gồm trong một thông số sau như 99 hoặc 03.
Thomas

2
@Thomas: Oracle đã không hỗ trợ !=cho đến ~ 9i như tôi hiểu, điều này mang lại rất nhiều cú pháp ANSI-92. Niềm tin của tôi là MySQL cũng tương tự, bắt đầu hỗ trợ trong 4.x.
Ngựa vằn OMG

Điều đó dường như cho thấy rằng !=có thể đã được đưa vào một thông số kỹ thuật sau này như là một thay thế <>. Đừng nhúng tay vào thông số kỹ thuật mới vì vậy tôi không thể nói chắc chắn.
Thomas

2
Là kết quả của WHERE MyColumn != NULLhoặc WHERE MyColumn = NULLxác định? Hay nói cách khác, nó có được đảm bảo luôn trả về 0 hàng hay không, cho dù có vô hiệu MyColumntrong cơ sở dữ liệu hay không?
Slauma

11
Cũng cần lưu ý rằng vì !=chỉ đánh giá các giá trị, làm những việc như thế WHERE MyColumn != 'somevalue'sẽ không trả về các bản ghi NULL.
jsumrall

88

NULL không có giá trị và do đó không thể so sánh bằng cách sử dụng các toán tử giá trị vô hướng.

Nói cách khác, không có giá trị nào có thể bằng (hoặc không bằng) NULL vì NULL không có giá trị.

Do đó, SQL có các vị từ IS NULL đặc biệt và IS KHÔNG NULL để xử lý NULL.


3
+1. Và, trái với tuyên bố của OP, đây không phải là "Microsoft SQL". Logic nhị phân được định nghĩa trong Tiêu chuẩn SQL và MS trong điểm này tuân thủ tiêu chuẩn.
TomTom

6
Tôi đã không gợi ý rằng đây là hành vi duy nhất của Microsoft. Tôi chỉ đơn giản nói rằng tôi đã quan sát nó trên Microsoft SQL Server.
Maxim Gershkovich

13
Không quan tâm, có bất kỳ tình huống mà hành vi (dự kiến) này là hữu ích? Dường như với tôi việc 'a' != nullKHÔNG trả lại giá trị ( true/ 1) là phản trực quan và thỉnh thoảng lại bắt tôi ra ngoài! Tôi đã từng nghĩ "một số giá trị so với không có giá trị" sẽ luôn luôn là "không bằng", nhưng có lẽ đó chỉ là tôi?!?
DarthPablo

1
Tôi nghĩ thật thú vị khi mọi người mô tả NULL là " không có giá trị ". Tương tự, sau đó, để nói số 1 'có giá trị' khi nó thực sự là một giá trị. Nhưng NULL đại diện cho giá trị phi ..
systemaddict

Là một cách giải quyết thủ công, bạn thường có thể SELECT * FROM MyTable WHERE coalesce(MyColumn, 'x') <> 'x'gán hằng số nếu đó là giá trị NULL, cung cấp cho bạn một kiểu dữ liệu phù hợp cho giá trị sentinel x (trong trường hợp này là một chuỗi / char). Đây là cú pháp TSQL nhưng Oracle và các công cụ khác có các tính năng tương tự.
systemaddict

26

Lưu ý rằng hành vi này là hành vi mặc định (ANSI).

Nếu bạn:

 SET ANSI_NULLS OFF

http://msdn.microsoft.com/en-us/l Library / ms188048.aspx

Bạn sẽ nhận được kết quả khác nhau.

SET ANSI_NULLS OFF rõ ràng sẽ biến mất trong tương lai ...


8
+1 ... không đủ sớm. Bây giờ khi nào tôi có thể nhận được các NULL "trùng lặp" trong một chỉ mục? :(

Bạn có thể nhận được các NULL trùng lặp trong chỉ mục SQL Server bằng cách thêm mệnh đề WHERE trong chỉ mục được lọc (ví dụ create unique index UK_MyTable on MyTable (Column) where Column is not null): msdn.microsoft.com/en-us/l Library / cc280372.aspx
Anthony Mills

3
Lưu ý từ các tài liệu: Khi SET ANSI_NULLSTẮT, các toán tử so sánh Bằng (=) và Không bằng (<>) không tuân theo tiêu chuẩn ISO. Câu lệnh CHỌN sử dụng WHERE column_name = NULLtrả về các hàng có giá trị null trong cột_name. Một câu lệnh CHỌN sử dụng WHERE column_name <> NULLtrả về các hàng có giá trị không phải trong cột. Ngoài ra, một câu lệnh CHỌN sử dụng WHERE column_name <> XYZ_valuetrả về tất cả các hàng không phải là XYZ_value và đó không phải là NULL. IMHO, tuyên bố cuối cùng này có vẻ hơi kỳ lạ trong việc loại trừ null khỏi kết quả!
DarthPablo

4
Lưu ý quan trọng từ tài liệu msDN : Trong phiên bản tương lai của SQL Server [mới hơn 2014], ANSI_NULLS sẽ luôn BẬT và bất kỳ ứng dụng nào đặt tùy chọn TẮT rõ ràng sẽ tạo ra lỗi. Tránh sử dụng tính năng này trong công việc phát triển mới và lên kế hoạch sửa đổi các ứng dụng hiện đang sử dụng tính năng này.
Otiel

7

Trong SQL, mọi thứ bạn đánh giá / tính toán với NULLkết quả thành UNKNOWN

Đây là lý do tại sao SELECT * FROM MyTable WHERE MyColumn != NULLhoặc SELECT * FROM MyTable WHERE MyColumn <> NULLcung cấp cho bạn 0 kết quả.

Để cung cấp kiểm tra các NULLgiá trị, hàm isNull được cung cấp.

Hơn nữa, bạn có thể sử dụng IStoán tử như bạn đã sử dụng trong truy vấn thứ ba.

Hi vọng điêu nay co ich.


"Trong SQL, mọi thứ bạn đánh giá / tính toán với kết quả NULL đều thành 'NULL'" - không chính xác. Kết quả mà bạn muốn nói là UNKNOWN.
onedaywhen

@MahendraLiya, hàm isNull không được cung cấp để kiểm tra NULLS, nhưng nó " Thay thế NULL bằng giá trị thay thế đã chỉ định. " Bạn nên sử dụng IS NULL hoặc IS NOT NULL thay vì ISNULL, đây là một điều khác biệt.
Kỹ sư đảo ngược

7

Thử nghiệm duy nhất cho NULL là IS NULL hoặc IS NOT NULL. Kiểm tra sự bằng nhau là vô nghĩa bởi vì theo định nghĩa, người ta không biết giá trị là gì.

Đây là một bài viết trên wikipedia để đọc:

https://en.wikipedia.org/wiki/Null_(Query)


6

Chúng tôi sử dụng

SELECT * FROM MyTable WHERE ISNULL(MyColumn, ' ') = ' ';

để trả về tất cả các hàng trong đó MyColumn là NULL hoặc tất cả các hàng trong đó MyColumn là một chuỗi trống. Đối với nhiều "người dùng cuối", vấn đề NULL so với chuỗi rỗng là một sự khác biệt mà không có nhu cầu và điểm nhầm lẫn.


5

Tôi chỉ không thấy lý do chức năng và liền mạch cho null không thể so sánh với các giá trị khác hoặc null khác, vì chúng ta có thể so sánh rõ ràng và nói rằng chúng giống nhau hay không trong bối cảnh của chúng ta. Thật buồn cười. Chỉ vì một số kết luận hợp lý và nhất quán, chúng tôi cần phải bận tâm liên tục với nó. Nó không hoạt động, làm cho nó có nhiều chức năng hơn và để nó cho các nhà triết học và các nhà khoa học kết luận liệu nó có phù hợp hay không và nó có "logic phổ quát" hay không. :) Ai đó có thể nói rằng đó là do chỉ mục hoặc thứ gì khác, tôi nghi ngờ rằng những thứ đó không thể được tạo ra để hỗ trợ null giống như các giá trị. Nó giống như so sánh hai ly rỗng, một là ly nho và một là ly bia, chúng tôi không so sánh các loại vật thể nhưng giá trị chúng chứa, giống như bạn có thể so sánh int và varchar, với null nó ' Thậm chí còn dễ dàng hơn, không có gì và có hai điểm chung, chúng giống nhau, rõ ràng có thể so sánh với tôi và bởi những người khác viết sql, bởi vì chúng tôi liên tục phá vỡ logic đó bằng cách so sánh chúng theo những cách kỳ lạ vì một số tiêu chuẩn ANSI. Tại sao không sử dụng năng lượng máy tính để làm điều đó cho chúng tôi và tôi nghi ngờ nó sẽ làm mọi thứ chậm lại nếu mọi thứ liên quan được xây dựng với ý nghĩ đó. "Không phải là không, không có gì", nó không phải là táo, hãy đến ... Thực chất là bạn của bạn và cũng có logic ở đây. Cuối cùng, điều duy nhất quan trọng là chức năng và việc sử dụng null theo cách đó mang lại ít nhiều chức năng và dễ sử dụng. Nó có hữu ích hơn không? bởi vì chúng tôi liên tục phá vỡ logic đó bằng cách so sánh chúng theo những cách kỳ lạ vì một số tiêu chuẩn ANSI. Tại sao không sử dụng năng lượng máy tính để làm điều đó cho chúng tôi và tôi nghi ngờ nó sẽ làm mọi thứ chậm lại nếu mọi thứ liên quan được xây dựng với ý nghĩ đó. "Không phải là không, không có gì", nó không phải là táo, hãy đến ... Thực chất là bạn của bạn và cũng có logic ở đây. Cuối cùng, điều duy nhất quan trọng là chức năng và việc sử dụng null theo cách đó mang lại ít nhiều chức năng và dễ sử dụng. Nó có hữu ích hơn không? bởi vì chúng tôi liên tục phá vỡ logic đó bằng cách so sánh chúng theo những cách kỳ lạ vì một số tiêu chuẩn ANSI. Tại sao không sử dụng năng lượng máy tính để làm điều đó cho chúng tôi và tôi nghi ngờ nó sẽ làm mọi thứ chậm lại nếu mọi thứ liên quan được xây dựng với ý nghĩ đó. "Không phải là không, không có gì", nó không phải là táo, hãy đến ... Thực chất là bạn của bạn và cũng có logic ở đây. Cuối cùng, điều duy nhất quan trọng là chức năng và việc sử dụng null theo cách đó mang lại ít nhiều chức năng và dễ sử dụng. Nó có hữu ích hơn không? Không phải táo đâu là apfel, thôi nào ... Thực chất là bạn của bạn và cũng có logic ở đây. Cuối cùng, điều duy nhất quan trọng là chức năng và việc sử dụng null theo cách đó mang lại ít nhiều chức năng và dễ sử dụng. Nó có hữu ích hơn không? Không phải táo đâu là apfel, thôi nào ... Thực chất là bạn của bạn và cũng có logic ở đây. Cuối cùng, điều duy nhất quan trọng là chức năng và việc sử dụng null theo cách đó mang lại ít nhiều chức năng và dễ sử dụng. Nó có hữu ích hơn không?

Xem xét mã này:

SELECT CASE WHEN NOT (1 = null or (1 is null and null is null)) THEN 1 ELSE 0 end

Có bao nhiêu bạn biết mã này sẽ trả về cái gì? Có hoặc không có KHÔNG trả về 0. Đối với tôi đó không phải là chức năng và nó gây nhầm lẫn. Trong c #, tất cả đều như vậy, các hoạt động so sánh trả về giá trị, về mặt logic, điều này cũng tạo ra giá trị, bởi vì nếu nó không có gì để so sánh (ngoại trừ. Không có gì :)). Họ chỉ "nói": bất cứ điều gì so với null "trả về" 0 và điều đó tạo ra nhiều cách giải quyết và đau đầu.

Đây là mã đã đưa tôi đến đây:

where a != b OR (a is null and b IS not null) OR (a IS not null and b IS null)

Tôi chỉ cần so sánh nếu hai trường (trong đó) có các giá trị khác nhau, tôi có thể sử dụng hàm, nhưng ...


4

NULL Không thể so sánh với bất kỳ giá trị nào bằng cách sử dụng các toán tử so sánh. NULL = NULL là sai. Null không phải là một giá trị. Toán tử IS được thiết kế đặc biệt để xử lý các so sánh NULL.


5
Tôi luôn thích những người bối rối khi đôi khi tôi sử dụng null = nullnơi người ta có thể sử dụng 1=0trong một số truy vấn đặc biệt. Và nếu họ phàn nàn, tôi đổi nó thành null != null:)
SWeko

8
"NULL = NULL là sai" Không phải vậy. NULL = NULL ước tính thành không xác định và không sai.
nvogel

@dportas là như vậy nhưng tôi có nghĩa là trong một điều kiện, nó sẽ không được đánh giá là đúng.
Vincent Ramdhanie

@VincentRamdhanie cũng không sai; thực tế, trong postgres, nó sẽ được đánh giá là NULL
Pere

2

Câu hỏi cũ, nhưng sau đây có thể cung cấp một số chi tiết hơn.

nullđại diện không có giá trị hoặc một giá trị không xác định. Nó không xác định lý do tại sao không có giá trị, có thể dẫn đến một sự mơ hồ.

Giả sử bạn chạy một truy vấn như thế này:

SELECT *
FROM orders
WHERE delivered=ordered;

nghĩa là, bạn đang tìm kiếm hàng nơi ordereddelivered ngày ngày giống nhau.

Điều gì sẽ xảy ra khi một hoặc cả hai cột là null?

Bởi vì ít nhất một trong những ngày không xác định, bạn không thể nói rằng 2 ngày giống nhau. Đây cũng là trường hợp khi cả hai ngày không xác định: làm thế nào chúng có thể giống nhau nếu chúng ta thậm chí không biết chúng là gì?

Vì lý do này, bất kỳ biểu thức nào được coi nulllà giá trị đều phải thất bại. Trong trường hợp này, nó sẽ không khớp. Đây cũng là trường hợp nếu bạn thử như sau:

SELECT *
FROM orders
WHERE delivered<>ordered;

Một lần nữa, làm thế nào chúng ta có thể nói rằng hai giá trị không giống nhau nếu chúng ta không biết chúng là gì.

SQL có một bài kiểm tra cụ thể cho các giá trị bị thiếu:

IS NULL

Cụ thể nó không so sánh các giá trị, mà là tìm kiếm các giá trị còn thiếu .

Cuối cùng, liên quan đến !=nhà điều hành, theo như tôi biết, nó không thực sự nằm trong bất kỳ tiêu chuẩn nào, nhưng nó được hỗ trợ rất rộng rãi. Nó đã được thêm vào để làm cho các lập trình viên từ một số ngôn ngữ cảm thấy thoải mái hơn ở nhà. Thành thật mà nói, nếu một lập trình viên gặp khó khăn trong việc ghi nhớ ngôn ngữ họ đang sử dụng, họ sẽ có một khởi đầu tồi tệ.


Đây là cùng một logic "vô nghĩa" mà @Hove đang mô tả trong câu trả lời của anh ấy. Sự thật là trong bối cảnh này, không cần thêm vật liệu phụ đó; Có thể dễ dàng giả định rằng khi chúng ta so sánh một cái gì đó với một thứ NULLchúng ta có nghĩa là chúng ta đang so sánh một giá trị với 'có một NULLgiá trị', chứ không phải giá trị với "giá trị không xác định mà lớp lót NULLlà" nhưng chúng ta không biết ", Điều rõ ràng là chúng ta sẽ không thể biết được. Điều đó sẽ thực sự làm dịu mọi thứ lên.
Pere

@Pere Tôi sẽ không nói rằng đó là nghiêm túc, và tôi không chắc rằng viết lách IS NULLkhó hơn nhiều so với viết = NULL. Tôi nghĩ rằng nó sẽ phù hợp hơn nếu WHERE columnA = columnBcó cách giải thích tương tự WHERE columnA = NULL, thay vì coi trường hợp sau là trường hợp đặc biệt. Hãy nhớ rằng NULLkhông có giá trị. Trong các ngôn ngữ lập trình, nơi nó hợp pháp để kiểm tra variable == nullnó là bởi vì nullcó một ý nghĩa khác nhau; nó không đại diện cho một cái gì đó chưa biết, nhưng cố tình đặt lại một giá trị. Không như vậy với SQL.
Manngo

Đó là lý do tại sao tôi đặt nó giữa các trích dẫn, @Mangoo;) (và cả "logic"). Đừng giận tôi; Tôi đã nói về "lý luận" ANSI, không phải về lời giải thích của bạn. Tôi đồng ý rằng không có chi phí nào giữa IS NULLAND =NULLtrong ví dụ mới nhất của bạn. Nhưng hãy xem cái cuối cùng của Hover. Tôi mệt mỏi vì phải trải qua nó nhiều lần, phải làm vô số không cần thiết? kiểm tra thêm ...
Pere

1

Tôi muốn đề xuất mã này tôi đã thực hiện để tìm xem có thay đổi giá trị nào không, ilà giá trị mới và dlà cũ (mặc dù thứ tự không quan trọng). Đối với vấn đề đó, một sự thay đổi từ giá trị thành null hoặc ngược lại là một sự thay đổi nhưng từ null thành null thì không (tất nhiên, từ giá trị này sang giá trị khác là một sự thay đổi nhưng từ giá trị sang cùng một giá trị thì không).

CREATE FUNCTION [dbo].[ufn_equal_with_nulls]
(
    @i sql_variant,
    @d sql_variant
)
RETURNS bit
AS
BEGIN
    DECLARE @in bit = 0, @dn bit = 0
    if @i is null set @in = 1
    if @d is null set @dn = 1

    if @in <> @dn
        return 0

    if @in = 1 and @dn = 1
        return 1

    if @in = 0 and @dn = 0 and @i = @d
        return 1

    return 0

END

Để sử dụng chức năng này, bạn có thể

declare @tmp table (a int, b int)
insert into @tmp values
(1,1),
(1,2),
(1,null),
(null,1),
(null,null)

---- in select ----
select *, [dbo].[ufn_equal_with_nulls](a,b) as [=] from @tmp

---- where equal ----
select *,'equal' as [Predicate] from @tmp where  [dbo].[ufn_equal_with_nulls](a,b) = 1

---- where not equal ----
select *,'not equal' as [Predicate] from @tmp where  [dbo].[ufn_equal_with_nulls](a,b) = 0

Kết quả là:

---- in select ----
a   b   =
1   1   1
1   2   0
1   NULL    0
NULL    1   0
NULL    NULL    1

---- where equal ----
1   1   equal
NULL    NULL    equal

---- where not equal ----
1   2   not equal
1   NULL    not equal
NULL    1   not equal

Việc sử dụng sql_variant làm cho nó tương thích với nhiều loại


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.