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

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

Пример 11: запросы на объединение как способ получения человекочитаемых данных

Oracle Решение 2.2.1.b

1SELECT "b_name",

2"s_id",

3"s_name",

4"sb_start",

5"sb_finish"

6 FROM "books"

7JOIN "subscriptions"

8ON "b_id" = "sb_book"

9JOIN "subscribers"

10ON "sb_subscriber" = "s_id"

Логика решения 2.2.1.b{69} полностью эквивалентна логике решения 2.2.1.a{67} (здесь приходится объединять даже меньше таблиц — всего три, а не пять). Обратите внимание на тот факт, что если объединение происходит не по одноимённым полям, а по разноимённым, в MySQL и Oracle тоже приходится использовать конструкцию ON вместо USING.

Задание 2.2.1.TSK.A: показать список книг, у которых более одного автора.

Задание 2.2.1.TSK.B: показать список книг, относящихся ровно к одному жанру.

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

Пример 12: запросы на объединение и преобразование столбцов в строки

2.2.2.Пример 12: запросы на объединение и преобразование столбцов в строки

Возможно, вы заметили, что в решении{67} задачи 2.2.1.a{66} есть неудобство: если у книги несколько авторов и/или жанров, информация начинает дублироваться (упорядочим для наглядности выборку по полю b_name):

b_name

a_name

g_name

Евгений Онегин

А.С. Пушкин

Классика

Евгений Онегин

А.С. Пушкин

Поэзия

Искусство программирования

Д. Кнут

Классика

Искусство программирования

Д. Кнут

Программирование

Курс теоретической физики

Л.Д. Ландау

Классика

Курс теоретической физики

Е.М. Лифшиц

Классика

Основание и империя

А. Азимов

Фантастика

Психология программирования

Д. Карнеги

Программирование

Психология программирования

Б. Страуструп

Программирование

Психология программирования

Д. Карнеги

Психология

Психология программирования

Б. Страуструп

Психология

Сказка о рыбаке и рыбке

А.С. Пушкин

Классика

Сказка о рыбаке и рыбке

А.С. Пушкин

Поэзия

Язык программирования С++

Б. Страуструп

Программирование

Пользователи же куда больше привыкли к следующему представлению дан-

ных:

Книга

Автор(ы)

Жанр(ы)

Евгений Онегин

А.С. Пушкин

Классика, Поэзия

Искусство программирования

Д. Кнут

Классика,

 

 

Программирование

Курс теоретической физики

Е.М. Лифшиц,

Классика

 

Л.Д. Ландау

 

Основание и империя

А. Азимов

Фантастика

Психология программирования

Б. Страуструп,

Программирование,

 

Д. Карнеги

Психология

Сказка о рыбаке и рыбке

А.С. Пушкин

Классика, Поэзия

Язык программирования С++

Б. Страуструп

Программирование

Задача 2.2.2.a{72}: показать все книги с их авторами (дублирование названий книг не допускается).

Задача 2.2.2.b{76}: показать все книги с их авторами и жанрами (дублирование названий книг и имён авторов не допускается).

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

Пример 12: запросы на объединение и преобразование столбцов в строки

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

book

author(s)

 

 

Евгений Онегин

А.С. Пушкин

 

 

Искусство программирования

Д. Кнут

 

 

Курс теоретической физики

Е.М. Лифшиц, Л.Д. Ландау

 

Основание и империя

А. Азимов

 

 

Психология программирования

Б. Страуструп, Д. Карнеги

 

Сказка о рыбаке и рыбке

А.С. Пушкин

 

 

Язык программирования С++

Б. Страуструп

 

 

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

 

 

 

 

 

 

book

author(s)

 

genre(s)

Евгений Онегин

А.С. Пушкин

Классика, Поэзия

Искусство программирования

Д. Кнут

Классика,

 

 

Программирование

Курс теоретической физики

Е.М. Лифшиц,

Классика

 

Л.Д. Ландау

 

 

Основание и империя

А. Азимов

Фантастика

Психология программирования

Б. Страуструп,

Программирование,

 

Д. Карнеги

Психология

Сказка о рыбаке и рыбке

А.С. Пушкин

Классика, Поэзия

Язык программирования С++

Б. Страуструп

Программирование

Решение 2.2.2.a{71}.

MySQL Решение 2.2.2.a

1SELECT `b_name`

2AS `book`,

3GROUP_CONCAT(`a_name` ORDER BY `a_name` SEPARATOR ', ')

4AS `author(s)`

5 FROM `books`

6JOIN `m2m_books_authors` USING(`b_id`)

7JOIN `authors` USING(`a_id`)

8

 

GROUP

BY

`b_id`

9

 

ORDER

BY

`b_name`

Решение для MySQL получается очень простым и элегантным потому, что эта СУБД поддерживает функцию GROUP_CONCAT, которая и выполняет всю основную работу. У этой функции очень развитый синтаксис (даже в нашем случае мы используем сортировку и указание разделителя), с которым обязательно стоит ознакомиться в официальной документации.

Обратите особое внимание на строку 8 запроса: ни в коем случае не стоит выполнять группировку по названию книги! Такая ошибка приводит к тому, что СУБД считает одной и той же книгой несколько разных книг с одинаковым названием (что в реальной жизни может встречаться очень часто). Группировка же по значению первичного ключа таблицы гарантирует, что никакие разные записи не будут смешаны в одну группу.

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

