- •Простой оператор select
- •Предикаты
- •Предикаты сравнения
- •Предикат in
- •Объединение
- •Пересечение и разность
- •Предикат exists
- •Получение итоговых значений
- •Предложение group by
- •Предложение having
- •Использование в запросе нескольких источников записей
- •Использование ключевых слов some (any) и all с предикатами сравнения
- •Переименование столбцов и вычисления в результирующем наборе
- •Преобразование типов и оператор cast
- •Оператор case
- •Предикат like
- •Предикат like и регулярные выражения
- •Использование значения null в условиях поиска
- •Функция datepart
- •Нумерация строк в соответствии с порядком, заданном значениями первичного ключа
- •Функция row_number
- •Декартово произведение
- •Коррелирующие подзапросы
Предложение having
Если предложение WHERE определяет предикат для фильтрации строк, то предложение HAVING применяется после группировки для определения аналогичного предиката, фильтрующего группы по значениям агрегатных функций. Это предложение необходимо для проверки значений, которые получены с помощью агрегатной функции не из отдельных строк источника записей, определенного в предложении FROM, а из групп таких строк. Поэтому такая проверка не может содержаться в предложении WHERE.
Пример: Получить количество ПК и среднюю цену для каждой модели, средняя цена которой менее $800
SELECT model,COUNT(model) AS Qty_model,AVG(price) AS Avg_price
FROM PC
GROUP BY model
HAVING AVG(price) < 800;
Заметим, что в предложении HAVING нельзя использовать псевдоним (Avg_price), используемый для именования значений агрегатной функции в предложении SELECT. Дело в том, что предложение SELECT, формирующее выходной набор запроса, выполняется предпоследним перед предложением ORDER BY. Ниже приведен порядок обработки предложений в операторе SELECT:
FROM
WHERE
GROUP BY
HAVING
SELECT
ORDER BY
Следует отметить, что предложение HAVING может использоваться и без предложения GROUP BY. При отсутствии предложения GROUP BY агрегатные функции применяются ко всему выходному набору строк запроса, т.е. в результате мы получим всего одну строку, если выходной набор не пуст.
Таким образом, если условие на агрегатные значения в предложение HAVING будет истинным, то эта строка будет выводиться, в противном случае мы не получим ни одной строки.
Использование в запросе нескольких источников записей
Как видно из приведенной в конце предыдущего раздела синтаксической формы оператора SELECT, в предложении FROM допускается указание нескольких таблиц. Простое перечисление таблиц через запятую практически не используется, поскольку оно соответствует реляционной операции, которая называется декартовым произведением. То есть в результирующем наборе каждая строка из одной таблицы будет сочетаться с каждой строкой из другой.
Например, для таблиц:
A | ||||||
|
B | ||||||
|
Результат запроса
SELECT *
FROMA, B;
будет выглядеть следующим образом:
a |
b |
c |
d |
1 |
2 |
2 |
4 |
1 |
2 |
3 |
3 |
2 |
1 |
2 |
4 |
2 |
1 |
3 |
3 |
Поэтому перечисление таблиц, как правило, используется совместно с условием соединения строк из разных таблиц, указываемым в предложении WHERE. Для приведенных выше таблиц таким условием может быть совпадение значений, скажем, в столбцах a и c:
SELECT *
FROM A, B
WHERE a = c;
Теперь результатом выполнения этого запроса будет следующая таблица:
|
то есть соединяются только те строки таблиц, у которых в указанных столбцах находятся равные значения (эквисоединение). Естественно, могут быть использованы любые условия, хотя эквисоединение используется чаще всего, поскольку эта операция воссоздает некую исходную сущность предметной области, декомпозированную на две других в результате процедуры нормализации в процессе построения логической модели.
Если разные таблицы имеют столбцы с одинаковыми именами, то для однозначности требуется использовать точечную нотацию, которая называется уточнением имени столбца:
<имя таблицы>.<имя столбца>
В тех случаях, когда это не вызывает неоднозначности, использование данной нотации не является обязательным.
Пример1: Найти номер модели и производителя ПК, имеющих цену менее $600:
SELECT DISTINCT PC.model, maker
FROM PC, Product
WHERE PC.model = Product.model AND
price < 600;
В результате каждая модель одного и того же производителя выводится только один раз:
Иногда в предложении FROM требуется указать одну и ту же таблицу несколько раз. В этом случае обязательным является переименование.
Пример2: Вывести пары моделей, имеющих одинаковые цены:
SELECT DISTINCT A.model AS model_1, B.model AS model_2
FROM PC AS A, PC B
WHERE A.price = B.price AND
A.model < B.model;
Переименование также является обязательным, если в предложении FROM используется подзапрос, так как, в противном случае, у нас нет возможности уточнения имени столбца из подзапроса. Так, первый пример можно переписать следующим образом:
SELECT DISTINCT PC.model, maker
FROM PC, (SELECT maker, model
FROM Product
) AS Prod
WHERE PC.model = Prod.model AND
price < 600;
Обратите внимание, что в этом случае в других предложениях оператора SELECT уже нельзя использовать квалификатор Product, поскольку таблица Product уже не используется. Вместо него используется псевдоним Prod. Кроме того, ссылаться извне теперь можно только на те столбцы таблицы Product, которые перечислены в подзапросе.
За псевдонимом производного табличного выражения может в скобках стоять список имен столбцов, которые будут использоваться вместо имен табличного выражения. Порядок имен должен, естественно, соответствовать списку столбцов табличного выражения (в нашем случае - списку в предложении SELECT). Это способ позволяет избежать неоднозначности имен и, как следствие, необходимости их уточнения. Вот как может выглядеть предыдущий пример:
SELECT DISTINCT model, maker
FROM PC, (SELECT maker, model
FROM Product
) AS Prod(maker, model_1)
WHERE model = model_1 AND
price < 600;