Przykład
Mam stolik
ID myField
------------
1 someValue
2 NULL
3 someOtherValue
oraz wyrażenie logiczne T-SQL, które może mieć wartość PRAWDA, FAŁSZ lub (ze względu na logikę potrójną SQL) NIEZNANE:
SELECT * FROM myTable WHERE myField = 'someValue'
-- yields record 1
Jeśli chcę uzyskać wszystkie inne rekordy , nie mogę po prostu zanegować wyrażenia
SELECT * FROM myTable WHERE NOT (myField = 'someValue')
-- yields only record 3
Wiem, dlaczego tak się dzieje (logika trójskładnikowa) i wiem, jak rozwiązać ten konkretny problem.
Wiem, że mogę po prostu użyć myField = 'someValue' AND NOT myField IS NULL
i otrzymuję wyrażenie „odwracalne”, które nigdy nie daje NIEZNANE:
SELECT * FROM myTable WHERE NOT (myField = 'someValue' AND myField IS NOT NULL)
-- yields records 2 and 3, hooray!
Ogólna sprawa
Porozmawiajmy teraz o ogólnym przypadku. Powiedzmy, że zamiast myField = 'someValue'
mam złożone wyrażenie obejmujące wiele pól i warunków, być może podkwerend:
SELECT * FROM myTable WHERE ...some complex Boolean expression...
Czy istnieje ogólny sposób na „odwrócenie” tej wyprawy? Punkty bonusowe, jeśli działa w przypadku podwyrażeń:
SELECT * FROM myTable
WHERE ...some expression which stays...
AND ...some expression which I might want to invert...
Muszę wesprzeć SQL Server 2008-2014, ale jeśli istnieje eleganckie rozwiązanie wymagające nowszej wersji niż 2008, to też chcę o tym usłyszeć.
źródło
Pierwsza myśl, która przychodzi mi do głowy:
Zwroty:
Zwroty:
Zależy to od sposobu, w jaki
EXISTS
zawsze zwraca true lub false , nigdy nieznany . KoniecznośćSELECT 1 WHERE
jest niestety konieczna, ale może być wykonalna dla twojego wymagania, na przykład:Zobacz EXISTS (Transact-SQL)
Nieco bardziej skomplikowane obrobionych przykład pokazujący jak albo
EXISTS
czyCASE/IIF
metody mogą być stosowane do odwrócenia indywidualnych predykatów:Kod:
źródło
Jeśli nie masz nic przeciwko przepisywaniu podwyrażeń z góry, możesz użyć
COALESCE
:Państwo musi upewnić się, że
'notSomeValue'
różni się od'someValue'
; najlepiej byłaby to jakaś całkowicie nielegalna wartość dla kolumny. (Oczywiście nie może byćNULL
.) Łatwo to zanegować, nawet jeśli masz długą listę:Czystsze, prostsze i bardziej oczywiste niż
CASE
lubIIF
, moim zdaniem,. Głównym minusem jest druga wartość, o której wiesz, że nie jest równa, ale to naprawdę problem, jeśli nie znasz rzeczywistej wartości z góry. W takim przypadku możesz zrobić to, co sugeruje Hanno Binder i użyćCOALESCE(myField, CONCAT('not', 'someValue')) = 'someValue'
(gdzie'someValue'
tak naprawdę byłby sparametryzowany).COALESCE
udokumentowano, że będzie dostępny począwszy od SQL Server 2005.Należy pamiętać, że takie bałaganie w zapytaniu (przy użyciu dowolnej z zalecanych tutaj metod) może utrudnić zoptymalizowanie zapytania przez bazę danych. W przypadku dużych zestawów danych
IS NULL
prawdopodobnie łatwiej jest zoptymalizować wersję.źródło
COALESCE(myField, CONCAT('not', 'someValue')) = 'someValue'
powinien działać dla każdego „someValue” i dowolnych danych w tabeli.Istnieje wbudowany operator zestawu EXCEPT , który skutecznie usuwa wyniki drugiego zapytania z pierwszego zapytania.
źródło
Czy dostępny jest COALESCE?
źródło
sql-server
, ale niemysql
lubpostgresql
.BOOLEAN
typ, a MySQL ma (sfałszowany)BOOLEAN
typ, który może być parametremCOALESCE()
funkcji. Jeśli pytanie oznaczono tagiemsql-agnostic
lubsql-standard
, odpowiedź byłaby w porządku.