4.4.2. Инструкция SELECT

Все запросы на получение практически любого количества данных из одной или нескольких таблиц выполняются с помощью единственного предложения SELECT. В общем случае результатом реализации предложения SELECT является другая таблица (но в общем случае набор кортежей, а не отношение, так как здесь в таблице могут быть одинаковые строки - то есть в этом пункте таблица и отно - шение - разные понятия). В этой новой (рабочей) таблице может быть снова применена операция SELECT и т.д., т.е. такие операции могут быть вложены друг в друга. Представляет исторический интерес тот факт, что именно возможность включения одного предложения SELECT внутрь другого послужила мотивировкой использования прилагательного "структуризированный" в названии языка SQL. В тоже время, к сожалению, не во всех реализациях допускается вложенность запросов.

Детально изучить синтаксис команды Select, можно используя [4, 14, 24, 36]. Здесь же рассмотрим существенные элементы синтаксиса (используется форма Бэкуса-Науэра, подробнее см. [5]).

<cursor specification>:=<query expression>[<order by clause>]

<query expression>:=<query term>|(<query expression>UNION[ALL]<query term>)

<query term>:=<query specification>|<query expression>

<query specification>:=SELECT[ALL|DISTINCT]<select list><table expression>

<table expression>:=<from clause>[<where clause>][<group by clause><having clause>]

 

Поясним используемые термины.

1.          <cursor specification> - есть спецификация курсора. Курсор - этот средство языка SQL, позволяющее получить последовательный доступ к результату запроса в БД. Дело в том, что многие реализации SQL позволяют производить навигационные операции с курсорами.

2.          <query expression> - выражение запроса

3.          <order by clause> - инструмент для упорядочивания кортежей в курсоре (результате).

4.          <query term> - элементарная логическая единица запроса. Запрос мо­жет состоять из нескольких термов, связанных операцией объединения UNI­ON. Каждый терм может состоять из более мелких термов, и т.д. <query specification> - это терм самого низкого уровня, представляющий из себя оператор SELECT. Здесь указывается <select list> - список атрибу­тов, которые войдут в результат, т.е. SELECT здесь не только отбирает записи согласно табличному выражению <table expression>, а еще и выбирает только нужные атрибуты, т.е. выполняется проекция, однако в ходе нее ду­бликаты по умолчанию не удаляются; если же их надо удалить, то необходи­мо указать ключевое слово DISTINCT, в этом случае проекция будет работать также, как и в реляционной алгебре. Табличное выражение <table ex­pression^ по сути, есть условие для отбора. Оно содержит <from clause>, представляющим собой ключевое слово FROM и источник, это мо­жет быть либо отношение из БД, либо спецификация другого курсора. Также надо указывать переменную, по которой затем можно будет обращаться к ис­точнику.

Итак, <from clause>:=FROM (<relation name>|<cursor spe- cifcation>) <variable>

Необязательные элементы <where clause>, <having clause> и <group by clause> служат для задания дополнительных условий на выбирае - мые кортежи.

<where clause> состоит из ключевого слова WHERE и логического усло­вия на отбираемые данные, логическое условие состоит из операторов сравнения (>,<,=,<>,>=,<=) и проверок на принадлежность курсору или на вхождение одного курсора в другой (IS IN).;

<groub by close> и <having by close> используются для задания условий не на один конкретный атрибут, а сразу на группу атрибутов, которые указываются после ключевого слова GROUP. Затем следует ключевое слово HAV­ING после которого следует условие, причем можно использовать только те име­на атрибутов, которые указаны в GROUP BY, а остальные только в функциях аг­регирования (min - минимум, max - максимум, avg - среднее значение, ^unt - ко­личество, sum - сумма).

На практике, конструкции языка SQL удобнее изучать на примерах, так как, несмотря на сложный синтаксис, в большинстве случаев применяются достаточно простые запросы.

Пример 1. Найти всех преподавателей старше 40 лет

Приведем запрос в двух формах - с использованием короткого псевдонима для именования таблицы и без использования псевдонима:

A)    SELECT * FROM ПРЕПОДАВАТЕЛИ P WHERE Г.возраст>4 0

B)   SELECT * FROM ПРЕПОДАВАТЕЛИ WHERE ПРЕПОДАВАТЕЛИ.возраст>4 0

Поскольку запрос работает только с одной таблицей, допустимо и отсут­ствие имени таблицы (отношения).

