Пример 1.4. Есть две таблицы
Построим запрос, выводящий фамилии клиентов и коды журналов.
SELECT Клиент.Фамилия, Подписка.КодЖурнала
FROM Клиент, Подписка;
Результат представляет собой декартово произведение исходных таблиц.
Каждая запись таблицы «Клиент» объединяется с каждой записью таблицы
«Подписка»

Следует ограничить результирующее множество комбинациями только тех
записей этих двух таблиц, которые связаны между собой (содержат одинаковые
значения в полях «КодКлиента»).
В предложении «FROM» вместо оператора объединения «,» (запятая) бу-
дем использовать оператор «INNER JOIN» - внутреннее объединение. Опера-
тор «INNER JOIN» позволяет наложить ограничение на объединяемые записи.
Предложение ON <условие> определяет связь между полями объединяемых
таблиц.
SELECT Клиент.Фамилия, Подписка.КодЖурнала
FROM Клиент INNER JOIN Подписка
ON Клиент.КодКлиента = Подписка.КодКлиента;
Результат содержит только комбинации записей, для которых выполняется
заданное условие.
Рассмотрим подробнее разные виды объединения.
INNER JOIN (внутреннее объединение). В результат включаются только
те записи из обеих таблиц, которые связаны между собой.
LEFT JOIN (левое внешнее объединение). В результат включаются все
записи из первой таблицы. Если для них нет связанных записей во второй
таблице, соответствующие поля результата будут пустыми.
RIGHT JOIN (правое внешнее объединение). Операция, зеркально сим-
метричная левому объединению. Включаются все записи из второй таб-
лицы и связанные с ними записи из первой.
В режиме конструктора тип объединения можно изменить заданием свойств
связи. Эта возможность была рассмотрена в [1], при описании работы с конст-
руктором запросов. При создании запроса в режиме конструктора для таблиц,

связи которых заданы в схеме данных, по умолчанию автоматически определя-
ется операция «INNER JOIN».
Пример 1.5. Заменим в созданном запросе (пример 1.4) тип объединения на
«LEFT JOIN».
SELECT Клиент.Фамилия, Подписка.КодЖурнала
FROM Клиент LEFT JOIN Подписка
ON Клиент.КодКлиента = Подписка.КодКлиента;
Результат работы измененного запроса:
Здесь присутствует фамилия «Федоров», для которой нет соответствий в
таблице «Журнал». Вторая колонка этой строки содержит значение «Null»
(пусто).
Группировка, сортировка, имена столбцов. Продолжим доработку со-
ставленного запроса. Заметим, что фамилия «Иванов» в результатах запроса
повторяется, поскольку для этого клиента оформлена подписка на два журнала.
Пример 1.6. Изменим запрос таким образом, чтобы фамилия каждого кли-
ента выводилась только один раз, и для него отображалось общее количество
выписанных журналов, а не коды каждого из журналов.
Зададим группировку записей по фамилии (фамилии не должны повторять-
ся) и для групп определим групповую операцию «подсчет количества».
SELECT Клиент.Фамилия, Count(Подписка.КодЖурнала)
FROM Клиент LEFT JOIN Подписка
ON Клиент.КодКлиента = Подписка.КодКлиента
GROUP BY Клиент.Фамилия;
Здесь подчеркнуты фрагменты, которые отличают этот запрос от предыду-
щего.
В предложении GROUP BY могут быть перечислены несколько полей че-
рез запятую. Если группировка производится по нескольким полям, объеди-
няться в группу будут строки, для которых попарно равны значения всех груп-
пируемых полей. Для всех полей, перечисленных в предложении SELECT, но
не вошедших в предложение GROUP BY, должны быть определены групповые
операции.
Результат работы запроса:

