SQL «IN subquery», когда подзапрос может быть NULL - PullRequest
7 голосов
/ 20 декабря 2010

У меня есть запрос, который должен возвращать результаты, которые НЕ совпадают в подзапросе. Подзапрос может вернуть пустой результат, поэтому мне нужно установить значение по умолчанию (скажем, 0), если подзапрос возвращает пустой набор, чтобы предотвратить IN (NULL), который всегда возвращает другой NULL.

Например

SELECT * FROM example_table WHERE id NOT IN (subquery_that_selects_ids)

subquery_that_selects_ids может вернуть набор целых чисел, то есть (1,2,5,6) или пустой набор, если подзапрос не находит подходящих результатов.

COALESCE здесь не работает, так как подзапрос, скорее всего, вернет более одного результата.

Решения должны работать в SQLite или postgresql. Как я могу запретить подзапросу возвращать пустой набор?


Все говорят мне, что запрос должен работать как написано. И вы все правы. Запрос строится AREL Rails3, так как я собирался опубликовать полный запрос здесь, я заметил, что AREL вставляет NULL для пустого набора при использовании условий массива.

т.е. Мой запрос в рельсах выглядел так:

Object.where("id NOT IN (?)", Object.where(other_conditions).select(:id))

когда Object.where(other_conditions) оценивается как [], ? заменяется на NULL

Поэтому я переписываю запрос так:

Object.where("id NOT IN (" + Object.where(other_conditions).select(:id).to_sql + ")")

Проблема решена.

Я отдаю должное @Michael Buen, но также голосую за любого, кто сказал мне, что запрос будет работать как написано, поскольку они верны. Благодаря @OMG Ponies и @Ted Elliott особенно!

Ответы [ 5 ]

5 голосов
/ 20 декабря 2010

Попробуйте:

SELECT * FROM example_table 
WHERE id NOT 
    IN (select x.id from subquery_that_selects_ids as x where x.id is not null)

Я думаю, что вы немного усложняете, NOT IN будет иметь строки, даже если в подзапросе нет строк.Ваш запрос будет работать без изменений.В любом случае, если вы действительно хотите, чтобы ваш подзапрос выдавал строки, даже если условия не были выполнены, используйте UNION

SELECT * FROM example_table 
WHERE id NOT 
    IN (select x.id from subquery_that_selects_ids as x 
        where 1 = 0 -- empty set
        union
        select 0)

UNION в любом случае удаляет дубликаты, UNION ALL сохраняет дубликаты

2 голосов
/ 21 декабря 2010

Я думаю, вы что-то путаете. Отправленный вами запрос работает нормально, если subquery_that_selects_ids возвращает пустой набор (поэтому выбрана каждая строка из example_table) Здесь не задействованы неявные нулевые значения.

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

SELECT * FROM example_table WHERE id = (SELECT id FROM other_table WHERE name = 'foo')
2 голосов
/ 20 декабря 2010

как насчет:

SELECT ex.ID, ex.OtherFields
FROM ExampleTable ex left join (Select ID from SomeOtherTable) o on o.ID = ex.ID
WHERE o.ID is null
0 голосов
/ 07 марта 2014

В многозначном подзапросе возникнут проблемы, если вы используете оператор NOT in AND, если набор, возвращаемый подзапросом, содержит значение NULL.Если подзапрос является пустым набором, это не означает, что он возвратил ноль;)

В случае, если содержит нулевое значение, он вынуждает внешний запрос вернуть один пустой набор, потому что он не может сказать, является лизначение в UNKNOWN или NOT IN Неизвестно.

Вот один пример, использующий таблицу hr.employees .

* SELECT last_name FROM hr.employees WHERE Commission_pct NOT IN (0.1, 0,35); *

Этот запрос вернет 26 строк.

* ВЫБРАТЬ фамилию ОТ hr.employees, ГДЕ комиссия_пункт НЕ ВХОДИТ (0,1,0.35, NULL); *

Этот запрос не возвращает строк, потому что NULL в списке, переданном NOT IN, испортит его.Итак, если ваш подзапрос может вернуть любое нулевое значение, вы должны обработать его с помощью функций (NVL, NVL2, COALESCE) в подзапросе.

Надеюсь, это помогло.

Спасибо

Александр Буфало

0 голосов
/ 20 декабря 2010

Почему бы не сработать?

SELECT *
  FROM example_table
 WHERE id IN (
    SELECT COALESCE(id, 0)
      FROM another_example_table
);
...