Contoh
Saya punya meja
ID myField
------------
1 someValue
2 NULL
3 someOtherValue
dan ekspresi T-SQL Boolean yang dapat mengevaluasi menjadi BENAR, SALAH atau (karena logika ternary SQL) DIKETAHUI:
SELECT * FROM myTable WHERE myField = 'someValue'
-- yields record 1
Jika saya ingin mendapatkan semua catatan lain , saya tidak bisa begitu saja meniadakan ekspresi
SELECT * FROM myTable WHERE NOT (myField = 'someValue')
-- yields only record 3
Saya tahu mengapa ini terjadi (logika ternary), dan saya tahu bagaimana menyelesaikan masalah khusus ini.
Saya tahu saya hanya bisa menggunakan myField = 'someValue' AND NOT myField IS NULL
dan saya mendapatkan ekspresi "tidak bisa dibalik" yang tidak pernah menghasilkan UNKNOWN:
SELECT * FROM myTable WHERE NOT (myField = 'someValue' AND myField IS NOT NULL)
-- yields records 2 and 3, hooray!
Kasus Umum
Sekarang, mari kita bicara tentang kasus umum. Katakanlah alih-alih myField = 'someValue'
saya memiliki ekspresi kompleks yang melibatkan banyak bidang dan kondisi, mungkin subquery:
SELECT * FROM myTable WHERE ...some complex Boolean expression...
Apakah ada cara generik untuk "membalikkan" pengungkapan ini? Poin bonus jika berfungsi untuk subekspresi:
SELECT * FROM myTable
WHERE ...some expression which stays...
AND ...some expression which I might want to invert...
Saya perlu mendukung SQL Server 2008-2014, tetapi jika ada solusi elegan yang membutuhkan versi yang lebih baru dari 2008, saya tertarik untuk mendengarnya juga.
sumber
Pikiran pertama yang terjadi pada saya:
Pengembalian:
Pengembalian:
Ini bergantung pada cara
EXISTS
selalu mengembalikan benar atau salah , tidak pernah tidak diketahui .SELECT 1 WHERE
Sayangnya, kebutuhan untuk itu diperlukan, tetapi bisa juga sesuai dengan kebutuhan Anda, misalnya:Lihat EXIS (Transact-SQL)
Contoh yang sedikit lebih rumit yang menunjukkan bagaimana salah satu
EXISTS
atauCASE/IIF
metode dapat diterapkan untuk membalikkan masing-masing predikat:Kode:
sumber
Jika Anda tidak keberatan menulis ulang sub-ekspresi di muka, Anda dapat menggunakan
COALESCE
:Anda harus memastikan bahwa
'notSomeValue'
itu berbeda dari'someValue'
; lebih disukai, itu akan menjadi nilai yang sepenuhnya ilegal untuk kolom. (Tidak mungkinNULL
, tentu saja.) Ini mudah untuk dinegasikan, bahkan jika Anda memiliki daftar panjang:Lebih bersih, lebih sederhana, dan lebih jelas daripada
CASE
atauIIF
, menurut saya. Kelemahan utama adalah memiliki nilai kedua yang Anda tahu tidak sama, tetapi ini hanya masalah jika Anda tidak tahu nilai aktual di depan. Dalam hal ini, Anda dapat melakukan seperti yang disarankan dan digunakan Hanno BinderCOALESCE(myField, CONCAT('not', 'someValue')) = 'someValue'
(di mana'someValue'
sebenarnya akan diparameterisasi).COALESCE
didokumentasikan tersedia dari SQL Server 2005 dan seterusnya.Perlu diketahui bahwa mengacaukan permintaan Anda seperti ini (menggunakan salah satu metode yang direkomendasikan di sini) dapat mempersulit basis data untuk mengoptimalkan kueri Anda. Untuk kumpulan data besar,
IS NULL
versi ini cenderung lebih mudah dioptimalkan.sumber
COALESCE(myField, CONCAT('not', 'someValue')) = 'someValue'
harus berfungsi untuk "sebagian Nilai" dan data apa pun di tabel.Ada operator set KECUALI bawaan yang, secara efektif, menghapus hasil kueri kedua dari kueri pertama.
sumber
Apakah COALESCE tersedia?
sumber
sql-server
, meskipun, tidakmysql
ataupostgresql
.BOOLEAN
tipe dan MySQL memiliki tipe (palsu)BOOLEAN
yang dapat menjadi parameterCOALESCE()
fungsi. Jika pertanyaan telah ditandai dengansql-agnostic
atausql-standard
, jawabannya akan baik-baik saja.