- •Глава 1. Историческая справка. 10
- •Глава 2. Пример бд «Ресторан». 20
- •Глава 3. Выборка данных. 25
- •Глава 4. Подзапросы и производные таблицы 65
- •Глава 5. Функции ранжирования. 86
- •Глава 1. Историческая справка.
- •Стандарты.
- •1.2. Структура sql.
- •Глава 2. Пример бд «Ресторан».
- •2.1. Описание.
- •2.2. Диаграмма.
- •2.3. Данные в таблицах.
- •Глава 3. Выборка данных.
- •3.1. Оператор select. Синтаксис.
- •3.2. Примеры запросов с использованием единственной таблицы.
- •3.2.1. Выборка без использования фразы where.
- •3.2.1.1. Простейшие примеры.
- •3.2.1.2. Исключение дубликатов (distinct).
- •3.2.1.3. Выборка вычисляемых значений.
- •3.2.2. Выборка c использованием фразы where.
- •3.2.2.1. Использование операторов сравнения.
- •3.2.2.2. Сравнение с null.
- •3.2.2.3. Использование between.
- •3.2.2.4. Использование in (not in).
- •3.2.2.5. Использование like.
- •3.2.2.6. Выборка с упорядочением.
- •3.2.3. Использование агрегатных функций для подведения итогов.
- •3.2.3.1. Агрегатные функции без использования фразы group by.
- •3.2.3.2. Фраза group by.
- •3.2.3.3. Раздел having.
- •3.3. Примеры запросов с использованием нескольких таблиц.
- •3.3.1. Соединения «с условием where».
- •3.3.2. Соединение таблиц с дополнительными условиями.
- •3.3.2.1. Соединение таблицы со своей копией.
- •3.4. Соединения нескольких таблиц, используя join.
- •3.4.1. Внутреннее соединение.
- •3.4.2. Внешнее соединение.
- •3.4.2.1. Левое внешнее соединение.
- •3.4.2.2. Правое внешнее соединение.
- •3.4.2.3. Полное внешнее соединение.
- •3.4.2.4. Перекрёстное соединение.
- •3.4.3. Реальные примеры соединений.
- •Isnull(cast(n.Количество as varchar), ’нет’) as на_складе
- •Isnull(cast(n.Количество as varchar),’нет’) as на_складе
- •Глава 4. Подзапросы и производные таблицы
- •4.1.Производная таблица.
- •4.2. Вложенные подзапросы
- •4.2.1 Простые вложенные подзапросы
- •4.2.2. Использование одной и той же таблицы во внешнем и вложенном подзапросе
- •4.2.3. Использование агрегатных функций в подзапросах.
- •4.2.4. Подзапросы в предложении having.
- •4.3. Соотнесенные подзапросы.
- •4.4 Использование оператора exists.
- •4.5. Использование операторов any и all.
- •4.6. Объединение запросов union.
- •4.6.1. Union и устранение дубликатов.
- •4.6.2. Использование строк и выражений с union.
- •4.6.3. Использование union с order by.
- •4.6.4. Реализация внешнего полного соединения через запросы с union.
- •Глава 5. Функции ранжирования.
- •5.1. Функция row_number.
- •5.2. Функции rank() и dense_rank()
- •Глава 6. ИспользованиеPivoTиUnpivot.
- •In ([Овощи], [Мясо], [Рыба], [Молоко], [Яйца], [Крупа], [Фрукты], [Кофе])
- •In ( [первый сведенный столбец], [второй сведенный столбец],
- •In ([Овощи], [Мясо], [Рыба], [Молоко], [Яйца], [Крупа], [Фрукты], [Кофе])
- •Insert into Продукты (id_Продукта, Продукт, Белки)
- •Values (18, 'Горох', 180 );
- •Insert into Продукты (Продукт, Белки, Жиры)
- •7.4. Оператор update.
- •Глава 8. Представление.
- •Insert into Список_блюд values (36, 'Рагу', 3, 20);
- •Глава 9. Создание, изменение и удаление таблиц.
- •9.1. Оператор create table
- •6. Ограничение identity (автоинкрементное поле).
- •9.2. Изменение таблицы после того как она была создана (alter table).
- •9.3. Удаление таблицы (drop table).
- •9.4. Операторы создания и удаления индексов.
- •9.5. Понятие домена
- •Глава 10. Обобщенные табличные выражения (сте).
- •Представления, производные таблицы и выражения cte.
- •Рекурсивные запросы.
- •Id_father integer foreign key references Tree (id),
- •Values (1, null, 'all'), (2, 1, 'sea'), (3, 1, 'earth'),
- •Деревья без рекурсии.
- •Пример использования сте для решения задачи Коммивояжера.
- •Insert into tur select to_town, from_town, miles from tur;
- •Глава 11. Этапы выполнения командыSql.
- •11.1. Оптимизация запросов.
- •Приложение 1. Реализация реляционной алгебры средствами оператора select (Реляционная полнота sql).
- •Intersect
- •Рекомендуемая литература
4.4 Использование оператора exists.
Квантор EXISTS (существует) - понятие, заимствованное из формальной логики. В языке SQL предикат с квантором существования представляется выражением
… EXISTS (SELECT * FROM ...).
Такое выражение считается истинным только тогда, когда результат вычисления "SELECT * FROM ..." является непустым множеством (вернул хотя бы одну строку). Рассмотрим примеры.
Пример 33.
Выдать названия Блюд, представленных в меню на данное число.
SELECT Блюдо
Результат |
|
Блюдо | |
Салат летний | |
Салат мясной | |
Паштет из рыбы | |
Суп харчо | |
Суп молочный | |
Бефстроганов | |
Судак по-польски | |
Суфле яблочное | |
Кофе на молоке |
WHERE EXISTS (SELECT * FROM Меню m
WHERE m.Блюдо = Блюда.ID_Блюда
and Дата = '2011-01-02');
Система последовательно выбирает строки таблицы Блюда, выделяет из них значения столбцов Блюдо и ID_Блюда, а затем проверяет, является ли истинным условие существования, т.е. существует ли в таблице Меню(m) хотя бы одна строка со значением Дата = '2011-01-02' и значением m.Блюдо, равным значению Блюда.ID_Блюда. Если условие выполняется, то полученное значение столбца Блюдо включается в результат. Соответственно, запрос
SELECT Блюдо
FROM Блюда
WHERE NOT EXISTS (SELECT *
FROM Меню m
WHERE m.Блюдо = Блюда.ID_Блюда );
выдаст названия блюд, которые ни разу не включались в состав меню. Данные запросы также являются соотнесенными.
Хотя этот рассмотренный пример только показывает иной способ формулировки запроса для задачи, решаемой и другими путями (с помощью оператора IN или соединения), EXISTS представляет собой одну из наиболее важных возможностей SQL. Фактически любой запрос, который выражается через IN, может быть альтернативным образом сформулирован также с помощью EXISTS. Однако обратное высказывание несправедливо.
4.5. Использование операторов any и all.
Операторы ANY и ALL напоминают EXISTS, который воспринимает подзапросы как аргументы; однако они отличаются от EXISTS тем, что используются совместно с реляционными операторами. В этом отношении, они напоминают оператор IN, когда тот используется с подзапросами; они берут все значения выведенные подзапросом и обрабатывают их как модуль. Однако, в отличие от IN, они могут использоваться только с подзапросами.
Оператор ANY.
Оператор ANY означает, что предикат истинен, если хотя бы для одного значения из подзапроса предикат сравнения истинен.
Пример 34.
Имеется иной способ нахождения названий Блюда представленных в меню на данное число.
SELECT Блюдо
FROM Блюда
WHERE ID_Блюда = ANY (SELECT Блюдо
FROM Меню
WHERE Дата = '2011-01-02');
Оператор ANY берет все значения выведенные подзапросом, (для этого случая - это все значения Блюд в таблице Меню на указанную дату), и оценивает их как верные, если любой(ANY) из них равняется значению Блюда текущей строки внешнего запроса.
Следует отметить, что подзапрос должен выбирать значения такого же типа как и те, которые сравниваются в основном предикате. В этом его отличие от EXISTS, который просто определяет, производит ли подзапрос результаты или нет, и фактически не использует эти результаты.
Если при работе оператора ANY используется равенство, то этот запрос может быть всегда заменен запросом с IN
SELECT Блюдо
FROM Блюда
WHERE ID_Блюда IN (SELECT Блюдо
FROM Меню
WHERE Дата = '2011-01-02');
или EXISTS.
SELECT Блюдо
FROM Блюда b
WHERE EXISTS (SELECT Блюдо
FROM Меню m
WHERE Дата = '2011-01-02' and m.Блюдо = b. ID_Блюда);
Однако оператор ANY может использовать и другие реляционные операторы, кроме равенства, и таким образом, делать сравнения которые являются выше возможностей IN. Например, мы сделали заказ, но не рассчитали с деньгами и нам требуется замена некоторых блюд на более дешевые блюда.
Пример 35.
Список блюд с ценой, меньшей, чем любое блюдо из заказа номер 2.
SELECT b.Блюдо,
cast(SUM (s.Вес * n.Цена/1000)+b.Труд as numeric(6,2)) as Стоимоть
FROM (Блюда b JOIN Состав s ON b.ID_Блюда = s.Блюдо)
JOIN Наличие n ON s.Продукт = n.Продукт
WHERE b.ID_Блюда NOT IN (select Блюдо from Заказы where ID_Заказ = 2)
GROUP BY b.Блюдо,b.ID_Блюда, b.Труд
HAVING (SUM (s.Вес * n.Цена/1000)+b.Труд) < ANY
(SELECT SUM (s.Вес*n.Цена/1000)+b.Труд as Стоимоть
FROM ((Блюда b JOIN Состав s ON b.ID_Блюда = s.Блюдо)
JOIN Наличие n ON s.Продукт = n.Продукт)
JOIN Заказы z ON s.Блюдо = z.Блюдо
WHERE ID_Заказ = 2
GROUP BY b.Блюдо, b.Труд);
Подзапрос определяет стоимость блюд заказа. Эти данные используются для отбора в основном запросе.
Оператор ALL.
С помощью ALL, предикат является верным, если каждое значение выбранное подзапросом удовлетворяет условию в предикате внешнего запроса. Если мы хотим найти самый дорогой (дешевый Цена <=) продукт, то можем это сделать следующим образом:
Пример 36.
SELECT Продукт FROM Наличие
WHERE Цена >= ALL (SELECT DISTINCT Цена FROM Наличие);
Т.е. мы найдем те продукты, которые имеют цену выше или равную всем остальным (максимальную). Как и в случае с ANY, мы можем использовать EXISTS для производства альтернативной формулировки такого же запроса:
SELECT Продукт
FROM Наличие n
WHERE NOT EXISTS (SELECT * FROM Наличие n1
WHERE n1.Цена > n.Цена);
ALL чаще используется с неравенствами, чем с равенствами, так как значение может быть "равным для всех" результатом подзапроса, только если все результаты, фактически, идентичны. Рассмотрим следующий запрос:
Пример 37.
SELECT Продукт
FROM Наличие
WHERE Цена = ALL (SELECT DISTINCT Цена FROM Наличие);
Эта команда допустима, но, мы не получим никакого вывода. Только в единственном случае вывод будет выдан этим запросом - если все цены на продукты окажутся одинаковыми.
В SQL, выражение - < > ALL - в действительности соответствует " не равен любому " результату подзапроса. Другими словами, предикат верен, если данное значение не найдено среди результатов подзапроса.
Следует отметить, что вариант с EXISTS не абсолютно идентичен вариантам с ANY(ALL) из-за различия в том как обрабатываются NULL-значения. Всякий раз, когда допустимый подзапрос не в состоянии сделать вывод, ALL - автоматически верен, а ANY автоматически неправилен. Большинство пользователей, однако, находят ANY и ALL более удобными в использовании, чем EXISTS, который требует соотнесенных подзапросов. Кроме того, в зависимости от реализации, ANY и ALL могут, по крайней мере, в теории, быть более эффективными, чем EXISTS. Подзапросы ANY или ALL могут выполняться один раз и иметь вывод, используемый чтобы определять предикат для каждой строки основного запроса. EXISTS, с другой стороны, берет соотнесенный подзапрос, который требует, чтобы весь подзапрос повторно выполнялся для каждой строки основного запроса. Основная причина для формулировки EXISTS как альтернативы ANY и ALL в том, что ANY и ALL могут быть несколько неоднозначен, из-за способа использования этого термина в Английском языке.
Правильное понимание ANY и ALL.
В SQL, сказать что - значение больше (или меньше) чем любое(ANY) из набора значений – то же самое что сказать, что оно больше (или меньше) чем любое одно отдельное из этих значений. И наоборот, сказать, что значение не равно всему(ALL) набору значений, тоже что сказать, что нет такого значения в наборе которому оно равно.