SELECT * FROM ПРЕПОДАВАТЕЛИ WHERE возраст>4 0

 

Пример 2. Определим декана ФМФ

SELECT фио_декана FROM ФАКУЛЬТЕТЫ WHERE назв_фак='ФМФ'

Обратим внимание, что в этом случае фактически выполняется 2 операции реляционной алгебры - проекция и селекция.

Пример 3. Выбрать преподавателей ФМФ (все атрибуты), получающих зар­плату больше 15000 р. и отсортировать их по фамилиям.

Рассмотрим несколько вариантов реализации запроса.

A)   Использование операции соединения в запросе явным образом

SELECT P.id, P-ФИО, P-возраст, P-стаж FROM

ПРЕПОДАВАТЕЛИ P INNER JOIN БЫТЬ_СОТР B INNER JOIN КАФЕДРЫ K INNER

JOIN ФАКУЛЬТЕТЫ F)

ON ( (P.id=B.id_преп)AND(B.id_каф=K.id)AND(K.id_фак=F.id)

WHERE (F.названйе='ФМФ')AND(в7з/п>15000)          _

ORDER BY P.ФИО

Примечание.

1. Операция JOIN предполагает вычисление произведения таблиц, а операция INNER JOIN - соединение, при этом возможно либо указать с помощью конструкции USING столбцы, ко¬торый присутствует в двух или более таблицах (в этом случае условие соединения - равен¬ство значений в этом столбце в обоих таблицах) , или с помощью конструкции ON (в этом случае указывается в явном виде условие объединения), как в нашем примере.
2. В запросах можно использовать возможность определения кратких псевдонимов, как в на¬шем примере, или использовать непосредственно имена таблиц.
3. В случае отсутствия одинако-именованных атрибутов, вообще говоря имена таблиц перед именами атрибутов можно не уточнять, однако в связи с высокой вероятностью путаницы в сложных запросах все таки рекомендуется это делать.
 

B)   Использование соединения в автоматическом режиме (запрос к нескольким таблицам)

SELECT P.id, P-ФИО, P-возраст, P-стаж FROM ПРЕПОДАВАТЕЛИ P,

БЫТЬ_СОТР B, КАФЕДРЫ K, ФАКУЛЬТЕТЫ F WHERE (P.id=B.id_преп)AND(B.id_каф=K.id)AND (K.id_фак=F.id)AND(F. название=' ФМФ')АШ(В. з/п>15000)

ORDER BY P.ФИО

C)   Использование вложенных конструкций

SELECT * FROM ПРЕПОДАВАТЕЛИ WHERE id IS IN (

SELECT id_преп FROM БЫТЬ_СОТР WHERE (з/п>2000) AND (id_^ IS IN (

SELECT id_каф FROM КАФЕДРЫ WHERE id_фак IS IN (

SELECT id FROM ФАКУЛЬТЕТЫ WHERE назв='ФМФ'

)ORDER BY ФИО

Пример 4. Вычислить средний возраст преподавателей.

 Используется функция агрегирования AVG.

SELECT AVG(возраст) FROM ПРЕПОДАВАТЕЛИ

Пример 5. Определить названия тех кафедр, на которых работает более 15 преподавателей.

Используется функция агрегирования COUNT.

SELECT назв. каф FROM (КАФЕДРЫ JOIN БЫТЬ_СОТР ON id=id_каф) GROUP BY id_каф HAVING C0UNT(ФИ0_преп)>15

 

Пример 6. Вычислить число преподавателей на каждой кафедре.

Здесь следует использовать функцию агрегирования COUNT внутри HAV­ING.

SELECT назв_каф, C0UNT(ФИ0_преп) FROM (КАФЕДРЫ JOIN БЫТЬ_СОТР ON id=id_каф) GROUP BY id_каф

Из примеров 4-6 видно, что, в отличие от реляционной алгебры, SQL позво­ляет в рамках оператора выборки фактически одновременно производить манипулирование выбранными данными, т.е. выполняются операции реляционной алгебры над исходными отношениями и операции над содержимым результирующих таблиц, что предполагает скрытые навигационые возможности.

В стандартном SQL также присутствует механизм курсоров, явно реализую­щий построчный доступ к результатам запроса, что делает SQL одновременно спецификационным и навигационным языком.

Более подробно с возможностями выборки данных в SQL можно ознакомит­ся в [4, 14, 24, 36]. Возможности конкретных реализаций SQL следует изучать по документации соответствующих сред.