- •Глава 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
- •Рекомендуемая литература
3.2.3.1. Агрегатные функции без использования фразы group by.
Если не используется фраза GROUP BY, то в перечень элементов_SELECT можно включать лишь агрегатные функции или выражения, содержащие такие функции. Другими словами, нельзя иметь в списке столбцы, не являющихся аргументами агрегатных функций.
Пример 12.
Выдать данные о блюде (Блюдо=10), указать количество ингредиентов и их суммарный вес:
SELECT COUNT(Продукт) as Количество, SUM(Вес) as Вес
Результат |
|
Количество |
Вес |
5 |
360 |
WHERE Блюдо = 10;
При выполнении запроса
SELECT Блюдо, COUNT(Продукт), SUM(Вес)
FROM Состав WHERE Блюдо = 10;
будет получено сообщение об ошибке:
Column 'Состав.Блюдо' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Это связано с тем, что агрегатная функция создает единственное значение из множества значений столбца-аргумента, а для "свободного" столбца должно быть выдано все множество его значений. Без специального указания (оно задается фразой GROUP BY) SQL не будет выяснять, одинаковы значения этого множества (как в данном примере, где Блюдо = 10) или различны (как было бы при отсутствии WHERE фразы). Поэтому подобный запрос отвергается системой.
Правда, никто не запрещает дать запрос
SELECT 'Блюдо 10', COUNT(Продукт), SUM(Вес)
FROM Состав WHERE Блюдо = 10;
Отметим также, что в столбце-аргументе перед применением любой функции, кроме COUNT(*), исключаются все неопределенные значения. Если оказывается, что аргумент - пустое множество, функция COUNT принимает значение 0, а остальные - NULL.
Например, для получения общего количества заказов, количества различных блюд и общего количества порций на указанную дату можно написать запрос
SELECT ’01.02.2011’ as Дата,
COUNT( DISTINCT ID_заказ) as Кол_заказов,
COUNT( DISTINCT блюдо) as Кол_блюд,
SUM(Количество_порций) as Кол_порций
FROM Заказы
Результат |
|
|
|
Дата |
Кол_заказов |
Кол_блюд |
Кол_порций |
01.02.2011 |
2 |
5 |
24 |
и получить
Если в запросе указать дату, когда ресторан не работал
SELECT ’01.01.2011’ as Дата,
COUNT( DISTINCT ID_заказ) as Кол_заказов,
COUNT( DISTINCT блюдо) as Кол_блюд,
SUM(Количество_порций) as Кол_порций
FROM Заказы
WHERE Дата=’01.01.2011’
Результат |
|
|
|
Дата |
Кол_заказов |
Кол_блюд |
Кол_порций |
01.01.2011 |
0 |
0 |
NULL |
3.2.3.2. Фраза group by.
Мы показали, как можно вычислить статистику по заказам на определенную дату.
Пример 13.
Теперь требуется вычислить эту статистику за каждый отработанный день. Это можно легко сделать с помощью запроса
SELECT Дата,
COUNT( DISTINCT ID_заказ) as Кол_заказов,
COUNT( DISTINCT блюдо) as Кол_блюд,
SUM(Количество_порций) as Кол_порций
FROM Заказы
GROUP BY Дата;
Результат |
|
|
|
Дата |
Кол_заказов |
Кол_блюд |
Кол_порций |
2011-01-02 |
2 |
5 |
24 |
2011-01-03 |
3 |
5 |
10 |
… |
|
|
|
Фраза GROUP BY (группировать по) инициирует перекомпоновку указанной во FROM таблицы по группам, каждая из которых имеет одинаковые значения в столбце, указанном в GROUP BY. В рассматриваемом примере строки таблицы Заказы группируются так, что в одной группе содержатся все строки для заказов с Дата=’ 2011-01-02’, в другой – для заказов с Дата=’ 2011-01-03’ и т.д. Далее к каждой группе применяется фраза SELECT. Каждое выражение в этой фразе должно принимать единственное значение для группы, т.е. оно может быть либо значением столбца, указанного в GROUP BY, либо арифметическим выражением, включающим это значение, либо константой, либо одной из агрегатных функций, которая оперирует всеми значениями столбца в группе и сводит эти значения к единственному значению (например, к сумме).
Если в запросе используются фразы WHERE и GROUP BY, то строки, не удовлетворяющие фразе WHERE, исключаются до выполнения группирования.
SELECT Дата,
COUNT( DISTINCT ID_заказ) as Кол_заказов,
COUNT( DISTINCT Блюдо) as Кол_блюд,
SUM(Количество_порций) as Кол_порций
FROM Заказы
WHERE Дата BETWEEN ’01.01.2011’ and ’01.31.2011’
GROUP BY Дата;
Отметим, что фраза GROUP BY не предполагает ORDER BY. Чтобы гарантировать упорядочение по дате результата рассматриваемого примера, следует дать запрос
SELECT Дата,
COUNT( DISTINCT ID_заказ) as Кол_заказов,
COUNT( DISTINCT Блюдо) as Кол_блюд,
SUM(Количество_порций) as Кол_порций
FROM Заказы
WHERE Дата BETWEEN ’01.01.2011’ and ’31.01.2011’
GROUP BY Дата
ORDER BY Дата;
Наконец, отметим, что строки таблицы можно группировать по любой комбинации ее столбцов.
Так, по запросу
SELECT Дата, Блюдо,
SUM(Количество_порций) as Кол_порций
FROM Заказы
WHERE Дата BETWEEN ’01.01.2011’ and ’01.31.2011’
GROUP BY Дата, Блюдо
ORDER BY Дата;
можно на каждый день января, узнать какие блюда, и в каком количестве порций были приготовлены:
Результат |
|
|
Дата |
Блюдо |
Кол_порций |
2011-01-02 |
1 |
10 |
2011-01-02 |
14 |
4 |
2011-01-02 |
15 |
6 |
2011-01-02 |
27 |
2 |
2011-01-02 |
33 |
2 |
2011-01-03 |
2 |
3 |
2011-01-03 |
4 |
3 |
2011-01-03 |
15 |
2 |
2011-01-03 |
16 |
1 |
2011-01-03 |
25 |
1 |
Синтаксис фразы GROUP BY
GROUP BY [ALL] [ CUBE | ROLLUP] {[таблица.]столбец [, [таблица.]столбец] …}
позволяет указать следующие параметры
ALL – означает включение в результат выборки всех групп, независимо от того, соответствуют ли связанные с ним данные существующим в разделе WHERE условиям выборки. В строках не соответствующих условию выборки, во всех столбцах, кроме столбцов, по которым осуществляется группировка, будут выведены значения NULL.
Результат |
|
Основа |
Количество |
Кофе |
0 |
Крупа |
0 |
Молоко |
0 |
Мясо |
0 |
Овощи |
4 |
Рыба |
0 |
Фрукты |
0 |
Яйца |
0 |
SELECT Основа, COUNT(*) as Количество
FROM Блюда
WHERE Основа = 'Овощи'
GROUP BY ALL Основа
ROLLUP ( )
Формирует статистические строки простого предложения GROUP BY и строки подытогов или строки со статистическими вычислениями высокого уровня, а также строки общего итога.
Количество возвращаемых группирований равно количеству выражений в списке элементов GROPU BY плюс один.
Например, рассмотрим следующую инструкцию.
SELECT a, b, c, SUM( <expression> )
FROM T
GROUP BY ROLLUP(a, b, c)
Для
каждого уникального сочетания значений
(a,
b, c)
, (a,
b)
и (a)
формируется одна строка с подытогом.
Вычисляется также строка общего итога.
Столбцы свертываются справа налево. Последовательность расположения столбцов влияет на выходное группирование ROLLUP и может отразиться на количестве строк в результирующем наборе. Рассмотрим пример для нашей БД.
Результат |
|
|
Дата |
Блюдо |
Кол_порций |
2011-01-02 |
1 |
10 |
2011-01-02 |
14 |
4 |
2011-01-02 |
15 |
6 |
2011-01-02 |
27 |
2 |
2011-01-02 |
33 |
2 |
2011-01-02 |
NULL |
24 |
2011-01-03 |
2 |
3 |
2011-01-03 |
4 |
3 |
2011-01-03 |
15 |
2 |
2011-01-03 |
16 |
1 |
2011-01-03 |
25 |
1 |
2011-01-03 |
NULL |
10 |
NULL |
NULL |
34 |
SUM(Количество_порций) as Кол_порций
FROM Заказы
WHERE Дата BETWEEN
’01.01.2011’ and ’01.31.2011’
GROUP BY ROLLUP(Дата, Блюдо);
CUBE ( )
Формирует статистические строки простого предложения GROUP BY, строки со статистическими вычислениями высокого уровня конструкции ROLLUP и строки с результатами перекрестных вычислений.
Выходные данные CUBE являются группированием для всех перестановок выражений в списке элементов GROPU BY.
Количество формируемых группирований равно (2n), где n — количество выражений в списке элементов GROPU BY . Например, рассмотрим следующую инструкцию.
SELECT a, b, c, SUM(<expression>)
FROM T
GROUP BY CUBE(a, b, c)
Формируется
одна строка для каждого уникального
сочетания значений (a,
b, c)
, (a,
b)
, (a,
c)
, (b,
c)
, (a)
,
(b)
и (c)
с подытогом для каждой строки и строкой
общего итога.
Выходные данные CUBE не зависят от порядка столбцов.
Результат |
|
|
Дата |
Блюдо |
Кол_порций |
2011-01-02 |
15 |
6 |
2011-01-03 |
15 |
2 |
NULL |
15 |
8 |
2011-01-03 |
16 |
1 |
NULL |
16 |
1 |
2011-01-03 |
25 |
1 |
NULL |
25 |
1 |
2011-01-02 |
27 |
2 |
NULL |
27 |
2 |
2011-01-02 |
33 |
2 |
NULL |
33 |
2 |
NULL |
NULL |
14 |
2011-01-02 |
NULL |
10 |
2011-01-03 |
NULL |
4 |
SELECT Дата, Блюдо,
SUM(Количество_порций) as Кол_порций
FROM Заказы
WHERE Блюдо >= 15
GROUP BY CUBE(Дата, Блюдо);