пример
У меня есть стол
ID myField
------------
1 someValue
2 NULL
3 someOtherValue
и логическое выражение T-SQL, которое может принимать значения ИСТИНА, ЛОЖЬ или (из-за троичной логики SQL) НЕИЗВЕСТНО:
SELECT * FROM myTable WHERE myField = 'someValue'
-- yields record 1
Если я хочу получить все остальные записи , я не могу просто отрицать выражение
SELECT * FROM myTable WHERE NOT (myField = 'someValue')
-- yields only record 3
Я знаю, как это происходит (троичная логика), и я знаю, как решить эту конкретную проблему.
Я знаю, что могу просто использовать, myField = 'someValue' AND NOT myField IS NULL
и я получаю «обратимое» выражение, которое никогда не приводит к НЕИЗВЕСТНОМУ:
SELECT * FROM myTable WHERE NOT (myField = 'someValue' AND myField IS NOT NULL)
-- yields records 2 and 3, hooray!
Общий случай
Теперь поговорим об общем случае. Допустим, вместо myField = 'someValue'
меня есть какое-то сложное выражение, включающее множество полей и условий, может быть, подзапросы:
SELECT * FROM myTable WHERE ...some complex Boolean expression...
Есть ли общий способ «инвертировать» это выражение? Бонусные баллы, если это работает для подвыражений:
SELECT * FROM myTable
WHERE ...some expression which stays...
AND ...some expression which I might want to invert...
Мне нужно поддерживать SQL Server 2008-2014, но если есть элегантное решение, требующее более новой версии, чем 2008, мне тоже интересно об этом услышать.
источник
Первая мысль, которая приходит мне в голову:
Возвращает:
Возвращает:
Это зависит от того, как
EXISTS
всегда возвращает истину или ложь , никогда неизвестно . КSELECT 1 WHERE
сожалению, это необходимо, но оно может быть выполнено по вашему требованию, например:Смотрите EXISTS (Transact-SQL)
Немного более сложный обработанный пример, показывающий, как можно применять методы
EXISTS
илиCASE/IIF
методы для инвертирования отдельных предикатов:Код:
источник
Если вы не возражаете переписать подвыражения заранее, вы можете использовать
COALESCE
:Вы должны убедиться, что
'notSomeValue'
это отличается от'someValue'
; предпочтительно, это будет какое-то совершенно недопустимое значение для столбца. (Конечно, и не может бытьNULL
.) Это легко отрицать, даже если у вас длинный список:Чище, проще и очевиднее, чем
CASE
илиIIF
, на мой взгляд. Основным недостатком является наличие второго значения, которое, как вы знаете, не равно, но это действительно проблема, если вы не знаете фактическое значение заранее. В этом случае вы можете делать то, что предлагает и использует Ханно БиндерCOALESCE(myField, CONCAT('not', 'someValue')) = 'someValue'
(где на'someValue'
самом деле будет параметризоваться).COALESCE
документально подтверждено, чтобы быть доступным с SQL Server 2005 и далее.Имейте в виду, что использование такого запроса (используя любой из методов, рекомендованных здесь) может затруднить оптимизацию запроса для базы данных. Для больших наборов данных
IS NULL
версию, вероятно, легче оптимизировать.источник
COALESCE(myField, CONCAT('not', 'someValue')) = 'someValue'
должен работать для любого "someValue" и любых данных в таблице.Есть встроенный оператор набора EXCEPT, который эффективно удаляет результаты второго запроса из первого запроса.
источник
COALESCE доступен?
источник
sql-server
, однако, неmysql
илиpostgresql
.BOOLEAN
тип, а у MySQL (поддельный)BOOLEAN
тип, который может быть параметромCOALESCE()
функции. Если бы вопрос был помечен знакомsql-agnostic
илиsql-standard
, ответ был бы в порядке.