- •Глава 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
- •Рекомендуемая литература
Isnull(cast(n.Количество as varchar), ’нет’) as на_складе
FROM Продукты p LEFT JOIN Наличие n ON p.ID_Продукта = n.Продукт
WHERE n.Продукт IS NULL;
Результат |
|
Продукт |
на_складе |
Масло растительное |
НЕТ |
Правое внешнее объединение.
Следующее правое внешнее соединение даёт в точности такие же результаты, как и левое:
SELECT p.Продукт,
Isnull(cast(n.Количество as varchar),’нет’) as на_складе
FROM Наличие n RIGHT JOIN Продукты p ON p.ID_Продукта = n.Продукт
Результат |
|
Продукт |
на_складе |
Масло растительное |
НЕТ |
Но как такое может быть?
В запросе поменяны местами таблицы! В запросе с правым соединением написано
FROM Наличие n RIGHT JOIN Продукты p
А в запросе с левым соединением было:
FROM Продукты p LEFT JOIN Наличие n
Из этого примера можно вынести важный урок: левое и правое внешние соединения абсолютно эквивалентны, смысл лишь в том, какая из таблиц является внешней — все строки этой таблицы будут включены в результат. Из-за этого многие программисты избегают правых внешних объединений и преобразуют их в левые, меняя таблицы местами; при этом таблица, из которой должны быть взяты все строки, всегда является левой. Левые внешние соединения для многих людей кажутся более понятными, чем правые.
Что если не менять таблицы местами в рассмотренном соединении? Предположим, запрос выглядит так:
SELECT p.Продукт, n.Количество, n.Стоимость
FROM Продукты p RIGHT JOIN Наличие n ON p.ID_Продукта = n.Продукт
На этот раз, как и в исходном левом объединении, таблица Продукты — левая, а таблица Наличие — правая.
Результат |
| |
Продукт |
Количество |
Цена |
Говядина |
108 |
429,84 |
Судак |
0 |
0,00 |
Масло |
73 |
274,61 |
Майонез |
39 |
97,46 |
Яйца |
61 |
111,83 |
Сметана |
88 |
206,60 |
Молоко |
214 |
83,80 |
Творог |
92 |
82,80 |
Морковь |
0 |
0,00 |
Лук |
77 |
46,30 |
Помидоры |
46 |
51,70 |
Зелень |
13 |
34,96 |
Рис |
54 |
51,17 |
Мука |
91 |
43,77 |
Яблоки |
117 |
189,92 |
Сахар |
98 |
96,14 |
Кофе |
37 |
166,50 |
Масло растительное |
NULL |
NULL |
Результаты запроса, оказываются, идентичны результатам внутреннего соединения.
Как такое может быть? Нет ли ошибки? Нет, и причина лежит в содержимом таблиц. Вспомните: правое внешнее объединение возвращает все строки правой таблицы и соответствующие им строки левой таблицы, если такие найдутся. Таблица Наличие — правая, и в данном случае каждая запись имеет свой ID_Продукта в таблице Продукты (иначе бы при добавлении строк в таблицу Наличие мы бы имели ошибку, связанную с внешним ключом). Возвращаются все записи, и несоответствующих строк нет.
Поэтому в порядке вещей, что правое внешнее соединение в этом случае даст такие же результаты, как и внутреннее, ведь оно следовало правилу: вернуть все строки внешней таблицы и соответствия, если таковые найдутся. В данном случае, они не нашлись.
Чтобы на самом деле увидеть правые внешние соединения в действии, рассмотрим следующий запрос.
Пример 23.
SELECT b.Блюдо, m.Дата, SUM( z.Количество_порций)
FROM ( Заказы z RIGHT JOIN Меню m ON m.Блюдо = z. Блюдо
and m. Дата = z. Дата)
JOIN Блюда b ON m.Блюдо = b.ID_ Блюдо
WHERE m.Дата = '2011-01-02'
Результат |
| |
Блюдо |
Дата |
|
Бефстроганов |
2011-01-02 |
4 |
Кофе на молоке |
2011-01-02 |
2 |
Паштет из рыбы |
2011-01-02 |
NULL |
Салат летний |
2011-01-02 |
10 |
Салат мясной |
2011-01-02 |
NULL |
Судак по-польски |
2011-01-02 |
6 |
Суп молочный |
2011-01-02 |
NULL |
Суп харчо |
2011-01-02 |
NULL |
Суфле яблочное |
2011-01-02 |
2 |
Данный запрос позволяет (благодаря правому внешнему соединению) вывести на экран все блюда из меню на 02.01.2011, даже если их никто не заказывал.