Tidak sama dengan <>! = Operator pada NULL

271

Bisakah seseorang tolong jelaskan perilaku berikut dalam 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)
Maxim Gershkovich
sumber

Jawaban:

309

<>adalah Standard SQL-92; !=adalah padanannya. Keduanya mengevaluasi nilai-nilai, yang NULLbukan - NULLadalah pengganti yang mengatakan bahwa tidak ada nilai.

Itulah sebabnya Anda hanya dapat menggunakan IS NULL/ IS NOT NULLsebagai predikat untuk situasi seperti itu.

Perilaku ini tidak spesifik untuk SQL Server. Semua dialek SQL yang memenuhi standar bekerja dengan cara yang sama.

Catatan : Untuk membandingkan jika nilai Anda bukan nol , Anda menggunakan IS NOT NULL, sedangkan untuk membandingkan dengan bukan nilai nol , Anda gunakan <> 'YOUR_VALUE'. Saya tidak bisa mengatakan apakah nilai saya sama atau tidak sama dengan NULL, tetapi saya dapat mengatakan apakah nilai saya NULL atau NOT NULL. Saya dapat membandingkan jika nilai saya adalah sesuatu selain NULL.

OMG Ponies
sumber
4
Sebenarnya, saya percaya <>bahwa itu ada dalam spesifikasi 92 tetapi kebanyakan vendor mendukung !=dan / atau itu termasuk dalam spesifikasi berikutnya seperti 99 atau 03.
Thomas
2
@ Thomas: Oracle tidak mendukung !=sampai ~ 9 seperti yang saya mengerti, yang membawa banyak sintaks ANSI-92. Keyakinan saya adalah MySQL serupa, memulai dukungan di 4.x.
OMG Ponies
Itu tampaknya menunjukkan bahwa !=mungkin telah dimasukkan dalam spesifikasi nanti sebagai alternatif <>. Tidak punya spesifikasi baru jadi saya tidak bisa mengatakannya dengan pasti.
Thomas
2
Apakah hasilnya WHERE MyColumn != NULLatau WHERE MyColumn = NULLdeterministik? Atau dengan kata lain, apakah dijamin untuk selalu mengembalikan 0 baris, tidak peduli apakah MyColumnitu dapat dibatalkan dalam database atau tidak?
Slauma
11
Juga harus dicatat bahwa karena !=hanya mengevaluasi nilai-nilai, melakukan sesuatu seperti WHERE MyColumn != 'somevalue'tidak akan mengembalikan catatan NULL.
jsumrall
88

NULL tidak memiliki nilai, sehingga tidak dapat dibandingkan dengan menggunakan operator nilai skalar.

Dengan kata lain, tidak ada nilai yang dapat sama dengan (atau tidak sama dengan) NULL karena NULL tidak memiliki nilai.

Oleh karena itu, SQL memiliki predikat IS NULL dan IS NOT NULL untuk berurusan dengan NULL.

Barry Brown
sumber
3
+1. Dan, bertentangan dengan pernyataan OP ini bukan "Microsoft SQL". Logika triner didefinisikan dalam SQL Standard dan MS pada poin ini mengikuti standar.
TomTom
6
Saya tidak menyarankan bahwa ini hanya perilaku Microsoft. Saya hanya menyatakan bahwa saya mengamatinya di Microsoft SQL Server.
Maxim Gershkovich
13
Karena ketertarikan, apakah ada situasi di mana perilaku (yang diharapkan) ini berguna? Sepertinya saya 'a' != nullTIDAK mengembalikan nilai ( true/ 1) berlawanan dengan intuisi dan menarik saya keluar dari waktu ke waktu! Saya akan berpikir "nilai dibandingkan dengan tidak ada nilai" akan selalu "tidak sama", tapi mungkin itu hanya saya?!?
DarthPablo
1
Saya pikir ini menarik bahwa orang menggambarkan NULL sebagai ' tidak memiliki nilai '. Sama halnya dengan mengatakan angka 1 'memiliki nilai' padahal sebenarnya itu adalah nilai. Tapi NULL mewakili tidak bernilai ..
systemaddict
Sebagai solusi manual, Anda biasanya SELECT * FROM MyTable WHERE coalesce(MyColumn, 'x') <> 'x'dapat menetapkan konstanta jika nilai NULL, asalkan Anda memberikan tipe data yang sesuai untuk nilai sentinel x (dalam hal ini string / char). Ini adalah sintaks TSQL tetapi Oracle dan mesin lainnya memiliki fitur serupa.
systemaddict
26

Perhatikan bahwa perilaku ini adalah perilaku default (ANSI).

Jika kamu:

 SET ANSI_NULLS OFF

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

Anda akan mendapatkan hasil yang berbeda.

