Материал: Using_MySql,_MS_SQL_Server_and_Oracle(1)

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Пример 13: запросы на объединение и подзапросы с условием IN

Oracle Исследование 2.2.3.EXP.A

1-- Запрос 1: использование JOIN

2SELECT DISTINCT "s_id",

3

 

"s_name"

4

 

FROM "subscribers"

5JOIN "subscriptions"

6ON "s_id" = "sb_subscriber"

1-- Запрос 2: использование IN (... DISTINCT ...)

2SELECT "s_id",

3"s_name"

4

 

FROM

"subscribers"

 

5

 

WHERE

"s_id" IN (SELECT

DISTINCT "sb_subscriber"

6

 

 

FROM

"subscriptions")

 

 

 

 

 

1-- Запрос 3: использование IN

2SELECT "s_id",

3"s_name"

4

 

FROM

"subscribers"

 

5

 

WHERE

"s_id" IN (SELECT

"sb_subscriber"

6

 

 

FROM

"subscriptions")

1-- Запрос 4: использование LEFT JOIN

2SELECT "s_id",

3"s_name"

4

 

FROM

"subscribers"

 

5

 

 

LEFT JOIN

"subscriptions"

6

 

 

ON

"s_id" =

"sb_subscriber"

7

 

WHERE

"sb_subscriber" IS

NULL

 

 

 

 

 

 

1-- Запрос 5: использование NOT IN (... DISTINCT ...)

2SELECT "s_id",

3"s_name"

4

 

FROM

"subscribers"

 

 

5

 

WHERE

"s_id" NOT IN

(SELECT

DISTINCT "sb_subscriber"

6

 

 

 

FROM

"subscriptions")

 

 

 

 

 

 

1-- Запрос 6: использование NOT IN

2SELECT "s_id",

3"s_name"

 

4

 

FROM

"subscribers"

 

 

 

 

 

 

5

 

WHERE

"s_id" NOT IN (SELECT

"sb_subscriber"

 

 

 

6

 

 

 

FROM

"subscriptions")

 

 

 

 

 

Медианы времени, затраченного на выполнение каждого запроса:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

MySQL

MS SQL Server

Oracle

 

 

JOIN

 

 

91.065

8.574

1.136

 

 

IN (… DISTINCT …)

0.068

6.711

0.298

 

 

IN

 

 

0.039

6.723

0.309

 

 

LEFT JOIN

 

45.788

8.695

0.284

 

 

NOT IN (… DISTINCT …)

45.564

7.437

0.329

 

 

NOT IN

 

46.020

7.384

0.311

 

Перед проведением исследования мы ставили два вопроса, и теперь у нас есть ответы:

Влияет ли на производительность наличие DISTINCT в подзапросе (для решений с IN)?

o В случае с IN наличие DISTINCT ощутимо замедляет работу MySQL и немного ускоряет работу MS SQL Server и Oracle.

o В случае с NOT IN наличие DISTINCT немного ускоряет работу MySQL

инемного замедляет работу MS SQL Server и Oracle.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 90/545

Пример 13: запросы на объединение и подзапросы с условием IN

Что работает быстрее — JOIN или IN (в обоих случаях: когда мы ищем как читателей, бравших книги, так и не бравших)?

o JOIN работает медленнее IN.

oLEFT JOIN работает немного медленнее NOT IN в MySQL и MS SQL Server и немного быстрее NOT IN в Oracle.

Поскольку большинство результатов крайне близки по значениям, однозначный вывод получается только один: IN работает быстрее JOIN, в остальных случаях стоит проводить дополнительные исследования.

Задание 2.2.3.TSK.A: показать список книг, которые когда-либо были взяты читателями.

Задание 2.2.3.TSK.B: показать список книг, которые никто из читателей никогда не брал.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 91/545

Пример 14: нетривиальные случаи использования условия IN и запросов на объединение

2.2.4.Пример 14: нетривиальные случаи использования условия IN и запросов на объединение

Существуют задачи, которые на первый взгляд решаются очень просто. Однако оказывается, что простое и очевидное решение является неверным.