Пример 1.7. Название второго столбца (в примере выше) сформировано ав-
томатически. Надо задать осмысленное название. Кроме того, является лишь
совпадением то, что фамилии расположены по алфавиту. Следует явно указать
способ сортировки результирующего набора. Внесем соответствующие изме-
нения в запрос.
SELECT Клиент.Фамилия, Count(Подписка.КодЖурнала) AS Количество
FROM Клиент LEFT JOIN Подписка
ON Клиент.КодКлиента = Подписка.КодКлиента
GROUP BY Клиент.Фамилия
ORDER BY Клиент.Фамилия ASC;
Результат работы запроса:
Ключевое слово AS указывает имя (псевдоним) для столбца. Если имя не
задано явно, используется соответствующее ему имя поля исходной таблицы.
Если же столбец формируется с помощью некоторого выражения, Access при-
сваивает ему имя самостоятельно (как было в предыдущем примере).
Псевдонимы можно задавать не только для столбцов, но и для источников
данных (таблиц), указанных в предложении FROM. Тогда к ним можно обра-
щаться внутри запроса по новому имени.
Параметры сортировки задаются в предложении ORDER BY. В предложе-
нии можно перечислять несколько полей через запятую. Сортировка будет вы-
полняться сначала по первому полю, затем по второму (если совпадают значе-
ния первого поля) и т.п.
В предложении ORDER BY для каждого из столбцов может указываться
одно из ключевых слов, задающих направление сортировки – ASC (по возрас-
танию) или DESC (по убыванию). Если направление не указано, подразумева-
ется значение ASC.
Созданный запрос с точки зрения Access достаточно тривиален. Его можно
просмотреть в режиме конструктора (как уже говорилось, все запросы, создан-
ные в режиме конструктора могут быть представлены в режиме SQL, но не все,
созданные в режиме SQL, могут быть представлены в режиме конструктора).

Линия связи, соединяющая таблицы, помечена стрелкой. Это указывает на
то, что используется внешнее объединение, а не внутреннее.
Ограничение результирующих наборов. Оператор SELECT извлекает
данные из одной или нескольких таблиц и из всех возможных комбинаций ос-
тавляет только те, которые соответствуют заданным критериям отбора.
Можно считать, что при этом последовательно выполняются две основные
операции – умножение и сужение [5, 9 – 11, 13]. Умножение – построение
всех возможных комбинаций записей (декартово произведение таблиц). Су-
жение (его также называют выборкой, ограничением или селекцией) – отсече-
ние «лишних» комбинаций. Умножение выполняется в предложении FROM и
там же с помощью слова ON может быть выполнено предварительное сужение
(из всех комбинаций записей остаются только связанные между собой).
Для выполнения дальнейшего сужения в операторе SELECT могут присут-
ствовать еще два вида предложений: WHERE и HAVING.
Предложение WHERE <условие> располагается после предложения
FROM и позволяет наложить дополнительные ограничения на результат объе-
динения. Ограничения, заданные словом ON иногда могут быть перенесены
также в предложение WHERE.
Предложение HAVING <условие> может располагаться после предложе-
ния GROUP BY и применяться к данным каждой сформированной группы.
При использовании предложения HAVING без предложения GROUP BY, оно
применяется ко всей результирующей таблице и действует аналогично предло-
жению WHERE.
Пример 1.8. Дополним разработанный ранее запрос новыми ограничения-
ми.
SELECT Клиент.Фамилия, Count(Подписка.КодЖурнала) AS Количество
FROM Клиент LEFT JOIN Подписка
ON Клиент.КодКлиента = Подписка.КодКлиента
WHERELeft(Клиент.Фамилия,1) = "И" ANDПодписка.КодЖурнала > 1
GROUP BY Клиент.Фамилия
HAVINGCount(Подписка.КодЖурнала) > 0
ORDER BY Клиент.Фамилия ASC;
В предварительный результат (после предложения WHERE) входят записи
только для тех клиентов, фамилия которых начинается с «И» и при этом ис-
пользуются только журналы, коды которых больше «1». К сформированному
набору применяется операция группировки. Уже после группировки исключа-
ются те клиенты, у которых нет подписки (число выписанных журналов равно
«0»), при подсчете количества не учитывается информация о подписке на жур-
налы, исключенные ранее в предложении WHERE. То, что осталось, сортиру-
ется в алфавитном порядке.
Получившийся запрос не является оптимальным, он был составлен исклю-
чительно в демонстрационных целях. Например, способ объединения LEFT
JOIN используется для включения фамилий клиентов, которые не имеют под-
писки. Поскольку такие клиенты все равно гарантированно не попадут в ре-
зультирующий набор, вместо LEFT JOIN здесь вполне можно использовать
INNER JOIN.