Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
9
Добавлен:
15.01.2021
Размер:
14.96 Mб
Скачать

Пример 52: получение комбинации неповторяющихся идентификаторов

Oracl

і

Решение 7.4.2.a

|

 

 

e

 

 

 

 

 

 

 

 

1

SELECT "id first",

 

 

2

 

 

"id second"

 

 

3

FROM

(SELECT "id first",

 

4

 

 

 

"id second"

 

5

 

 

 

ROW NUMBER() OVER (ORDER BY NULL) AS "rn"

6

 

 

FROM

(SELECT "id first"

7

 

 

 

FROM

(SELECT "s id" AS "id first",

8

 

 

 

 

ROW NUMBER()

9

 

 

 

 

OVER (ORDER BY DBMS RANDOM.RANDOM) AS "rn"

10

 

 

 

 

FROM

"subscribers") "pre set1"

11

 

 

 

WHERE

"rn" <= 2) "set1"

12

 

 

 

CROSS JOIN

 

13

 

 

 

(SELECT "id second"

14

 

 

 

FROM

(SELECT "s id" AS "id second",

15

 

 

 

 

ROW NUMBER()

16

 

 

 

 

OVER (ORDER BY DBMS RANDOM.RANDOM) AS "rn"

17

 

 

 

 

FROM

"subscribers") "pre set2"

18

 

 

 

WHERE

"rn" = 1

"set2"

19

 

 

WHERE

"id first" != "id second") "prepared data"

20

WHERE

"rn" = 1

 

 

На этом решение данной задачи завершено.

■ЛУ Решение 7.4.2. b{536}.

Внимание! Решение данной задачи приведено как пример того, что делать нельзя. Далее будет объяснено, почему именно это нельзя делать.

Поскольку MySQL не поддерживает общие табличные выражения, для данной СУБД решение задачи объективно не существует, и мы сразу переходим к MS SQL Server и Oracle (решения для обеих СУБД одинаковы, отличия - лишь в способе упорядочивания и получения первой записи, но эти особенности уже рассмотрены в решении{536} задачи 7.4.2.a{536}).

Сначала рассмотрим код (напоминание: это неправильный код) для обеих

СУБД.

MS SQL

 

Решение 7.4.2.b (неправильный код)

|

 

1

WITH [first_source]

 

 

2

 

AS (SELECT TOP 1 [s_id]

 

 

3

 

FROM

[subscribers]

 

 

4

 

ORDER

BY NEWID()),

 

 

5

 

[second_source]

 

 

6

 

AS (SELECT TOP 1 [s_id]

 

 

7

 

FROM

[subscribers]

 

 

8

 

WHERE

[s_id] !=

 

[s_id]

9

 

(SELECT

 

[first_source])

10

 

 

FROM

 

 

11

 

ORDER BY NEWID())

 

[id first]

12

 

[second_source] [s_id] AS

[id_second]

13

FROM

[first_source]

 

 

14

CROSS JOIN [second source]

 

 

 

 

 

 

 

 

Работа с MySQL, MS SQL Server и Oracle в примерах ©Богдан Марчук Стр: 570/545

Пример 52: получение комбинации неповторяющихся идентификаторов

Oracle I

Решение 7.4.2.b (неправильный код)

|

 

 

 

1

WITH

"first_source"

 

 

 

 

2

 

AS (SELECT "s_id",

 

 

 

 

3

 

 

ROW_NUMBER() OVER

(ORDER

BY DBMS RANDOM.RANDOM)

AS "rn"

4

 

FROM

"subscribers"),

 

 

 

 

5

 

"second_source" AS (SELECT

 

 

 

 

6

 

 

"s_id",

 

 

 

 

7

 

 

ROW_NUMBER() OVER

(ORDER

BY DBMS_RANDOM.RANDOM)

AS "rn"

8

 

FROM

"subscribers"

 

 

 

 

 

 

 

 

 

9

 

WHERE

"s_id" != (SELECT

" s_id"

 

10

 

 

FROM

 

"first_source"

 

11

 

 

WHERE

 

"rn" = 1 )

 

12

SELECT "first_source" "s_id" AS "

id_first", id_second"

 

13

 

"second_source" "s_id" AS "

 

 

 

14

FROM

"first_source"

 

 

 

 

15

CROSS JOIN "second_source"

 

 

 

 

16

WHERE "first_source" "rn" = 1

 

 

 

 

17

AND "second source" "rn" = 1

 

 

 

 

 

 

 

 

 

 

 

 

На первый взгляд, код должен работать.

В первом общем табличном выражении (строки 1-4 обоих запросов) мы получаем одну случайную запись. Во втором общем табличном выражении (строки 510 запроса для MS SQL Server и 5-11 запроса для Oracle) мы получаем ещё одну случайную запись, не совпадающую с полученной в первом общем табличном выражении, - за это отвечает условие WHERE.

Основной код запроса, идущий после общих табличных выражений, лишь оформляет результат в виде одной строки.

Попробуем несколько раз выполнить запросы. Если данных немного (а у нас в таблице subscribers всего четыре записи), очень скоро мы увидим ситуацию наподобие такой:

id_first id_second

3 3

Но как?! Ведь во втором общем табличном выражении чётко прописано в условии WHERE не брать запись, которую уже выбрало первое общее табличное

выражение!

Дело в том, что результаты вычисления общих табличных выражений не являются фиксированными (non-persistent). Иными словами, они генерируются заново при каждом обращении к общему табличному выражению, и потому набор данных, возвращаемый в подзапросе секции WHERE не совпадает с набором данных,

возвращаемым в других местах запроса.

Поясним это ещё раз (графически) на примере решения для MS SQL Server.

MS SQL

 

Решение 7.4.2.b (неправильный код)

 

 

 

1

WITH

[first_source]

 

 

 

2

 

 

AS (SELECT TOP 1 [s_id]

-----------

 

3

 

 

FROM

[subscribers]

Данные 2

 

4

 

 

ORDER BY NEWID()),

 

 

 

5

 

 

[second_source]

//

 

 

6

 

 

AS (SELECT TOP 1 [s_id]

 

 

 

7

 

 

FROM

[subscribers]

 

 

 

8

 

 

WHERE

[s_id] != (SELECT [s_id]

 

9

 

 

 

FROM

[first_source])

 

10

 

 

ORDER BY NEWID())

 

 

 

11

SELECT [first_source] [s_id] AS [id_first]

 

12

 

 

[second_source] [s_id] AS [id_second]

 

 

13

FROM

[first_source]

 

Данные 1

 

14

CROSS JOIN [second source]

 

 

 

Работа с MySQL, MS SQL Server и Oracle в примерах ©Богдан Марчук Стр: 571/545

Пример 52: получение комбинации неповторяющихся идентификаторов

«Данные 1» и «данные 2» представляют собой разные данные. Допустим, что «данные 1» - случайным образом выбранный идентификатор со значением 3. Но при выполнении второго общего табличного выражения «данные 2» дают другое число (например, 1) и второй случайный идентификатор сравнивается уже с этим числом (1),

ане с тем, что было выбрано ранее (3).

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

К сожалению, эта проблема не имеет никакого решения в MS SQL Server - в данной СУБД невозможно «материализовать» результаты вычисления общих табличных выражений. В Oracle же обходной способ существует.

Oracle і Решение 7.4.2.b

1WITH "first source"

2AS (SELECT /*+ MATERIALIZE */ "s id",

3

 

ROW NUMBER() OVER (ORDER BY DBMS RANDOM.RANDOM) AS "rn"

4

FROM

"subscribers"),

5"second source"

6AS (SELECT /*+ MATERIALIZE */ "s id",

7

 

ROW NUMBER() OVER (ORDER BY DBMS RANDOM.RANDOM) AS "rn"

8

FROM

"subscribers"

 

9

WHERE

"s id" != (SELECT "s id"

10

 

FROM

"first source"

11

 

WHERE

"rn" = 1))

12SELECT "first source" "s id" AS "id first",

13"second source" "s id" AS "id second"

14

FROM

"first source"

15CROS JOIN "second source"

16WHER "first source" "rn" = 1

17AND"second_source" "rn" = 1

Обратите внимание на конструкцию /*+ MATERIALIZE */ в строках 2 и 6 - это

т.н. подсказка (query hint), предписывающая СУБД «материализовать» (по аналогии с материализованными представлениями, см. пример 27{215}) результаты выполнения общего табличного выражения. Теперь результаты вычисления общих табличных выражений фиксируются, и описанная выше проблема исчезает, т.е. «данные 1» и «данные 2» совпадают.

Внимание! Конструкция /*+ MATERIALIZE */ является недокументиро-

ванной особенностью Oracle и может в любой момент перестать поддерживаться. Т.е. такое решение хоть и работает, но не может считаться

надёжным.

Задание 7.4.2.TSK.A: оптимизировтаь решение{536} задачи 7.4.2.a{536} таким образом, чтобы получение двух случайных записей для первого набора и одной случайной записи для второго набора происходило без упорядочивания по случайному числу.

Задание 7.4.2.TSK.B: реализовать решение{536} задачи 7.4.2.a{536} в виде хранимой

процедуры без получения декартового произведения множеств.

Работа с MySQL, MS SQL Server и Oracle в примерах ©Богдан Марчук Стр: 572/545

Краткое сравнение MySQL, MS SQL Server, Oracle

Раздел 8: Краткое сравнение MySQL, MS SQL Server, Oracle

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

Особенности запросов на выборку и модификацию данных.

Суть

MySQL

MS SQL Server

Oracle

Ссылка

Условия объ-

Можно использовать

Можно использовать

Можно использовать

2.2.1.a{67}

единения в

ON или US-

только ON

ON или US-

 

 

JOIN

1ЫО(одноимённые

 

ШО(одноимённые

 

 

 

 

 

 

 

поля в объединяе-

 

поля в объединяе-

 

 

 

мых таблицах)

 

мых таблицах)

 

 

Типы данных

Результирующий тип

Нужна конвертация,

Результирующий тип

2.1.5.a{31}

для AVG и иных

выбирается ав-

выбирается ав-

 

 

 

 

 

числовых

томатически, кон-

иначе будут неверные

томатически, кон-

 

 

операций

вертация не нужна

результаты

вертация не нужна

 

 

 

 

 

 

 

(например, AVG от

 

 

 

 

 

целочисленного поля

 

 

 

 

 

тоже будет целым

 

 

 

 

 

числом, т.е. дробная

 

 

 

 

 

часть будет утеряна)

 

 

 

Расположение

В конце

В конце

В начале; можно из-

2.1.6.EXP.A{37}

 

 

менить через NULLS

 

 

по умолчанию

 

 

FIRST и NULLS LAST

 

 

NULL- значений

 

 

 

 

 

при сортировке

 

 

 

 

 

Приведение

Автоматическое

Автоматическое

Требуется явная

2.1.7.b{40}

строкового

 

 

конвертация

 

 

представления

 

 

 

 

 

даты к

 

 

 

 

 

датавремен-

 

 

 

 

 

ному типу

 

 

 

 

 

Показ первых

LIMIT x

TOP x или OFFSET y

До 12c нужен вло-

2.1.8.b{44}

нескольких

 

ROWS FETCH NEXT x

женный запрос с

 

 

рядов выборки

 

ROWS ONLY

ROW_NUMBER() , c12c

 

 

 

 

 

поддерживается

 

 

 

 

 

OFFSET y ROWS

 

 

 

 

 

FETCH NEXT x ROWS

 

 

 

 

 

ONLY

 

 

 

 

 

 

 

 

 

Есть также поддержка

 

2.2.7.b{116}

 

 

TOP ...

 

 

 

 

 

WITH TIES

 

 

 

 

 

 

 

 

Ранжирующие

Не поддерживаются,

ROW_NUMBER, RANK,

ROW_NUMBER, RANK,

2.1.8.EXP.D{50},

(оконные

но можно проэмули-

DENSE_RANK, NTILE

DENSE_RANK, NTILE

2.2.7.d

{120}

функции)

ровать

 

 

,

 

 

2.2.9.

d{140}

 

 

 

 

Именование

Обязательно

Обязательно

Обязательно, при

2.1.8.EXP.D{50},

подзапросов,

 

 

этом нельзя писать AS

2.1.8.c{46},

являющихся

 

 

перед именем

2.1.8.

d{48}

источником

 

 

подзапроса

 

 

табличных

 

 

 

 

 

данных (в

 

 

 

 

 

секции FROM и

 

 

 

 

 

JOIN)

 

 

 

 

 

Работа с MySQL, MS SQL Server и Oracle в примерах © Богдан Марчук Стр: 543/545

Краткое сравнение MySQL, MS SQL Server, Oracle

Особенности запросов на выборку и модификацию данных (продолжение).

Суть

MySQL

MS SQL Server

Oracle

Ссылка

Общие таб-

Не поддерживаются,

Поддерживаются

Поддерживаются

2.1.8.d{48},

личные выра-

но иногда можно

 

 

2.2.6.b{103}

жения

эмулировать

 

 

 

Определение

иАТЕП1ЕЕ(большая

DATEDIFF(day,

(большая -

2.1.9.d{57}

разницы в днях

, меньшая)

меньшая, большая)

меньшая)

 

между двумя

 

 

 

 

датами

 

 

 

 

Получение

CURDATE()

CONVERT(date,

TRUNC(SYSDATE)

2.1.9.d{57}

текущей даты

 

GETDATE()

 

 

Особенности

Можно в SELECT

Нельзя в SELECT

Нельзя в SELECT

2.1.10.a{61},

GROUP BY

указывать поля, не

указывать поля, не

указывать поля, не

2.2.2.a{72}

 

являющиеся агреги-

являющиеся агреги-

являющиеся агреги-

 

 

рующими функциями

рующими функциями

рующими функциями

 

 

и не перечисленные в

и не перечисленные в

и не перечисленные в

 

 

GROUP BY. Можно в

GROUP BY. Нельзя в

GROUP BY. Нельзя в

 

 

GROUP BY ссылаться

GROUP BY ссылаться

GROUP BY ссылаться

 

 

на имя (псевдоним)

на имя (псевдоним)

на имя (псевдоним)

 

 

выражения,

выражения,

выражения,

 

 

используемого в

используемого в

используемого в

 

 

SELECT.

SELECT.

SELECT.

 

 

 

 

 

 

Групповая

GROUP_CONCAT()

STUFF (FOR XML...)

LISTAGG()

2.2.2.a{72},

конкатенация

 

 

 

2.2.2.b{76}

Выборка дан-

Как правило, не тре-

Всегда требуется

Всегда требуется

2.2.5.c{100}

ных из не-

явное указание имени

явное указание имени

 

буется указания имени

 

скольких таблиц

таблицы, если в

таблицы, если в

 

таблицы, СУБД

 

и одноимённые

автоматически

выборку попадает два

выборку попадает два

 

поля

определяет, откуда

и более одноимённых

и более одноимённых

 

 

поля

поля

 

 

извлекать данные

 

 

 

 

 

 

 

 

 

 

«Защита от

IFNULL(поле,

ISNULL(поле,

NVL(поле, под-

2.2.6.b{103}

NULL»

подстановочное

подстановочное

становочное зна-

 

 

значение)

значение)

чение)

 

 

 

 

 

 

TRUE / FALSE

Есть, трактуются как 1

Явным образом от-

Явным образом от-

2.2.7.e{124}

 

и 0

сутствуют

сутствуют

 

Разновидности

JOIN, LEFT JOIN,

JOIN, LEFT JOIN,

JOIN, LEFT JOIN,

Пример 20{149}

JOIN

RIGHT JOIN, CROSS

RIGHT JOIN, CROSS

 

RIGHT JOIN, CROSS

 

 

JOIN, FULL OUTER

JOIN, FULL OUTER

 

 

JOIN, не поддержи-

 

 

JOIN, CROSS APPLY и

JOIN, с версии 12c

 

 

вается FULL OUTER

 

 

OUTER APPLY

поддерживается

 

 

JOIN и CROSS/OUTER

 

 

 

CROSS APPLY и

 

 

APPLY

 

 

 

 

OUTER APPLY

 

 

 

 

 

Проверка того

(NOT) EXISTS

(NOT) EXISTS

 

2.2.7.e{124}

факта, что за-

(запрос)

(запрос)

EXISTS (запрос) , а

2.3.5.b{203}

прос вернул

 

 

вместо NOT EXISTS

6.1.2.a{419}

(не)пустой ре-

 

 

нужно объявить

 

 

 

 

 

зультат

 

 

переменную, сделать

 

 

 

 

SELECT COUNT в неё,

 

 

 

 

сравнить её с нулём

 

Конкатенация

CONCAT(сколько

CONCAT(сколько

CONCAT(ровно два

2.3.5.c{205}

строк

угодно парамет-

угодно парамет-

параметра) или ис-

 

 

ров)

ров)

пользовать ||

 

Работа с MySQL, MS SQL Server и Oracle в примерах © Богдан Марчук Стр: 543/545

Краткое сравнение MySQL, MS SQL Server, Oracle

Особенности запросов на выборку и модификацию данных (продолжение).

Суть

MySQL

MS SQL Server

Oracle

Ссылка

Вставка зна-

Просто передать

Включить для таб-

Отключить триггер,

2.3.1.a{182}

чения в авто-

значение — и всё

лицы IDEN-

реализующий авто-

 

инкременти-

 

TITY_INSERT

инкрементацию

 

руемый пер-

 

 

 

 

вичный ключ

 

 

 

 

Вставка или

REPLACE и ON

MERGE

MERGE

2.3.4.a{195},

обновление в

DUPLICATE KEY

 

 

2.3.4.b{197}

зависимости от

UPDATE

 

 

 

совпадения

 

 

 

 

значений

 

 

 

 

первичного

 

 

 

 

ключа

 

 

 

 

Особенности представлений, триггеров, хранимых подпрограмм, транзакций.

Суть

MySQL

MS SQL Server

Oracle

Ссылка

 

Нельзя использовать

Можно использовать

Можно использовать

3.1.1.a{210}

Построение

подзапросы в секции

подзапросы в

подзапросы в секции

 

представлений

FROM

секции FROM

FROM

 

Кэширующие

Не поддерживаются

Поддерживаются

Поддерживаются

Пример 27{215}

(материали-

 

 

 

 

зованные, ин-

 

 

 

 

дексирован-

 

 

 

 

ные) пред-

 

 

 

 

ставления

 

 

 

 

Триггеры

Не более шести штук

BEFORE-триггеров нет,

BEFORE-триггеров нет,

3.1.2.b{232}

 

(даже если пытаться

но можно создавать

но можно создавать

 

 

задать разные имена):

любое количество

любое количество

 

 

BE- FORE/AFTER

AFTER и INSTEAD OF

AFTER и INSTEAD OF

 

 

IN-

триггеров на

триггеров на

 

 

SERT/UPDATE/DE-

INSERT/UP-

INSERT/UP-

 

 

LETE

DATE/DELETE

DATE/DELETE

 

 

 

 

 

 

 

Работают только на

Работают только на

Есть как триггеры

4.1.1.a{272},

 

уровне записи (акти-

уровне выражения

уровня записи, так и

4.1.1.b{281}

 

вируются каждый раз

(активируются один

триггеры уровня вы-

 

 

для каждой записи

раз для всего выра-

ражения (с некото-

 

 

обрабатываемых

жения)

рыми ограничениями:

 

 

данных)

 

нет псевдотаблиц

 

 

 

 

inserted и up-

 

 

 

 

dated)

 

 

 

 

 

4.1.1.b{281}

 

Нельзя «навесить»

Можно «навесить»

Можно «навесить»

 

 

одно тело триггера на

одно тело триггера на

одно тело триггера на

 

 

несколько операций

несколько операций

несколько операций

 

 

Не активируются

 

 

4.1.1.a{272},

 

каскадными опера-

Активируются кас-

Активируются кас-

4.1.2.a{292}

 

циями

кадными операциями

кадными операциями

 

Триггеры на

Не поддерживаются

Поддерживаются

Поддерживаются

Пример 30{257}

 

только INSTEAD OF

только INSTEAD OF

 

представлениях

 

 

 

 

 

 

 

 

 

 

 

Неявные

Есть

Есть

Нет

Пример 41{408}

транзакции и их

 

 

 

 

автопод-

 

 

 

 

тверждение

 

 

 

 

Работа с MySQL, MS SQL Server и Oracle в примерах © Богдан Марчук Стр: 543/545

Краткое сравнение MySQL, MS SQL Server, Oracle

Особенности представлений, триггеров, хранимых подпрограмм, транзакций (продолжение).

Суть

MySQL

MS SQL Server

Oracle

Ссылка

Уровни изо-

READ UNCOMMIT

READ UNCOMMIT

Уровни READ COM-

Пример 44{434}

лированности

TED, READ COMMIT-

MITTED,

 

TED, READ COMMIT

 

транзакций

TED, REPEATABLE

SERIALIZABLE;

 

TED, REPEATABLE

 

 

READ, SNAPSHOT,

режимы READ ONLY,

 

 

READ, SERIALIZABLE

 

 

 

SERIALIZABLE

READ WRITE

 

Уровень изо-

REPEATABLE READ

READ COMMITTED

READ COMMITTED

6.2.1.a{428}

лированности

 

 

 

 

по умолчанию

 

 

 

 

Вывод отла-

SELECT x

PRINT x

DBMS_OUT-

6.2.2.a{434}

дочной ин-

 

 

PUT.PUT_LINE(x)

 

формации

 

 

 

 

Пауза в вы-

SELECT SLEEP(s)

WAITFOR DELAY

EXEC

6.2.1.a{428}

полнении

 

'hh:mm:ss'

DBMS_LOCK.SLEEP(

 

скрипта

 

 

s)

 

Модификация

Да

Нет

Да

5.1.1.c{367}

данных в хра-

 

 

 

 

нимых функ-

 

 

 

 

циях

 

 

 

 

Задание 8.TSK.A: дополните приведённую выше таблицу списками индексов, поддерживаемых каждой из трёх СУБД.

Задание 8.TSK.B: заведите себе подобную таблицу и отмечайте особенности каждой СУБД — в первую очередь те, столкнувшись с которыми, вы вынуждены искать дополнительную информацию.

Работа с MySQL, MS SQL Server и Oracle в примерах © Богдан Марчук Стр: 543/545