SET ANSI_NULLS OFF tampaknya akan pergi di masa depan ...

Cade Roux
sumber
8
+1 ... tidak cukup cepat. Sekarang kapan saya bisa mendapatkan "duplikat" NULL dalam indeks? :(
Anda bisa mendapatkan duplikat NULL dalam indeks SQL Server dengan menambahkan klausa WHERE dalam indeks yang difilter (misalnya create unique index UK_MyTable on MyTable (Column) where Column is not null): msdn.microsoft.com/en-us/library/cc280372.aspx
Anthony Mills
3
Catatan dari dokumen: Ketika SET ANSI_NULLSMATI, operator pembanding Equals (=) dan Not Equal To (<>) tidak mengikuti standar ISO. Pernyataan SELECT yang menggunakan WHERE column_name = NULLmengembalikan baris yang memiliki nilai nol dalam nama_kolom. Pernyataan SELECT yang menggunakan WHERE column_name <> NULLmengembalikan baris yang memiliki nilai nonnull di kolom. Juga, pernyataan SELECT yang menggunakan WHERE column_name <> XYZ_valuemengembalikan semua baris yang bukan XYZ_value dan yang bukan NULL. IMHO, pernyataan terakhir ini tampaknya sedikit aneh karena tidak menyertakan null dari hasilnya!
DarthPablo
4
Catatan penting dari dokumen msdn : Dalam versi SQL Server yang akan datang [lebih baru dari 2014], ANSI_NULLS akan selalu AKTIF dan aplikasi apa pun yang secara eksplisit mengatur opsi ke OFF akan menghasilkan kesalahan. Hindari menggunakan fitur ini dalam pekerjaan pengembangan baru, dan rencanakan untuk memodifikasi aplikasi yang saat ini menggunakan fitur ini.
Otiel
7

Dalam SQL, apa pun yang Anda evaluasi / hitung dengan NULLhasil ke UNKNOWN

Inilah sebabnya SELECT * FROM MyTable WHERE MyColumn != NULLatau SELECT * FROM MyTable WHERE MyColumn <> NULLmemberi Anda 0 hasil.

Untuk memberikan pemeriksaan NULLnilai, fungsi isNull disediakan.

Selain itu, Anda bisa menggunakan ISoperator seperti yang Anda gunakan dalam kueri ketiga.

Semoga ini membantu.

Mahendra Liya
sumber
"Dalam SQL, apa pun yang Anda evaluasi / hitung dengan hasil NULL menjadi 'NULL'" - salah. Hasil yang Anda maksud adalah TIDAK DIKETAHUI.
onedaywhen
@ MahendraLiya fungsi isNull tidak disediakan untuk memeriksa NULLS, tetapi " Mengganti NULL dengan nilai penggantian yang ditentukan. ". Anda harus menggunakan IS NULL atau IS NOT NULL sebagai ganti ISNULL yang merupakan hal yang berbeda.
Insinyur Terbalik
7

Satu-satunya tes untuk NULL adalah IS NULL atau IS NOT NULL. Pengujian untuk kesetaraan tidak masuk akal karena menurut definisi orang tidak tahu apa nilainya.

Inilah artikel wikipedia untuk dibaca:

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

dkretz
sumber
6

Kita gunakan

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

untuk mengembalikan semua baris di mana MyColumn adalah NULL atau semua baris di mana MyColumn adalah string kosong. Bagi banyak "pengguna akhir", masalah NULL vs string kosong adalah perbedaan tanpa perlu dan titik kebingungan.

Jeff Mergler
sumber
5

Saya hanya tidak melihat alasan fungsional dan mulus untuk null tidak dapat dibandingkan dengan nilai-nilai lain atau null lainnya, karena kita dapat dengan jelas membandingkannya dan mengatakan mereka sama atau tidak dalam konteks kita. Itu lucu. Hanya karena beberapa kesimpulan dan konsistensi logis kita perlu terus-menerus peduli dengannya. Itu tidak fungsional, membuatnya lebih fungsional dan serahkan kepada para filsuf dan ilmuwan untuk menyimpulkan apakah itu konsisten atau tidak dan apakah itu memegang "logika universal". :) Seseorang mungkin mengatakan itu karena indeks atau sesuatu yang lain, saya ragu bahwa hal-hal itu tidak dapat dibuat untuk mendukung nol sama dengan nilai. Ini sama dengan membandingkan dua gelas kosong, satu adalah gelas anggur dan lainnya adalah gelas bir, kami tidak membandingkan jenis objek tetapi nilai-nilai yang dikandungnya, sama seperti Anda dapat membandingkan int dan varchar, dengan nol itu ' Bahkan lebih mudah, itu bukan apa-apa dan apa yang sama-sama dimiliki oleh ketiadaan, keduanya sama, jelas dapat dibandingkan oleh saya dan semua orang yang menulis sql, karena kami terus-menerus memecahkan logika itu dengan membandingkannya dengan cara yang aneh karena beberapa standar ANSI. Mengapa tidak menggunakan daya komputer untuk melakukannya untuk kita dan saya ragu itu akan memperlambat segalanya jika semuanya terkait dibangun dengan itu dalam pikiran. "Ini bukan nol itu bukan apa-apa", itu bukan apel itu apfel, ayolah ... Secara fungsional adalah teman Anda dan ada juga logika di sini. Pada akhirnya satu-satunya hal yang penting adalah fungsionalitas dan tidak menggunakan null dengan cara itu membawa fungsionalitas yang lebih atau kurang dan kemudahan penggunaan. Apakah ini lebih bermanfaat? karena kami terus-menerus melanggar logika itu dengan membandingkannya dengan cara yang aneh karena beberapa standar ANSI. Mengapa tidak menggunakan daya komputer untuk melakukannya untuk kita dan saya ragu itu akan memperlambat segalanya jika semuanya terkait dibangun dengan itu dalam pikiran. "Ini bukan nol itu bukan apa-apa", itu bukan apel itu apfel, ayolah ... Secara fungsional adalah teman Anda dan ada juga logika di sini. Pada akhirnya satu-satunya hal yang penting adalah fungsionalitas dan tidak menggunakan null dengan cara itu membawa fungsionalitas yang lebih atau kurang dan kemudahan penggunaan. Apakah ini lebih bermanfaat? karena kami terus-menerus melanggar logika itu dengan membandingkannya dengan cara yang aneh karena beberapa standar ANSI. Mengapa tidak menggunakan daya komputer untuk melakukannya untuk kita dan saya ragu itu akan memperlambat segalanya jika semuanya terkait dibangun dengan itu dalam pikiran. "Ini bukan nol itu bukan apa-apa", itu bukan apel itu apfel, ayolah ... Secara fungsional adalah teman Anda dan ada juga logika di sini. Pada akhirnya satu-satunya hal yang penting adalah fungsionalitas dan tidak menggunakan null dengan cara itu membawa fungsionalitas yang lebih atau kurang dan kemudahan penggunaan. Apakah ini lebih bermanfaat? Bukan apel itu apfel, ayolah ... Secara fungsional adalah teman Anda dan ada juga logika di sini. Pada akhirnya satu-satunya hal yang penting adalah fungsionalitas dan tidak menggunakan null dengan cara itu membawa fungsionalitas yang lebih atau kurang dan kemudahan penggunaan. Apakah ini lebih bermanfaat? Bukan apel itu apfel, ayolah ... Secara fungsional adalah teman Anda dan ada juga logika di sini. Pada akhirnya satu-satunya hal yang penting adalah fungsionalitas dan tidak menggunakan null dengan cara itu membawa fungsionalitas yang lebih atau kurang dan kemudahan penggunaan. Apakah ini lebih bermanfaat?

