Бази даних-20210115T104840Z-001 / Реферат на тему _Современные СУБД_ / Using_MySql,_MS_SQL_Server_and_Oracle
.pdfПример 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