НЕ НУЛЯЕТСЯ и НЕ ЗНАЕТ (str, NULL) в предложении WHERE - PullRequest
3 голосов
/ 14 сентября 2011

У меня есть три таблицы (здесь упрощенно):

recipients: recipientId, isGroup
users: userId, first name, last name
groups: groupid, groupname

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

Так вот, что я сделал:

select u.first_name, u.last_name, g.groupname, r.isGroup
from recipients r
left join users u on u.userid = r.recipientId
left join groups g on g.groupid = r.recipientId
where r.isGroup IS NULL or g.groupname IS NOT NULL

Приведенный выше запрос не возвращает ожидаемых результатов.Я получаю это обратно:

adam, smith, null, null
yolanda, smith, null, null
null, null, members, 1
null, null, null, 1

Последняя строка неожиданна, поскольку явно нет имени группы (g.groupname имеет значение NULL) и r.IsGroup = 1.

Когда ясделать это:

select u.first_name, u.last_name, g.groupname, r.isGroup
from recipients r
left join users u on u.userid = r.recipientId
left join groups g on g.groupid = r.recipientId
where r.isGroup IS NULL

Я получаю ожидаемые результаты:

adam, smith, null, null
yolanda, smith, null, null

И когда я делаю это:

select u.first_name, u.last_name, g.groupname, r.isGroup
from recipients r
left join users u on u.userid = r.recipientId
left join groups g on g.groupid = r.recipientId
where g.groupname IS NOT NULL

Я получаю ожидаемые результаты:

null, null, members, 1

Только когда я объединяю два предложения where с OR, я получаю дополнительную строку.

Теперь, когда я изменяю свой запрос на (изменить IS NULL на ISNULL):

select u.first_name, u.last_name, g.groupname, r.isGroup
from recipients r
left join users u on u.userid = r.recipientId
left join groups g on g.groupid = r.recipientId
where r.isGroup IS NULL or ISNULL(g.groupname, null) IS NOT NULL

Я получаю ожидаемые результаты:

adam, smith, null, null
yolanda, smith, null, null
null, null, members, 1

На самом деле, мне даже не нужно менять предложение where, следующий запрос также работает так же хорошо и дает мне ожидаемыйрезультат показан выше:

select u.first_name, u.last_name, ISNULL(g.groupname,null), r.isGroup
from recipients r
left join users u on u.userid = r.recipientId
left join groups g on g.groupid = r.recipientId
where r.isGroup IS NULL or g.groupname IS NOT NULL

ТАК, вопрос, ПОЧЕМУ? Почему размещение ISNULL в моем операторе SELECT меняет работу предложения WHERE? Почему это вообще меняет дело? Почему мой первый запрос не работает? Почему он не функционирует, только когда я добавляю ИЛИ - почему он тоже не сломается?

Заранее спасибо.

Я использую MS SQL Server 2008.

правки: исправлена ​​опечатка, уточнен вопрос

Ответы [ 5 ]

4 голосов
/ 22 сентября 2011

Мы обнаружили, что это проблема в Sql Server 2008 без установленных пакетов обновления.Попробуйте установить SP1 или SP2.В нашем случае пакет обновления решил проблему.

2 голосов
/ 14 сентября 2011

Я полагаю, что вы пытаетесь сделать это, чтобы получить всех пользователей и группы, где, если это пользователь first_name и last_name будут чем-то, а groupname будет NULL, но если это группа, first_name и last_name будут NULL и groupname будет что-то Вместо этого ваше предложение WHERE фильтрует результаты, а не определяет условия объединения ваших данных. Я думаю, что это получит то, что вы ищете (если r.isGroup == 1 означает, что это группа):

Чтобы более или менее использовать исходный запрос, но исключить записи, которые не существуют как группа или пользователь:

select u.first_name, u.last_name, g.groupname, r.isGroup
from recipients r
left join users u 
    on u.userid = r.recipientId and r.isGroup != 1
left join groups g 
    on g.groupid = r.recipientId and r.isGroup == 1
where u.userid IS NOT NULL or g.groupid IS NOT NULL

Однако я думаю, что объединение с внутренними объединениями будет работать лучше:

select u.first_name, u.last_name, NULL, r.isGroup
from recipients r
inner join users u on u.userid = r.recipientId
where r.isGroup != 1
union
select NULL, NULL, g.groupname, r.isGroup
from recipients r
inner join groups g on g.groupid = r.recipientId
where r.isGroup == 1
2 голосов
/ 14 сентября 2011

ISNULL - это функция, которая перенастраивает указанное входное значение, если столбец равен нулю, иначе значение столбца.

ISNULL(tbl.x, 'y') --returns 'y' if tbl.x is null otherwise the value of tbl.x
0 голосов
/ 15 сентября 2011

Похоже, что вы получите желаемый результат, хотя, если есть какие-то ошибки от NULLS, которые по-швейцарски проверяют ваши данные, это может не сработать:

select u.first_name, u.last_name, g.groupname, r.isGroup
from #recipients r
left join #users u on u.userid = r.recipientId
left join #groups g on g.groupid = r.recipientId
WHERE  g.groupname IS NOT NULL 
    OR ISNULL(r.IsGroup,0) > CASE WHEN g.groupid IS NOT NULL AND g.groupname IS NULL THEN -1 ELSE 0 END
0 голосов
/ 14 сентября 2011

Из предложения SELECT:

u.groupname

из предложения WHERE:

g.groupname

Сделайте эти два совпадения и дайте знать, если вы видите что-то другое.

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