Задача 2.2.4.a{92}: показать список читателей, у которых сейчас на руках нет книг (использовать JOIN).

Задача 2.2.4.b{95}: показать список читателей, у которых сейчас на руках нет книг (не использовать JOIN).

В задачах 2.2.3.* примера 13{82} всё было просто: если в таблице subscriptions есть информация о читателе, значит, он брал книги в библиотеке, а если нет

— не брал. Теперь же нас будут интересовать как читатели, никогда не бравшие книги (объективно у них на руках нет книг), так и читатели, бравшие книги (но ктото вернул всё, что брал, а кто-то ещё что-то читает).

 

Ожидаемый результат 2.2.4.a.

 

 

 

s_id

s_name

 

1

Иванов И.И.

 

2

Петров П.П.

 

 

Ожидаемый результат 2.2.4.b.

 

 

s_id

s_name

 

1

Иванов И.И.

 

2

Петров П.П.

 

Решение 2.2.4.a{92}.

MySQL Решение 2.2.4.a

1SELECT `s_id`,

2`s_name`

3

 

FROM

`subscribers`

 

4

 

 

LEFT OUTER JOIN

`subscriptions`

5

 

 

ON

`s_id` = `sb_subscriber`

6

 

GROUP

BY `s_id`

 

7

 

HAVING

COUNT(IF(`sb_is_active` = 'Y', `sb_is_active`, NULL)) = 0

 

 

 

 

 

MS SQL Решение 2.2.4.a

1SELECT [s_id],

2[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

 

 

 

 

 

 

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 92/545

Пример 14: нетривиальные случаи использования условия IN и запросов на объединение

Oracle Решение 2.2.4.a

1SELECT "s_id",

2"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 и CASE в строках 8-11 запросов для MS SQL Server и Oracle — любое значение поля sb_is_active, отличное от Y, они превращают в NULL.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 93/545

Пример 14: нетривиальные случаи использования условия IN и запросов на объединение

Теперь остаётся проверить результат работы COUNT: если он равен нулю, у читателя на руках нет книг.

Типичной ошибкой при решении задачи 2.2.4.a является попытка получить нужный результат следующим запросом:

MySQL

Решение 2.2.4.a (ошибочный запрос)

1SELECT `s_id`,

2`s_name`

 

3

 

FROM

`subscribers`

 

4

 

 

 

LEFT OUTER JOIN `subscriptions`

 

5

 

 

 

ON `s_id` = `sb_subscriber`

 

6

 

WHERE

`sb_is_active` = 'Y'

 

7

 

 

 

OR `sb_is_active` IS NULL

 

8

 

GROUP

BY `s_id`

 

9

 

HAVING COUNT(`sb_is_active`) = 0

 

 

 

Решение 2.2.4.a (ошибочный запрос)

 

MS SQL

 

1SELECT [s_id],

2[s_name]

 

3

 

FROM

[subscribers]

 

4

 

 

 

LEFT OUTER JOIN [subscriptions]

 

5

 

 

 

ON [s_id] = [sb_subscriber]

 

6

 

WHERE

[sb_is_active] = 'Y'

 

7

 

 

 

OR [sb_is_active] IS NULL

 

8

 

GROUP

BY [s_id], [s_name], [sb_is_active]

 

9

 

HAVING

COUNT([sb_is_active]) = 0

 

 

 

Решение 2.2.4.a (ошибочный запрос)

 

Oracle

 

1SELECT "s_id",

2"s_name"

3

 

FROM "subscribers"

 

4

 

LEFT OUTER JOIN

"subscriptions"

5

 

ON

"s_id" = "sb_subscriber"

6WHERE "sb_is_active" = 'Y'

7OR "sb_is_active" IS NULL

 

8

 

GROUP

BY "s_id", "s_name", "sb_is_active"

 

9

 

HAVING

COUNT("sb_is_active") = 0

 

 

 

 

Здесь получается такой неверный набор данных:

 

 

 

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 Стр: 94/545

Источник: https://studfile.net/preview/16418462/