Пример 20: все разновидности запросов на объединение в трёх СУБД
Для демонстрации конкретных примеров создадим в БД «Исследование» таблицы rooms и computers, связанные связью «один ко многим»:
dm MySQL |
|
|
|
SQLServer2012 |
|
dm Oracle |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rooms |
«column» |
|
|
«column» |
|
«column» |
|||
*PK r_id: INT |
|
|
*PK r_id: int |
|
*PK r_id: NUMBER(10) |
|||
* |
r_name: VARCHAR(50) |
|
* |
r_name: nvarchar(50) |
* |
r_name: NVARCHAR2(50) |
||
* |
r_space: TINYINT |
|
* |
r_space: tinyint |
* |
r_space: NUMBER(3) |
||
«PK» |
|
|
|
«PK» |
|
«PK» |
||
+ PK_rooms(INT) |
|
+ PK_rooms(int) |
|
+ PK_rooms(NUMBER) |
||||
|
|
|
|
+PK_rooms^ 1 |
|
|
|
|
+PK_rooms |
1 |
|
|
|
|
+ PK_rooms |
||
|
|
|
|
|
|
|
||
|
|
|
|
|
(c_room = r_id) |
|
|
|
|
(c_room = r_id) |
|
|
|
|
|
(c_room = r_id) |
|
|
«FK» |
|
|
|
«FK» |
|
|
«FK» |
|
^0..* |
|
|
|
^.Л |
|
|
|
|
|
+FK_computers_rooms |
|
+FK_computers_rooms |
Q * +FK_computers_rooms |
|||
computers |
computers |
|
|
|
||||
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
computers |
«column» |
|
|
|
«column» |
|
|
«column» |
|
*PK c_id: INT |
|
|
*PK c_id: int |
|
*PK c_id: NUMBER(10) |
|||
FK c_room : INT |
|
|
FK c_room: int |
|
FK c_room: NUMBER(10) |
|||
* c_name: VARCHAR(50) |
|
* c_name: nvarchar(50) |
|
* c_name: NVARCHAR2(50) |
||||
«FK» |
|
|
|
«FK» |
|
|
«FK» |
|
+ FK_computers_rooms(INT) |
|
+ FK_computers_rooms(int) |
|
+ FK_computers_rooms(NUMBER) |
||||
«PK» |
|
|
|
«PK» |
|
|
«PK» |
|
+ PK_computers(INT) |
|
+ PK_computers(int) |
|
+ PK_computers(NUMBER) |
||||
|
MySQL |
|
MS SQL Server |
Oracle |
||||
|
Рисунок 2.2.a — Таблицы rooms и computers в трёх СУБД |
|||||||
Поместим в таблицу rooms следующие данные: |
|
|||||||
r_id |
|
|
r_name |
|
r_space |
|
||
1 |
Комната с двумя компьютерами |
5 |
|
|
||||
2 |
Комната с тремя компьютерами |
5 |
|
|
||||
3 |
Пустая комната 1 |
|
|
2 |
|
|
||
4 |
Пустая комната 2 |
|
|
2 |
|
|
||
5 |
Пустая комната 3 |
|
|
2 |
|
|
||
Поместим в таблицу computers следующие данные: |
|
|||||||
|
|
|
|
|
|
|
||
c_id |
c_room |
|
c_name |
|
|
|
||
1 |
1 |
|
Компьютер A в комнате 1 |
|
|
|||
2 |
1 |
|
Компьютер B в комнате 1 |
|
|
|||
3 |
2 |
|
Компьютер A в комнате 2 |
|
|
|||
4 |
2 |
|
Компьютер B в комнате 2 |
|
|
|||
5 |
2 |
|
Компьютер C в комнате 2 |
|
|
|||
6 |
NULL |
Свободный компьютер A |
|
|
||||
7 |
NULL |
Свободный компьютер B |
|
|
||||
8 |
NULL |
Свободный компьютер C |
|
|
||||
Сразу отметим, что слова INNER и OUTER в подавляющем большинстве слу-
чаев являются т.н. «синтаксическим сахаром» (т.е. добавлены для удобства человека, при этом никак не влияя на выполнения запроса) и потому являются необязательными: «просто JOIN» всегда внутренний, а LEFT JOIN, RIGHT JOIN и FULL
JOIN всегда внешние.
В этом примере очень много задач, и в них легко запутаться, потому сначала мы перечислим их все, а затем разместим условия, ожидаемые результаты и решения вместе.
Задачи на «классическое объединение»:
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 160/545
Пример 20: все разновидности запросов на объединение в трёх СУБД
•2.2.10.a{152}: показать информацию о том, как компьютеры распределены по комнатам;
•2.2.10.b{153}: показать все комнаты с поставленными в них компьютерами;
•2.2.10.c{154}: показать все пустые комнаты;
•2.2.10.d{155}: показать все компьютеры с информацией о том, в каких они
расположены комнатах;
•2.2.10.e{156}: показать все свободные компьютеры;
•2.2.10.f{158}: показать всю информацию о том, как компьютеры разме-
щены по комнатам (включая пустые комнаты и свободные компьютеры);
•2.2.10.g{160}: показать информацию по всем пустым комнатам и свободным компьютерам;
•2.2.10.h{162}: показать возможные варианты расстановки компьютеров по комнатам (не учитывать вместимость комнат);
•2.2.10.i{164}: показать возможные варианты перестановки компьютеров по комнатам (компьютер не должен оказаться в той комнате, в которой он сейчас стоит, не учитывать вместимость комнат).
Задачи на «неклассическое объединение»:
•2.2.10.j{166}: показать возможные варианты расстановки компьютеров по комнатам (учитывать вместимость комнат);
•2.2.10.k{168}: показать возможные варианты расстановки свободных компьютеров по пустым комнатам (не учитывать вместимость комнат);
•2.2.10.l{170}: показать возможные варианты расстановки свободных компьютеров по пустым комнатам (учитывать вместимость комнат);
•2.2.10.m{173}: показать возможные варианты расстановки свободных компьютеров по комнатам (учитывать остаточную вместимость комнат);
•2.2.10.n{175}: показать расстановку компьютеров по непустым комнатам так, чтобы в выборку не попало больше компьютеров, чем может поместиться в комнату;
•2.2.10.o{179}: показать расстановку компьютеров по всем комнатам так, чтобы в выборку не попало больше компьютеров, чем может поместиться в комнату.
Задачи на «классическое объединение» предполагают решение на основе прямого использования предоставляемого СУБД синтаксиса (без подзапросов и прочих ухищрений).
Задачи на «неклассическое объединение» предполагают решение на основе либо специфичного для той или иной СУБД синтаксиса, либо дополнительных действий (как правило — подзапросов).
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 161/545
Пример 20: все разновидности запросов на объединение в трёх СУБД
Задача 2.2.10.a: показать информацию о том, как компьютеры распределены по комнатам.
Ожидаемый результат 2.2.10.a.
r_id |
r_name |
c_id |
c_room |
c_name |
1 |
Комната с двумя компьютерами |
1 |
1 |
Компьютер A в комнате 1 |
1 |
Комната с двумя компьютерами |
2 |
1 |
Компьютер B в комнате 1 |
2 |
Комната с тремя компьютерами |
3 |
2 |
Компьютер A в комнате 2 |
2 |
Комната с тремя компьютерами |
4 |
2 |
Компьютер B в комнате 2 |
2 |
Комната с тремя компьютерами |
5 |
2 |
Компьютер C в комнате 2 |
Решение 2.2.10.a: используем внутреннее объединение.
Решение 2.2.10.a
1SELECT 'r_id' ,
2' r_name' ,
3' c_id' ,
4'c room',
5'c name'
6 FROM 'rooms'
7JOIN 'computers'
8ON 'r id' = 'c room
MS SQL і Решение 2.2.10.a
1SELECT [r id],
2[r name],
3[c id],
4[c room] ,
5[c name]
6 |
|
FROM |
[rooms] |
7 |
|
|
JOIN [computers] |
8 |
|
|
ON [r id] = [c room] |
|
Oracl |
|
|
e |
|
і Решение 2.2.10.a | |
|
1SELECT "r id",
2"r name"
3"c id",
4"c room"
5"c name"
6 |
FROM |
"rooms" |
|
7 |
|
JOIN "computers" |
|
8 |
|
ON "r |
id" = "c room" |
Логика внутреннего объединения состоит в том, чтобы подобрать из двух таблиц пары записей, у которых совпадает значение поля, по которому происходит объединение. Для наглядности ещё раз рассмотрим ожидаемый результат и поместим рядом поля, по которым происходит объединение:
r_name |
r_id |
c_room |
c_id |
c_name |
Комната с двумя компьютерами |
1 |
1 |
1 |
Компьютер A в комнате 1 |
Комната с двумя компьютерами |
1 |
1 |
2 |
Компьютер B в комнате 1 |
Комната с тремя компьютерами |
2 |
2 |
3 |
Компьютер A в комнате 2 |
Комната с тремя компьютерами |
2 |
2 |
4 |
Компьютер B в комнате 2 |
Комната с тремя компьютерами |
2 |
2 |
5 |
Компьютер C в комнате 2 |
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 162/545
Пример 20: все разновидности запросов на объединение в трёх СУБД
Задача 2.2.10.b: показать все комнаты с поставленными в них компьютерами.
Ожидаемый результат 2.2.10.b.
r_id |
r_name |
c_id |
c_room |
c_name |
1 |
Комната с двумя компьютерами |
1 |
1 |
Компьютер A в комнате 1 |
1 |
Комната с двумя компьютерами |
2 |
1 |
Компьютер B в комнате 1 |
2 |
Комната с тремя компьютерами |
3 |
2 |
Компьютер A в комнате 2 |
2 |
Комната с тремя компьютерами |
4 |
2 |
Компьютер B в комнате 2 |
2 |
Комната с тремя компьютерами |
5 |
2 |
Компьютер C в комнате 2 |
3 |
Пустая комната 1 |
NULL |
NULL |
NULL |
4 |
Пустая комната 2 |
NULL |
NULL |
NULL |
5 |
Пустая комната 3 |
NULL |
NULL |
NULL |
Решение 2.2.10.b: используем левое внешнее объединение. В этом решении нужно показать все записи из таблицы rooms — как те, для которых есть соответствие в таблице computers, так и те, для которых такого соответствия нет.
MySQL і Решение 2.2.10.b
1 |
SELECT |
|
|
2 |
|
|
|
3 |
|
'r_id', 'r_name', 'c_id', 'c_room', 'c_name' 'rooms' LEFT JOIN |
|
4 |
|
||
|
'computers' |
||
5 |
|
||
|
ON 'r id' = 'c room' |
||
6 |
FROM |
||
|
|||
7 |
|
|
|
8 |
|
|
MS SQL і Решение 2.2.10.b |
1SELECT [r_id],
2[r_name]
3[c_id],
4[c_room]
5[c_name]
6FROM [rooms]
|
LEFT JOIN |
[computers] |
8 |
ON |
[r id] = [c room] |
|
|
|
Oracle I |
Решение 2.2.10.b |
| |
1SELECT "r_id",
2"r_name"
3"c_id",
4"c_room"
5"c_name"
6FROM "rooms"
|
LEFT JOIN "computers" |
8 |
ON "r id" = "c room" |
В случае левого внешнего объединения СУБД извлекает все записи из левой таблицы и пытается найти им пару из правой таблицы. Если пары не находится, соответствующая часть записи в итоговой таблице заполняется NULL-значениями.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 163/545
Пример 20: все разновидности запросов на объединение в трёх СУБД
r_name |
r_id |
c_room |
c_id |
c_name |
Комната с двумя компьютерами |
1 |
1 |
1 |
Компьютер A в комнате 1 |
Комната с двумя компьютерами |
1 |
1 |
2 |
Компьютер B в комнате 1 |
Комната с тремя компьютерами |
2 |
2 |
3 |
Компьютер A в комнате 2 |
Комната с тремя компьютерами |
2 |
2 |
4 |
Компьютер B в комнате 2 |
Комната с тремя компьютерами |
2 |
2 |
5 |
Компьютер C в комнате 2 |
Пустая комната 1 |
3 |
NULL |
NULL |
NULL |
Пустая комната 2 |
4 |
NULL |
NULL |
NULL |
Пустая комната 3 |
5 |
NULL |
NULL |
NULL |
Модифицируем ожидаемый результат так, чтобы эта идея была более наглядной:
Ожидаемый результат 2.2.10.С.
r id |
r_name |
c_id |
c_room |
c_name |
3 |
Пустая комната 1 |
NULL |
NULL |
NULL |
4 |
Пустая комната 2 |
NULL |
NULL |
NULL |
5 |
Пустая комната 3 |
NULL |
NULL |
NULL |
Решение 2.2.10.С: используем левое внешнее объединение с исключением, т.е. выберем только те записи из таблицы rooms, для которых нет соответствия в таблице computers.
Задача 2.2.10.c: показать все пустые комнаты.
MySQL і Решение 2.2.10.С
1SELECT 'r id',
2'r name',
3'c id',
4'c room'
5'c name'
6 |
FROM |
' rooms' |
7 |
|
LEFT JOIN 'computers' |
8 |
|
ON 'r id' = 'c room' |
9 |
WHERE |
'c room' IS NULL |
MS SQL I Решение 2.2.10.C |
1SELECT [r id],
2[r name]
3[c id],
4[c room]
5[c name]
6 |
FROM |
[rooms] |
7 |
|
LEFT JOIN [computers] |
8 |
|
ON [r id] = [c room] |
9 |
WHERE |
[c room] IS NULL |
Oracle I Решение 2.2.10.C |
1SELECT "r id",
2"r name"
3"c id",
4"c room"
5"c name"
6 |
FROM |
"rooms" |
7 |
|
LEFT JOIN "computers" |
8 |
|
ON "r id" = "c room" |
9 |
WHERE |
"c room" IS NULL |
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 164/545