Пример 14: нетривиальные случаи использования условия IN и запросов на объединение
Oracle |
Решение 2.2.4.a |
|
1 |
SELECT |
|
2 |
|
" s_id" , "s name" |
3 |
FROM |
"subscribers" |
4 |
|
LEFT OUTER JOIN "subscriptions" |
5 |
|
ON "s id" = "sb subscriber" |
6 |
GROUP |
BY "s id", |
7 |
|
"s name" |
8 |
HAVING COUNT(CASE |
|
9 |
|
WHEN "sb_is_active" = 'Y' THEN "sb_is_active" |
10 |
|
ELSE NULL |
11 |
|
END) = 0 |
|
|
|
Почему получается такое нетривиальное решение? Строки 1-5 запросов 2.2.4. a возвращают следующие данные (добавим поле sb_is_active для наглядности):
s id |
s name |
sb is active |
1 |
Иванов И.И. |
N |
1 |
Иванов И.И. |
N |
1 |
Иванов И.И. |
N |
1 |
Иванов И.И. |
N |
1 |
Иванов И.И. |
N |
2 |
Петров П.П. |
NULL |
3 |
Сидоров С.С. |
Y |
3 |
Сидоров С.С. |
Y |
3 |
Сидоров С.С. |
Y |
4 |
Сидоров С.С. |
N |
4 |
Сидоров С.С. |
Y |
4 |
Сидоров С.С. |
Y |
Признаком того, что читатель вернул все книги, является отсутствие (COUNT (...) = 0) у него записей со значением sb_is_active = 'Y'. Проблема в том, что мы не можем «заставить» COUNT считать только значения Y — он будет учитывать любые значения, не равные NULL. Отсюда легко следует вывод, что нам осталось превратить в NULL любые значения поля sb_is_active, не равные Y, т.е. получить такой результат:
s id |
s name |
sb is active |
1 |
Иванов И.И. |
NULL |
1 |
Иванов И.И. |
NULL |
1 |
Иванов И.И. |
NULL |
1 |
Иванов И.И. |
NULL |
1 |
Иванов И.И. |
NULL |
2 |
Петров П.П. |
NULL |
3 |
Сидоров С.С. |
Y |
3 |
Сидоров С.С. |
Y |
3 |
Сидоров С.С. |
Y |
4 |
Сидоров С.С. |
NULL |
4 |
Сидоров С.С. |
Y |
4 |
Сидоров С.С. |
Y |
Именно за это действие отвечают выражения IF в строке 7 запроса для
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 100/545
Пример 14: нетривиальные случаи использования условия IN и запросов на объединение
MySQL и CASE в строках 8-11 запросов для MS SQL Server и Oracle — любое значение поля sb_is_active, отличное от Y, они превращают в NULL.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 101/545
Пример 14: нетривиальные случаи использования условия IN и запросов на объединение
Теперь остаётся проверить результат работы COUNT: если он равен нулю, у читателя на руках нет книг.
Типичной ошибкой при решении задачи 2.2.4.а является попытка полу- XLV чить нужный результат следующим запросом:
|
Здесь получается такой неверный набор данных: |
|
|
|
|
s_id |
s_name |
|
2 |
Петров П.П. |
|
Это решение учитывает никогда не бравших книги читателей (sb_is_active IS NULL), а также тех, у кого есть на руках хотя бы одна книга (sb_is_active = 'Y'), но те, кто вернул все книги, под это условие не подходят:
s_id |
s_name |
sb_is_active |
|
1 |
Иванов И.И. |
N |
|
1 |
Иванов И.И. |
N |
Эти записи не удовлетворяют |
1 |
Иванов И.И. |
N |
условию WHERE и будут |
1 |
Иванов И.И. |
N |
пропущены. |
1 |
Иванов И.И. |
N |
|
2 |
Петров П.П. |
NULL |
|
3 |
Сидоров С.С. |
Y |
|
3 |
Сидоров С.С. |
Y |
|
3 |
Сидоров С.С. |
Y |
|
4 |
Сидоров С.С. |
N |
|
4 |
Сидоров С.С. |
Y |
|
4 |
Сидоров С.С. |
Y |
|
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 102/545
Пример 14: нетривиальные случаи использования условия IN и запросов на объединение
Таким образом, Иванов И.И. оказывается пропущенным. Поэтому нужно использовать решение, представленное в начале рассмотрения задачи 2.2.4. а (т.е. решение с преобразованием значения поля sb_is_active).
'Vf Решение 2.2.4.b{92}.
Типичной ошибкой при решении задачи 2.2.4. b является попытка получить нужный результат следующим запросом:
|
MySQL |
|
Решение 2.2.4.b (ошибочный запрос) |
|
|||||
|
1 |
|
SELECT |
|
's id', |
|
|
||
|
2 |
|
|
|
|
's name' |
|
|
|
|
|
|
|
|
|
|
|||
|
3 |
|
FROM |
|
|
'subscribers' |
|
|
|
|
4 |
|
WHERE |
|
's id' IN (SELECT |
DISTINCT 'sb subscriber' |
|||
|
5 |
|
|
|
|
|
FROM |
'subscriptions' |
|
|
6 |
|
|
|
|
|
WHERE |
'sb is active' = 'N') |
|
|
MS SQL I |
Решение 2.2.4.b (ошибочный запрос) |
| |
||||||
|
1 |
|
SELECT |
|
[s id], |
|
|
||
|
2 |
|
|
|
|
[s name] |
|
|
|
|
|
|
|
|
|
|
|||
|
3 |
|
FROM |
|
|
[subscribers] |
|
|
|
|
4 |
|
WHERE |
|
[s id] IN (SELECT |
DISTINCT [sb subscriber] |
|||
|
5 |
|
|
|
|
|
FROM |
[ subscriptions] |
|
|
6 |
|
|
|
|
|
WHERE |
[sb is active] = 'N') |
|
|
Oracle |
|
Решение 2.2.4.b (ошибочный запрос) |
|
|||||
|
1 |
|
SELECT |
"s id", |
|
|
|||
|
2 |
|
|
|
"s name" |
|
|
||
|
3 |
|
FROM |
|
"subscribers" |
|
|
||
|
4 |
|
WHERE |
"s id" IN (SELECT |
DISTINCT "sb subscriber" |
||||
|
5 |
|
|
|
|
|
FROM |
"subscriptions" |
|
|
6 |
|
|
|
|
|
WHERE |
"sb is active" = 'N') |
|
|
|
|
Получается такой набор данных: |
|
|||||
|
|
|
|
|
|
|
|
|
|
s_id |
s_name |
|
|
|
|||||
1 |
|
Иванов И.И. |
|
|
|
||||
4 |
|
Сидоров С.С. |
|
|
|
||||
Но это — решение задачи «показать читателей, которые хотя бы раз вернули
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 103/545
Пример 14: нетривиальные случаи использования условия IN и запросов на объединение
книгу». Данная проблема (характерная для многих подобных ситуаций) лежит не столько в области правильности составления запросов, сколько в области понимания смысла (семантики) модели базы данных.
Если по некоторому факту выдачи книги отмечено, что она возвращена (в поле sb_is_active стоит значение N), это совершенно не означает, что рядом нет другого факта выдачи тому же читателю книги, которую он ещё не вернул. Рассмотрим это на примере читателя с идентификатором 4 («Сидоров С.С.»):
sb_id |
sb_subscriber |
sb_book |
sb_start |
sb_finish |
sb_is_active |
|
57...... |
4 |
5 |
2012-06-1Ї |
N |
||
2012-08-11 - |
||||||
|
||||||
91-" |
4 |
1 |
2015-10-07 |
-2015-03-07 - |
Y |
|
4 |
|
2015-10-08 |
2025-11-08 |
Y |
||
99 ....... |
4 |
|||||
|
Он вернул одну книгу, и потому подзапрос вернёт его идентификатор, но ещё две книги он не вернул, и потому по условию исходной задачи он не должен оказаться в списке.
Также очевидно, что читатели, никогда не бравшие книг, не попадут в список людей, у которых на руках нет книг (идентификаторы таких читателей вообще ни разу не встречаются в таблице subscriptions).
Задание 2.2.4.TSK.A: показать список книг, ни один экземпляр которых сейчас не находится на руках у читателей.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 104/545