SQL не равен & null - PullRequest
       8

SQL не равен & null

9 голосов
/ 12 марта 2009

Мы хотели бы написать этот запрос:

select * from table 
where col1 != 'blah' and col2 = 'something'

Мы хотим, чтобы запрос включал строки, в которых col1 равен нулю (а col2 = 'что-то'). В настоящее время запрос не будет делать это для строк, в которых col1 равен нулю. Является ли приведенный ниже запрос лучшим и быстрым способом?

select * from table 
where (col1 != 'blah' or col1 is null) and col2 = 'something'

В качестве альтернативы, мы могли бы при необходимости обновить все нулевые значения col1 до пустых строк. Будет ли это лучший подход? Тогда наш первый запрос будет работать.


Обновление : Re: использование NVL: я прочитал в другой публикации , что это не считается хорошим вариантом с точки зрения производительности.

Ответы [ 9 ]

16 голосов
/ 12 марта 2009

В Oracle нет разницы между пустой строкой и NULL.

Это вопиющее игнорирование стандарта SQL, но вы идете ...

В дополнение к этому вы не можете сравнивать NULL (или не NULL) с «обычными» операторами: «col1 = null» не будет работать, «col1 = '» не будет работать, «col1! = Null» не будет работать, вы должны использовать «ноль».

Итак, нет, вы не можете заставить эту работу работать иначе, чем «col 1 is null» или какой-то другой вариант (например, использование nvl).

3 голосов
/ 04 октября 2012

Хотя не самый читаемый - Oracle имеет функцию LNNVL , которая по сути является функцией not (), но инвертирует поведение для нулей. Это означает, что сравнение чего-либо с нулем внутри lnnvl вернет true (я не знаю, какое это может иметь влияние на производительность).

Чтобы сделать то, что вы хотите в одном выражении:

select * from table where lnnvl(col1 = 'blah') and col2 = 'something'

Обратите внимание, что это будет работать только для сравнения значения, допускающего обнуляемость, со значением, которое, как вы можете быть уверены, не обнуляется. В противном случае вам нужно будет делать то, что предлагает Тило, - использовать оператор, подобный

lnnvl(nvl(col1, -1) = nvl(col2, -1))
3 голосов
/ 12 марта 2009

Я думаю, что решение, которое вы разместили, является одним из лучших вариантов.

Что касается производительности, то, на мой взгляд, это не большая разница в этом случае, если в предложении уже есть сравнение! =, Обычно оптимизатор не использует индекс в этом столбце, поскольку селективность недостаточна, более различающий фильтр будет другой стороной условия "и".

Если вы спросите меня, я не буду использовать пустую строку как ноль, но, возможно, это просто личное предпочтение.

2 голосов
/ 12 марта 2009

Это зависит от ваших данных, но большинство оптимизаторов будут смотреть на col2 до col1, так как = это более простой показатель, чем! =.

В противном случае есть несколько способов ускорить этот запрос. Это, вероятно, лучше всего сделать (col1! = 'Blah' или col1 равно null), но некоторые базы данных позволяют индексировать функцию. Таким образом, вы можете индексировать coalesce (col1, 0) и получать хорошую производительность.

На самом деле это зависит от ваших данных и вашей таблицы.

0 голосов
/ 25 июля 2012

Как насчет этой опции. Я думаю, что это может сработать, если ваше значение никогда не равно нулю.

where not (value = column)

, что приведет к следующей таблице истинности для оценки для предложения where

                    col1
              | 'bla' |  null |
              -----------------
      | 'bla' |   F   |   T   |
value -------------------------
      |  null |   T   |  *T   | 

* это единственное, что "неправильно", но это нормально, поскольку наше значение никогда не равно нулю

Обновление

Хорошо, я только что опробовал свою идею, и она провалилась. Я оставлю здесь ответ, чтобы сэкономить время других, пытающихся сделать то же самое. Вот мои результаты:

select 'x', 'x' from dual where not ('x' = 'x');
0 rows
select 'x', 'y' from dual where not ('x' = 'y');
1 row
select 'x', 'null' from dual where not ('x' = null);
0 rows
select 'null', 'null' from dual where not (null = null);
0 rows

Обновление 2

Это решение работает, если ваше значение никогда не равно нулю (соответствует таблице истинности выше)

where ('blah' != col1 or col1 is null)

тесты здесь:

select 'x', 'x' from dual where ('x' != 'x' or 'x' is null);
0 rows
select 'x', 'y' from dual where ('x' != 'y' or 'y' is null);
1 row
select 'x', 'null' from dual where ('x' != null or null is null);
1 row
select 'null', 'null' from dual where (null != null or null is null);
1 row
0 голосов
/ 08 мая 2009

Если вы хотите ускорить такого рода запросы и используете Oracle 10g или новее, используйте индекс на основе функций, чтобы превратить эти значения NULL в значения:

CREATE INDEX query_specific_index ON table (col2, NVL(col1,'***NULL***'));

select * from table 
where NVL(col1,'***NULL***') != 'blah' and col2 = 'something';

База данных, скорее всего, будет использовать индекс в этом сценарии (конечно, в зависимости от решения CBO, которое зависит от количества строк и точности статистики). Запрос ДОЛЖЕН использовать точное выражение, указанное в индексе - в этом случае "NVL(col1,'***NULL***')"

Конечно, выберите значение для '***NULL***', которое не будет конфликтовать ни с какими данными в столбце col1!

0 голосов
/ 12 марта 2009

В Oracle используйте функцию nvl

select * from table where nvl(col1,'notblah') <> 'blah'
0 голосов
/ 12 марта 2009

для Oracle

select * from table where nvl(col1, 'value') != 'blah' and col2 = 'something'

Для SqlServer

select * from table where IsNull(col1, '') <> 'blah' and col2 = 'something'
0 голосов
/ 12 марта 2009

Я думаю, что ваше увеличение будет минимальным при изменении значений NULL на "" строки. Однако, если «blah» не равен NULL, он должен содержать значения NULL.

РЕДАКТИРОВАТЬ: Я думаю, я удивлен, почему меня здесь проголосовали. Если 'blah', если не null или пустая строка, то это никогда не должно иметь значения, поскольку вы уже проверяете, не равен ли COL1 'blah', который НЕ является NULL или пустой строкой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...