Pertimbangkan kode ini:

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

Berapa banyak dari Anda yang tahu kode apa yang akan dikembalikan? Dengan atau tanpa TIDAK mengembalikan 0. Bagi saya itu tidak berfungsi dan itu membingungkan. Dalam c # itu semua sebagaimana mestinya, operasi perbandingan mengembalikan nilai, secara logis ini juga menghasilkan nilai, karena jika tidak ada yang bisa dibandingkan (kecuali. Tidak ada :)). Mereka hanya "berkata": apa pun yang dibandingkan dengan nol "mengembalikan" 0 dan itu menciptakan banyak solusi dan sakit kepala.

Ini adalah kode yang membawaku ke sini:

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

Saya hanya perlu membandingkan jika dua bidang (di mana) memiliki nilai yang berbeda, saya bisa menggunakan fungsi, tapi ...

Hrvoje Batrnek
sumber
4

NULL Tidak dapat dibandingkan dengan nilai apa pun menggunakan operator pembanding. NULL = NULL salah. Null bukan nilai. Operator IS dirancang khusus untuk menangani perbandingan NULL.

Vincent Ramdhanie
sumber
5
Saya selalu menikmati orang-orang yang bingung ketika kadang-kadang saya gunakan di null = nullmana orang mungkin menggunakan 1=0beberapa permintaan khusus. Dan jika mereka mengeluh, saya ubah ke null != null:)
SWeko
8
"NULL = NULL salah" Tidak begitu. NULL = NULL dievaluasi menjadi tidak dikenal dan tidak salah.
nvogel
@dportas yang begitu tetapi saya maksudkan bahwa dalam kondisi itu tidak akan dievaluasi sebagai benar.
Vincent Ramdhanie
@VincentRamdhanie tidak salah; pada kenyataannya, di postgres akan dievaluasi sebagai NULL
Pere
2