Пример 12: запросы на объединение и преобразование столбцов в строки

И ещё одна особенность MySQL заслуживает внимания: в строке 1 мы извлекаем поле b_name, которое не упомянуто в выражении GROUP BY в строке 8 и не является агрегирующей функцией. MS SQL Server и Oracle не позволяют поступать подобным образом и строго требуют, чтобы любое поле из конструкции SELECT, не являющееся агрегирующей функций, было явно упомянуто в выражении GROUP BY.

Итак, что делает GROUP_CONCAT? Фактически, «разворачивает часть столбца в строку» (одновременно упорядочивая авторов по алфавиту и разделяя их набором символов «, »):

b_name

a_name

 

author(s)

Евгений Онегин

А.С. Пушкин

А.С. Пушкин

Искусство программирования

Д. Кнут

Д. Кнут

Курс теоретической физики

Л.Д. Ландау

Е.М. Лифшиц, Л.Д. Ландау

Е.М. Лифшиц

Основание и империя

А. Азимов

А. Азимов

Психология программирования

Д. Карнеги

Б. Страуструп, Д. Карнеги

Б. Страуструп

Сказка о рыбаке и рыбке

А.С. Пушкин

А.С. Пушкин

Язык программирования С++

Б. Страуструп

Б. Страуструп

MS SQL Server не поддерживает функцию GROUP_CONCAT, а потому решение для него весьма нетривиально:

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

1WITH [prepared_data]

2AS (SELECT [books].[b_id],

3

 

 

[b_name],

4

 

 

[a_name]

5

 

FROM

[books]

6

 

 

JOIN

[m2m_books_authors]

7

 

 

ON

[books].[b_id] = [m2m_books_authors].[b_id]

8

 

 

JOIN

[authors]

9

 

 

ON

[m2m_books_authors].[a_id] = [authors].[a_id]

10)

11SELECT [outer].[b_name]

12AS [book],

13STUFF ((SELECT ', ' + [inner].[a_name]

14

 

 

FROM

[prepared_data] AS [inner]

15

 

 

WHERE

[outer].[b_id] = [inner].[b_id]

16

 

 

ORDER

BY [inner].[a_name]

17

 

 

FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'),

18

 

 

1, 2, '')

19

 

 

AS [author(s)]

 

20

 

FROM

[prepared_data] AS [outer]

21GROUP BY [outer].[b_id],

22[outer].[b_name]

Начнём рассмотрение со строк 1-10. В них представлено т.н. CTE (Common Table Expression, общее табличное выражение). Очень упрощённо общее табличное выражение можно считать отдельным поименованным запросом, к результату выполнения которого можно обращаться как к таблице. Это особенно удобно, когда таких обращений в дальнейшем используется несколько (без общего табличного выражения с использованием классического подзапроса, тело такого подзапроса пришлось бы писать везде, где необходимо к нему обратиться).

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

Пример 12: запросы на объединение и преобразование столбцов в строки

В нашем случае общее табличное выражение возвращает такие данные:

b_id

b_name

a_name

1

Евгений Онегин

А.С. Пушкин

2

Сказка о рыбаке и рыбке

А.С. Пушкин

3

Основание и империя

А. Азимов

4

Психология программирования

Д. Карнеги

4

Психология программирования

Б. Страуструп

5

Язык программирования С++

Б. Страуструп

6

Курс теоретической физики

Л.Д. Ландау

6

Курс теоретической физики

Е.М. Лифшиц

7

Искусство программирования

Д. Кнут

Это — уже почти готовое решение, останется только «развернуть в строку» части столбца a_name с авторами одной и той же книги. Эту задачу выполнят строки 13-19 запроса.

Основной рабочей частью процесса является код коррелирующего подза-

проса:

SELECT ', ' + [inner].[a_name]

FROM [prepared_data] AS [inner]

WHERE [outer].[b_id] = [inner].[b_id]

ORDER BY [inner].[a_name]

Для каждой строки результата, полученного из общего табличного выражения, выполняется подзапрос, возвращающий данные из этого же результата, относящиеся к рассматриваемой на внешнем уровне строке. Более простой вариант коррелирующего подзапроса мы уже рассматривали{49}, а теперь покажем, как работает СУБД в данном конкретном случае:

Строка из внешней

 

Какие строки бу-

Какие данные будут собраны

части запроса

 

дут обработаны

 

(b_id)

 

внутренней ча-

 

 

 

стью запроса

 

 

 

(b_id)

 

1

1

 

, А.С. Пушкин

2

2

 

, А.С. Пушкин

3

3

 

, А. Азимов

4

4 и 4

, Б. Страуструп, Д. Карнеги

4

4 и 4

, Б. Страуструп, Д. Карнеги

5

5

 

, Б. Страуструп

6

6

и 6

, Е.М. Лифшиц, Л.Д. Ландау

6

6

и 6

, Е.М. Лифшиц, Л.Д. Ландау

7

7

 

, Д. Кнут

Символы «, » (запятая и пробел), стоящие в начале каждого значения в столбце «Какие данные будут собраны» — не опечатка. Мы явно говорим СУБД извлекать именно текст в виде «, » + имя_автора. Чтобы в конечном результате этих символов не было, мы используем функцию STUFF.

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

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