TIDAK (a = 1 AND b = 1) vs (a <> 1 AND b <> 1)

16

Dalam WHEREklausa dari kueri SQL, saya berharap dua kondisi ini memiliki perilaku yang sama:

NOT (a=1 AND b=1)

vs.

a<>1 AND b<>1

Kondisi pertama berperilaku seperti yang diharapkan, dan sementara saya membenarkan kondisi kedua untuk melakukan hal yang sama, itu tidak.

Ini adalah hal yang sangat mendasar, tetapi dengan malu saya tidak dapat melihat apa yang saya lakukan salah.

jon
sumber
Bisakah Anda memposting data contoh dan hasil yang diharapkan vs hasil aktual?
Gareth Lyons
6
Sebagaimana dicatat oleh Lenard dalam jawabannya, ini adalah contoh aturan De Morgan: not (A dan B) = (bukan A) atau (bukan B) , tidak (A atau B) = (bukan A) dan (bukan B) . Hati-hati dengan nilai NULL.
Barranka
2
Pikirkan saja dalam bahasa Inggris. Yang pertama Anda adalah "Bukan itu masalahnya bahwa saya berdua adalah Raja Prancis dan juga manusia" - sungguh benar. Yang kedua adalah "Aku bukan Raja Prancis atau manusia" - sangat salah.
Patrick Stevens
3
Ini bertentangan dengan "hukum De Morgan". Setara dengan itu a <> 1 OR b<>1.
Willem Van Onsem

Jawaban:

46

Mereka tidak setara.

NOT (a=1 AND b=1)

setara dengan:

(NOT a=1 OR NOT b=1) <=> (a<>1 OR b<>1)

Kesetaraan ini dikenal sebagai De Morgan's Law. Lihat misalnya:

https://en.wikipedia.org/wiki/De_Morgan%27s_laws

Teknik yang bagus untuk membuktikan / menyangkal persamaan untuk ekspresi aljabar boolean adalah dengan menggunakan cte untuk domain, dan membandingkan ekspresi berdampingan:

with T(a) as ( values 0,1 )
   , U(a,b) as (select t1.a, t2.a as b 
               from t as t1 
               cross join t as t2
) 
select a,b
    , case when not (a=1 and b=1) then 1 else 0 end
    , case when a<>1 and b<>1 then 1 else 0 end 
from U

A           B           3           4          
----------- ----------- ----------- -----------
          0           0           1           1
          0           1           1           0
          1           0           1           0
          1           1           0           0

Sunting: Karena DB2 tidak mendukung tipe data Boolean, saya memperluas contoh di:

http://sqlfiddle.com/#!15/25e1a/19

Kueri yang ditulis ulang terlihat seperti:

with T(a) as ( values (0),(1),(null) )
   , U(a,b) as (select t1.a, t2.a as b 
                from t as t1 
                cross join t as t2
) 
select a,b
     , not (a=1 and b=1) as exp1 
     , a<>1 or b<>1 as exp2
from U;

Hasil kueri adalah:

a       b       exp1        exp2
--------------------------------
0       0       true        true
0       1       true        true
0       (null)  true        true
1       0       true        true
1       1       false       false
1       (null)  (null)      (null)
(null)  0       true        true
(null)  1       (null)      (null)
(null)  (null)  (null)      (null)

Seperti yang ditunjukkan, exp1 dan exp2 adalah sama.

Lennart
sumber
16
+1 hanya untuk menyebut De Morgan. Harus membaca wajib bagi siapa saja yang melakukan segala bentuk pemrograman / skrip.
Tonny
Tapi bagaimana dengan NULL?
dan04
@ dan04 Anda dapat menambahkan NULL ke baris pertama (menjadi with T(a) as ( values 0,1,NULL )dan menjalankan kembali kueri dan Anda akan melihat apa yang terjadi. NULL pasti melempar kunci pas di sebagian besar aturan kesetaraan yang kita pelajari. Jawaban singkatnya adalah = NULL dan a < > NULL keduanya menghasilkan NULL, sehingga mereka akan jatuh ke kasus lain. Untuk bacaan lebih lanjut: ( stackoverflow.com/questions/1833949/… )
Brian J
Saya tidak yakin mengapa Anda harus mengubah contoh pertama untuk DB2. Ini berfungsi seperti yang ditunjukkan pada saya. Saya menggunakan DB2 untuk saya daripada DB2 LUW. Contoh kedua memiliki beberapa kesalahan sintaks untuk DB2 untuk i.
jmarkmurphy
@markmarkphy, saya tidak tahu DB2 untuk saya, mungkin itu berfungsi di sana. Untuk LUW, ekspresi case memetakan ke 0 atau 1 sehingga harus diubah untuk memasukkan null juga. Dengan melakukan itu, ekspresi huruf tidak lagi sepele (IMO), dan ekspresi menjadi sulit untuk dipikirkan.
Lennart
9

Contoh pertama Anda mengatakan:

Mengembalikan semua baris kecuali di mana kedua a = 1 AND b = 1

Contoh kedua Anda mengatakan:

Mengembalikan semua baris kecuali di mana baik sebuah = 1 OR b = 1

Agar kueri kedua untuk mengembalikan sama dengan yang pertama, Anda harus mengubah ANDkeOR

CREATE TABLE #Test (a BIT, b BIT);

INSERT INTO #Test
        ( a, b )
VALUES
        ( 0, 0 ),
        ( 1, 0 ),
        ( 0, 1 ),
        ( 1, 1 );

SELECT * FROM #Test AS t
WHERE NOT (a=1 AND b=1);

SELECT * FROM #Test AS t
WHERE (a <> 1 OR b <> 1);

Ini mengembalikan hasil berikut

a   b
0   0
1   0
0   1
Mark Sinkinson
sumber
Bisakah Anda menjelaskan mengapa a<>1 AND b<>1diterjemahkan menjadi "baik a = 1 ATAU b = 1"?
doub1ejack
1
@ doub1ejack, Anda memerlukan negasi tambahan dalam pernyataan kedua Anda untuk membuatnya setara dengan yang pertama: NOT ( a=1 OR b=1 ). Bahasa alami yang disayangkan mengandung ambiguitas yang membuatnya sulit untuk menerjemahkan formula logis ke bahasa alami dan sebaliknya. Misalnya, apakah neither a=1 nor b=1artinya NOT ( a=1 OR b=1 )atau (NOT a=1) OR (NOT b=1)?
Lennart
1
@ doub1ejack Kebalikan dari "mobil itu merah DAN memiliki empat pintu" adalah "Baik mobil itu tidak merah, ATAU ia tidak memiliki empat pintu." Jika banyak hal harus benar untuk membuat pernyataan itu benar, maka hanya satu di antaranya yang salah untuk menjadikannya salah.
hobbs