
- •Введение в модель данных sql
- •1. Лекция: Язык баз данных sql: общее введение, типы данных и средства определения доменов Введение
- •Краткая история языка sql
- •Структура языка sql
- •Типы данных sql
- •Tочные числовые типы
- •Истинно целые типы
- •Точные типы, допускающие наличие дробной части
- •Приближенные числовые типы
- •Типы символьных строк
- •Типы битовых строк
- •Типы даты и времени
- •Тип даты
- •Типы времени
- •Типы временной метки
- •Типы времени и временной метки с временной зоной
- •Типы временных интервалов
- •Булевский тип
- •Типы коллекций
- •Типы массивов
- •Типы мультимножеств
- •Анонимные строчные типы
- •Типы, определяемые пользователем
- •Ссылочные типы
- •Средства определения, изменения определения и отмены определения доменов
- •Определение домена
- •Примеры определений доменов
- •Изменение определения домена
- •Примеры изменения определения домена
- •Отмена определения домена
- •Неявные и явные преобразования типа или домена
- •Неявные преобразования типов в sql
- •Явные преобразования типов или доменов и оператор cast
- •Заключение
- •2. Лекция: Язык баз данных sql: средства определения базовых таблиц и ограничений целостности
- •Введение
- •Средства определения, изменения и ликвидации базовых таблиц
- •Определение базовой таблицы
- •Определение столбца
- •Значения столбца по умолчанию
- •Ограничения целостности столбца
- •Определение табличного ограничения
- •Табличное ограничение первичного или возможного ключа
- •Проверочное табличное ограничение
- •Табличное ограничение внешнего ключа
- •Разновидности способов сопоставления значений внешнего и возможного ключей
- •Поддержка ссылочной целостности и ссылочные действия
- •Примеры определений базовых таблиц
- •Изменение определения базовой таблицы
- •Добавление, изменение или удаление определения столбца
- •Примеры изменения определения столбца
- •Изменение набора табличных ограничений
- •Примеры изменения набора табличных ограничений
- •Отмена определения (уничтожение) базовой таблицы
- •Средства определения и отмены общих ограничений целостности
- •Определение общих ограничений целостности
- •Отмена определения общего ограничения целостности
- •Немедленная и откладываемая проверка ограничений
- •Заключение
- •3. Лекция: Язык баз данных sql: общая характеристика оператора select и организация списка ссылок на таблицы в разделе from
- •4. Лекция: Язык баз данных sql: предикаты раздела where оператора select
- •Предикат сравнения
- •Примеры запросов с использованием предиката сравнения
- •Предикат between
- •Примеры запросов с использованием предиката between
- •Предикат null
- •Примеры запросов с использованием предиката null
- •Предикат in
- •Примеры запросов с использованием предиката in
- •Предикат like
- •Примеры запросов с использованием предиката like
- •Предикат similar
- •Примеры запросов с использованием предиката similar
- •Предикат exists
- •Примеры запросов с использованием предиката exists
- •Предикат unique
- •Примеры запросов с использованием предиката unique
- •Предикат overlaps
- •Примеры запросов с использованием предиката overlaps
- •Предикат сравнения с квантором
- •Примеры запросов с использованием предиката сравнения с квантором
- •Предикат match
- •Примеры запросов с использованием предиката match
- •Предикат distinct
- •Примеры запросов с использованием предиката distinct
- •Заключение
- •5. Лекция: Язык баз данных sql: группировка и условия раздела having, порождаемые и соединенные таблицы
- •Логические выражения раздела having
- •Предикаты сравнения
- •Предикат between
- •Предикат null
- •Предикат in
- •Предикат like
- •Предикат exists
- •Предикат unique
- •Предикаты сравнения с квантором
- •Предикат distinct
- •Более сложные конструкции оператора выборки
- •Соединенные таблицы
- •Формальные определения
- •Примеры соединений разного вида
- •Примеры запросов с использованием соединенных таблиц
- •6. Лекция: Язык баз данных sql: средства формулировки аналитических и рекурсивных запросов
- •Возможности формулирования аналитических запросов
- •Раздел group by rollup
- •Агрегатная функция grouping
- •Раздел group by cube
- •Рекурсивные запросы
- •Определения, относящиеся к рекурсии
- •Рекурсивные запросы с разделом with
- •Раздел search
- •Раздел cyrcle
- •Рекурсивные представления
- •Заключение
- •7. Лекция: Язык баз данных sql: средства манипулирования данными
- •Введение
- •Базовые средства манипулирования данными
- •Оператор insert для вставки строк в существующие таблицы
- •Вставка всех строк указанной таблицы
- •Вставка явно заданного набора строк
- •Вставка строк результата запроса
- •Оператор update для модификации существующих строк в существующих таблицах
- •Оператор delete для удаления строк в существующих таблицах
- •Представления, над которыми возможны операции обновления
- •Представления, допускающие применение операций обновления, в стандарте sql/92
- •Представления, допускающие применение операций обновления, в стандарте sql:1999
- •Критерии применимости операций обновления
- •Правила функциональных зависимостей
- •Раздел with check option определения представления
- •Режимы проверки cascaded и local
- •Примеры результатов действия раздела with check option
- •Исторический очерк
Примеры запросов с использованием соединенных таблиц
Мы приведем всего пару примеров, чтобы проиллюстрировать формулировки запросов, в разделе FROM которых используются ссылки на соединенные таблицы, т. е. выражения соединений.
SELECT DEPT.DEPT_NO, EMP1.EMP_NAME, COUNT(*), MIN(EMP2.EMP_SAL),
MAX(EMP2.EMP_SAL), AVG(EMP2.EMP_SAL)
FROM (DEPT NATURAL INNER JOIN EMP AS EMP2)
INNER JOIN EMP AS EMP1 ON DEPT.DEPT_MNG = EMP1.EMP_NO
GROUP BY DEPT.DEPT_NO, EMP1.EMP_NAME;
Пример 15.17. Для каждого отдела найти его номер, имя руководителя, число сотрудников, минимальный, максимальный и средний размеры зарплаты сотрудников (еще одна формулировка запроса из примера 15.4). (html, txt)
SELECT EMP1.EMP_NO, EMP2.EMP_NAME
FROM (EMP AS EMP1 NATURAL INNER JOIN DEPT)
INNER JOIN EMP AS EMP2 ON DEPT.DEPT_MNG = EMP2.EMP_NO
WHERE EMP1.EMP_SAL > 30000.00;
Пример 15.18. Найти номера служащих и имена их начальников отделов для служащих, размер зарплаты которых больше 30000 руб. (html,txt)
Можно обойтись вообще без раздела WHERE, если пожертвовать "естественностью" первого соединения (пример 15.17.1):
SELECT EMP1.EMP_NO, EMP2.EMP_NAME
FROM (EMP AS EMP1 INNER JOIN DEPT
ON EMP1.DEPT_NO = DEPT.DEPT_NO AND
EMP1.EMP_SAL > 30000.00)
INNER JOIN EMP AS EMP2 ON DEPT.MNG = EMP2.EMP_NO;
Пример 15.17.1. (html,txt)
Возможности соединенных таблиц открывают широкий простор для воображения, но не будем увлекаться и ограничимся приведенными простыми примерами.
Порождаемые таблицы с горизонтальной связью (lateral_derived_table)
Во всех вариантах построения запросов, обсуждавшихся ранее в этой и предыдущей лекциях, оставалась действующей общая семантика выполнения запроса: на первом шаге вычисляется расширенное декартово произведение таблиц, специфицированных в списке раздела FROM. Это остается верным и для случаев порождаемых и соединенных таблиц - вычисление выражения запросов или выражения соединений соответственно производится как подшаг вычисления раздела FROM. Однако в SQL имеется один специальный случай спецификации ссылки на таблицу (table_reference), который, вообще говоря, изменяет семантику раздела FROM. В этом подразделе мы кратко рассмотрим специальный случай.
Как показывают синтаксические правила, приведенные в лекции 13, один из возможных способов спецификации ссылки на таблицу состоит в следующем:
table_reference ::= LATERAL (query_expression)
[ [ AS ] correlation_name
[ ( derived_column_list ) ] ]
Таблица, ссылка на которую специфицируется таким образом, называется порождаемой таблицей с горизонтальной связью1)(lateral_derived_table; для краткости будем называть такие таблицы LD-таблицами). Отличие LD-таблицы от обычной порождаемой таблицы состоит в том, что в выражении запросов LD-таблицы разрешается использовать ссылки на столбцы таблиц, специфицированных ранее в разделе FROM (т. е. таких таблиц, ссылки на которые содержатся в списке раздела FROM слева от ссылки на данную LD-таблицу).2)Покажем на примере, каким образом наличие в списке раздела FROM ссылки на LD-таблицу меняет семантику этого раздела.
Предположим, что раздел FROM имеет вид FROM T1, T2, причем таблица T2 является LD-таблицей. Обозначим соответствующее выражение запросов через Q2. Тогда таблица T, являющаяся результатом раздела FROM, будет вычисляться следующим образом. Последовательно, строка за строкой просматривается таблица T1. Пусть s1 является очередной строкой T1. Тогда в Q2 все ссылки на столбцы вида T1.ck, где ck - имя некоторого столбца T1, заменяются значением s1.ck, и вычисляется полученное таким образом выражение запросов. Обозначим результирующую таблицу этого выражения через T2s1. Обозначим через T12s1таблицу, являющуюся результатом расширенного декартова произведения s1 CROSS JOIN T2s1. Таблица T получается путем объединения с сохранением дубликатов таблиц T12s1, полученных для всех строк s1 таблицы T1.
Видимо, наиболее важным (хотя и не единственным) частным случаем применения LD-таблицы является тот случай, когда в результате выполнения раздела FROM формируется соединение таблиц. Многие из формулировок запросов, приводившихся в этой лекции в качестве примеров, можно переформулировать с использованием данного механизма. Приведем лишь один простой пример.
SELECT EMP.EMP_NO
FROM DEPT, LATERAL
(SELECT EMP1_SAL
FROM EMP EMP1
WHERE EMP1.EMP_NO = DEPT.DEPT_MNG),
LATERAL
(SELECT EMP_NO
FROM EMP
WHERE EMP_SAL = EMP1_SAL AND
EMP.EMP_NO <> DEPT.DEPT_MNG);
Пример 15.19. Найти номера сотрудников, не являющихся руководителями отделов и получающих заплату, размер которой равен размеру зарплаты какого-либо руководителя отдела (еще одна формулировка запроса из примера 14.10 из лекции 14). (html,txt)
Я не мог бы привести ни одного примера запроса, который было бы невозможно сформулировать без использования порождаемых таблиц с горизонтальной связью. Возникает впечатление (возможно, ошибочное), что эта конструкция была введена в язык по двум причинам - (a) из соображений общности и (b) по причине простоты реализации (в том смысле, что для реализации LD-таблиц не требуется изобретать какие-то новые технические приемы).
Заключение
Думаю, что теперь читатели в состоянии в полной мере оценить мощность, разнообразие и избыточность средств языка SQL, предназначенных для формулировки запросов на выборку данных. Конечно, язык SQL (по крайней мере, ту часть SQL, которая обсуждается в этом курсе) нельзя считать языком программирования, но написание сложных запросов сродни программированию. И нельзя сказать, что SQL каким-либо образом дисциплинирует это "программирование". По всей видимости, в общем случае никто не может сказать, какая из формулировок одного и того же запроса является более правильной, это дело вкуса.
Зачастую десять студентов, одновременно формулирующих на SQL один и тот же запрос к одной и той же базе данных, выдают десять разных правильных решений. Один человек предпочитает формулировки запросов в классическом стиле, другой использует выражения запросов в разделе FROM, третий пытается сосредоточить все условия выборки в разделе HAVING. Люди с алгебраическими наклонностями предпочитают использовать выражения соединений. Приходилось встречать и формулировки со сложными вложенными подзапросами в списке выборки раздела SELECT.
Конечно, теоретически компилятор SQL должен быть в состоянии распознать все эквивалентные формулировки одного и того же запроса и выработать для всех них один и тот же наиболее эффективный план выполнения. Но чем больше разнообразие возможных формулировок, тем сложнее эта задача. Отсюда практический совет: не злоупотребляйте сложностью формулировки запроса. Полагайтесь на интуицию (и имеющиеся представления об особенностях используемой системы) и формулируйте запрос как можно проще.
И еще один практический совет. При формулировке запроса никогда не пользуйтесь имеющимися у вас данными о текущем состоянии базы данных, полагайтесь только на метаданные схемы базы данных. В противном случае вы сможете сформулировать запрос, выдающий в данный момент правильный результат, но этот запрос не будет эквивалентен никакому запросу, выдающему правильный ответ при любом состоянии базы данных.