Pertanyaan lama, tetapi berikut ini mungkin menawarkan beberapa detail.

nullmewakili tidak ada nilai atau nilai yang tidak diketahui. Itu tidak menentukan mengapa tidak ada nilai, yang dapat menyebabkan ambiguitas.

Misalkan Anda menjalankan kueri seperti ini:

SELECT *
FROM orders
WHERE delivered=ordered;

yaitu, Anda mencari baris di mana tanggal ordereddan deliveredadalah sama.

Apa yang diharapkan ketika satu atau kedua kolom adalah nol?

Karena setidaknya salah satu tanggal tidak diketahui, Anda tidak dapat berharap untuk mengatakan bahwa 2 tanggal itu sama. Ini juga kasus ketika kedua tanggal tidak diketahui: bagaimana mereka bisa sama jika kita bahkan tidak tahu apa itu?

Karena alasan ini, ekspresi apa pun yang memperlakukan nullsebagai nilai harus gagal. Dalam hal ini, itu tidak akan cocok. Ini juga terjadi jika Anda mencoba yang berikut:

SELECT *
FROM orders
WHERE delivered<>ordered;

Sekali lagi, bagaimana kita dapat mengatakan bahwa dua nilai tidak sama jika kita tidak tahu apa itu nilai.

SQL memiliki tes khusus untuk nilai yang hilang:

IS NULL

Secara khusus ini tidak membandingkan nilai, tetapi mencari nilai yang hilang .

Akhirnya, berkenaan dengan !=operator, sejauh yang saya ketahui, itu sebenarnya tidak ada dalam standar, tetapi didukung secara luas. Itu ditambahkan untuk membuat programmer dari beberapa bahasa merasa lebih di rumah. Terus terang, jika seorang programmer mengalami kesulitan mengingat bahasa apa yang mereka gunakan, mereka memulai dengan buruk.

Manngo
sumber
Ini sama "logika" tidak masuk akal "" yang @Hove jelaskan dalam jawabannya. Yang benar adalah bahwa dalam konteks ini tidak perlu peralatan tambahan itu; dapat dengan mudah diasumsikan bahwa ketika kita membandingkan sesuatu dengan NULLkita berarti bahwa kita membandingkan nilai dengan 'memiliki NULLnilai', bukan nilai untuk "nilai yang tidak ditentukan bahwa yang mendasari NULLadalah ¿memiliki? tetapi kita tidak tahu ", yang jelas kita tidak akan pernah bisa tahu. Itu akan sangat memudahkan.
Pere
@Pere Saya tidak akan mengatakan bahwa ini benar-benar “tidak masuk akal”, dan saya tidak yakin bahwa menulis IS NULLjauh lebih sulit daripada menulis = NULL. Saya pikir akan lebih konsisten jika WHERE columnA = columnBmemiliki interpretasi yang sama dengan WHERE columnA = NULL, daripada memperlakukan yang terakhir sebagai kasus khusus. Ingat bahwa NULLini bukan nilai. Dalam bahasa pemrograman mana yang sah untuk mengujinya variable == nulladalah karena nullmemiliki makna yang berbeda; itu tidak mewakili sesuatu yang tidak diketahui, tetapi pengaturan ulang suatu nilai secara sengaja. Tidak demikian halnya dengan SQL.
Manngo
Itu sebabnya saya meletakkannya di antara tanda kutip, @Mangoo;) (dan juga "logika"). Jangan marah padaku; Saya sedang berbicara tentang "alasan" ANSI, bukan tentang penjelasan Anda. Saya setuju bahwa tidak ada overhead antara IS NULLAND =NULLdalam contoh terbaru Anda. Tapi lihat yang terakhir melayang-layang. Saya lelah mengalaminya lagi dan lagi, harus melakukan banyak ¿yang tidak perlu? pemeriksaan ekstra ...
Pere
1

Saya ingin menyarankan kode ini saya buat untuk menemukan jika ada perubahan nilai, imenjadi nilai baru dan dmenjadi yang lama (meskipun urutannya tidak masalah). Dalam hal ini, perubahan dari nilai ke nol atau sebaliknya adalah perubahan tetapi dari nol ke nol tidak (tentu saja, dari nilai ke nilai lain adalah perubahan tetapi dari nilai ke nilai yang sama tidak).

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

Untuk menggunakan fungsi ini, Anda bisa

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

Hasilnya adalah:

---- 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

Penggunaan sql_variant membuatnya kompatibel untuk berbagai jenis

Yariv de Botton
sumber