Материал: Реляционная алгебра. Основы SQL

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

·        ALL - включает все строки, соответствующие указанным далее условиям отбора;

·        DISTINCT (ключевое слово из ANSI SQL-92) - исключает строки с повторяющимися данными на основе только данных результирующего набора записей;

Необязательный параметр TOP n [PERCENT] ограничивает количество записей в результирующей таблице первыми n или n% набора.

Оператор FROM определяет имена таблиц, из которых должны выбираться данные.

WHERE определяет условие для отбора записей и реализует реляционную операцию выборки. Условие задается текстовым оператором типа LIKE для текстовых полей или числовыми операторами типа >, <, =, < >, >=, BETWEEN для числовых полей. Если WHERE не использован, то запрос возвратит все записи, удовлетворяющие критерию SELECT.

Модификатор ORDER BY определяет порядок сортировки записей в созданной таблице. Ключевыми словами ASC и DESC можно определить сортировку по возрастанию или убыванию соответственно.

Пример инструкции запроса на выборку:


Результатом выполнения запроса будет новая таблица, содержащая два столбца Имя_Д и Вес и множество строк, удовлетворяющих условию Вес>500, отсортированных по убыванию веса.

2.4 Статистические функции

Статистические или агрегатные функции (итоговые в реляционной алгебре) используются тогда, когда необходимо определить статистические данные (сумму, среднее, минимальное, максимальное и т.п.) группы записей с общим значением атрибута. Для этого используется инструкция GROUP BY:

SELECT статистическая функция (имя поля) AS заголовок поля [, список полей]

FROM имена таблиц

[WHERE условие отбора]

GROUP BY условие группировки

[HAVING условие для результата]

[ORDER BY столбцы сортировки];

Поле, используемое как аргумент статистической функции, должно содержать данные числового типа.

Ключевое слово AS определяет заголовок столбца результирующего набора записей. GROUP BY определяет столбец, по значениям которого записи объединяются в группы, к которым применяется статистическая функция и возвращает одно значение. HAVING позволяет ввести одно или несколько условий, налагаемых на значение результирующего столбца, полученного в результате группировки и применения статистической функции.

Примеры команд SQL, применяющих статистические функции:

Общее количество деталей можно получить следующим образом:

SUM(Поставки.Кол) FROM Поставки;

В предложении SELECT можно указывать несколько скалярных выражений:

SELECT MIN(Кол), MAX(Кол), SUM(Кол), AVG(Кол) FROM Поставки;

Такие запросы возвращают в качестве результата таблицу, состоящую из одной строки.

Количество кортежей в отношении можно посчитать следующим образом:

SELECT COUNT (*) AS Кол_кортежей FROM Поставки;

В результате получим таблицу из одной строки с заголовком “Кол_кортежей”.

Статистические функции можно применять как ко всем кортежам отношения, так и к отдельным группам кортежей. Для того, чтобы получить, например, количество деталей, поставляемых каждым поставщиком, применяется оператор GROUP BY. В возвращенной таблице количество строк будет равно количеству поставщиков и результаты будут сгруппированы по одинаковым значениям атрибута группировки:

SELECT Пк.ПN, SUM(Пк.Кол)Поставки AS ПкBY Пк.ПN;

(Здесь показан пример использования псевдонимов, которые вводятся в предложении FROM при помощи оператора AS (его можно и пропустить). Использование псевдонимов упрощает запись команд. Они также используются и для организации некоторых запросов.)

В предложении SELECT необходимо указывать атрибут, по которому производится группировка и нельзя указывать имена атрибутов, не входящих в предложение GROUP BY (но можно указывать несколько статистических функций).

На создаваемые оператором GROUP BY результаты можно накладывать ограничения оператором HAVING, например:

SELECT Пк.ПN, SUM (Пк.Кол)Поставки AS ПкBY Пк.ПNCOUNT(*)>2;

Предложение HAVING COUNT(*)>2 выделяет только те группы, в которых количество кортежей больше 2 (поставщики выполнили более 2 поставок).

2.5 Создание соединений

Реляционная операция произведения двух отношений TIMES реализуется в SQL, если указать имена этих отношений в предложении FROM:

* FROM Проекты, Поставки;

Если дополнить эту команду предложением WHERE, сравнивающим значения атрибутов этих отношений, то будет реализована реляционная операция соединения JOIN: Например, соединение отношений Проекты и Поставки:

* Проекты, ПоставкиПроекты.ПрN=Поставки.ПрN;

Подобным образом можно соединить произвольное число отношений:

SELECT DISTINCT П.Имя_П, Д.Имя_Д, Пр.Имя_Пр, Пк.КолПоставщики П, Детали Д, Проекты Пр, Поставки Пк

WHERE Д.ДN=Пк.ДN

AND П.ПN=Пк.ПN

AND Пр.ПрN=Пк.ПрN

AND Пк.Кол>500;

Такое соединение выполняется с конца. Сначала из таблицы Поставки удаляются строки со значениями поля Кол менее или равным 500. Затем соединяются кортежи отношения Поставки с теми кортежами отношения Проекты, у которых совпадают значения атрибута ПрN. После этого кортежи созданного представления соединяются с кортежами отношения Поставщик, у которых совпадают значения атрибута ПN. Далее, полученные кортежи соединяются с кортежами отношения Детали, у которых совпадают значения атрибута ДN.

Для организации соединений между таблицами и их объединения может быть использован и оператор JOIN…ON, который указывает на подключаемую таблицу и связь между полями:

SELECT список полей

FROM имя таблицы {INNER/LEFT/RIGHT} JOIN связанная таблица

ON условие связи

[WHERE условие отбора]

[ORDER BY столбцы сортировки];

В приведенной инструкции показано, как оператор JOIN окружен именами двух связываемых таблиц, причем вместо правого имени может использоваться повторно конструкция JOIN … ON, называемая вложенной: [имя таблицы {INNER/LEFT/RIGHT} JOIN связанная таблица ON условие связи]. В этом случае первая таблица соединяется с соединением второй и третьей таблиц. Инструкция SQL может содержать набор нескольких вложенных конструкций JOIN … ON. Их число обычно равно общему количеству таблиц, включенных в запрос, минус один. Перед оператором JOIN должен быть указан тип соединения:

·        INNER - соединяет записи из двух таблиц, если связующие поля этих таблиц содержат одинаковые значения;

·        LEFT (RIGHT) - соединяет записи исходных таблиц, причем левое внешнее соединение включает все записи из первой (левой) таблицы и присоединяет к ним записи из второй таблицы, если связующие поля содержат одинаковые значения. Правое внешнее соединение включает все записи из второй (правой) таблицы и присоединяет к ним записи из первой таблицы, если связующие поля содержат одинаковые значения.

Конструкция ON условие связи позволяет описать два поля и связь между ними (одно поле в таблице связанная таблица, второе - в таблице имя таблицы). В выражении условие связи присутствует оператор сравнения значений полей, который возвращает значения True или False. Если значение выражения True, то объединенная запись включается в результирующий набор.

Пример инструкции на соединение отношений Проекты и Поставки базы данных Проекты-Поставщики-Детали по значениям полей ПрN, присутствующим в обоих отношениях:

SELECT DISTINCT Пр.Имя_Пр, Пр.Гор, Пк.ДN, Пк.Кол(Проекты Пр INNER JOIN Поставки Пк)

ON Пр.ПрN=Пк.ПрN;

Соединения представляют собой мощный инструмент для организации сложных запросов. Например, соединение таблицы самой с собой позволяет формировать всевозможные комбинации пар. Допустим, надо узнать, какие детали поставляются несколькими поставщиками. Соединение таблицы Поставки с таблицей Поставки по значению поля ДN даст всевозможные пары поставщиков:

SELECT F.ПN, S.ПN, F.ДNПоставки AS F, Поставки AS SF.ДN=S.ДN;

В результате выполнения этой команды будет создано представление, фрагмент которого показан на рисунке.

F.ПN

S.ПN

F.ДN

П1

П1

Д1

П1

П1

Д1

П1

П5

Д1

П1

П1

Д1

П1

П1

Д1

П1

П5

Д1

П5

П1

Д1

П5

П1

Д1

П5

П5

Д1

...

...

...


Добавив условие выборки

AND F.ПN <> S.ПN

убираем строки, содержащие одинаковые номера поставщиков. Модификатор DISTINCT удалит повторяющиеся кортежи. Если бы в полях F.ПN и S.ПN были данные числового типа, то условие выборки AND F.ПN < S.ПN позволило бы получить ответ без последующих операций.

Выбрав проекцию F.ДN, получим список деталей, поставляемых несколькими поставщиками.

2.6 Вложенные запросы

Вложенные запросы - это применение одного запроса к результирующему набору записей другого. Для этой цели создается запрос SELECT, в котором для формирования условия предложения WHERE используется еще один запрос SELECT. Такие конструкции могут существенно повысить производительность работы базы данных.

Синтаксис записи вложенных запросов:

SELECT список полей

FROM список таблиц

WHERE [имя таблицы.] имя поля

                   IN (SELECT оператор выборки

                            [GROUP BY условие группировки]

                            [HAVING условие отбора]

[ORDER BY столбцы сортировки]);

Пример: Найти номера поставщиков, поставляющих хотя бы одну черную деталь.

SELECT Пк.ПN FROM Поставки Пк

WHERE Пк.ДN IN

                   (SELECT Д.ДN FROM Детали Д

                            WHERE Д.Цвет='Черный');

Механизм действия вложенного запроса такой. Внутренний запрос вложен во внешний запрос, который последовательно сравнивает значения своего атрибута (Пк.ДN) с возвращенным внутренним запросом множеством этих же атрибутов (Д.ДN). Если рассматриваемый атрибут внешнего запроса есть в указанном множестве, то будет возвращен выбранный в предложении SELECT атрибут (Пк.ПN).

Чтобы в нашем примере найти имена поставщиков, надо добавить еще один вложенный запрос:

SELECT П.Имя_П FROM Поставщики П

WHERE П.ПN IN

                   (SELECT Пк.ПN FROM Поставки Пк

                   WHERE Пк.ДN IN

                            (SELECT Д.ДN FROM Детали Д

                            WHERE Д.Цв='Черный'));

Такой же результат можно получить при помощи операции соединения:

SELECT DISTINCT П.Имя_П

FROM Поставщики П, Поставки Пк, Детали Д

WHERE П.ПN=Пк.ПN

                   AND Пк.ДN=Д.ДN

                   AND Д.Цв='Черный';

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

SELECT * FROM Поставщики П

WHERE П.ПN NOT IN

                   (SELECT Пк.ПN FROM Поставки Пк);

Вложенные запросы могут применять статистические функции, причем, как во внешнем, так и во внутреннем запросах.

2.7 Запрос на объединение

Запросы на объединение реализуют реляционную операцию UNION и позволяют представить в одной таблице записи, созданные несколькими запросами на выборку, записав их один под другим. Синтаксис запроса на объединение, основой которого является оператор UNION, имеет вид:

SELECT оператор выборки

UNION

SELECT оператор выборки

                   [GROUP BY условие группировки]

                   [HAVING итоговое условие]

[UNION

SELECT оператор выборки

                   [GROUP BY условие группировки]

                   [HAVING итоговое условие]]

[UNION

…]

[ORDER BY столбцы сортировки];

При использовании операторов UNION необходимо задавать одинаковый набор имен полей в списке отбираемых полей, причем, их последовательность должна быть одинакова в каждом предложении UNION SELECT. Модификатор ORDER BY может быть использован только один раз в инструкции за последним оператором UNION SELECT. При необходимости в каждый оператор SELECT и UNION SELECT можно вложить операторы GROUP BY и HAVING. Оператор UNION удаляет из результирующей таблицы все строки-дубликаты. Чтобы это не происходило, используют оператор UNION ALL.

Синтаксис оператора UNION позволяет собирать в одном поле объединенной таблицы значения из различных доменов:

SELECT Имя_П AS Наименование

         FROM Поставщики

         WHERE Гор=’Минск’

UNION SELECT Имя_Пр AS Наименование

         FROM Проекты

         WHERE Гор=’Минск’;

Результатом запроса будет таблица из одного столбца, названного «Наименование», содержащая поставщиков, находящихся в Минске, и проектов, выполняемых в Минске.

2.8 Запросы, выполняющие реляционные операции вычитания, пересечения и деления

В некоторых модификациях языка SQL, например, используемой в СУБД Oracle, реляционная операция пересечения отношений выполняется оператором INTERSECT, который возвращает только те строки, которые присутствуют в обеих таблицах. Вычитание отношений реализуется оператором EXCEPT, который возвращает строки первой таблицы за исключением тех, которые присутствуют и во второй таблице. Как и в случае оператора UNION, обрабатываемые таблицы должны иметь одинаковый набор и последовательность имен полей. В СУБД Access эти операции могут быть реализованы при помощи оператора EXISTS.

Оператор EXISTS в предложении WHERE выполняет проверку на существование данных, которые удовлетворяют критериям соответствующего вложенного запроса, и возвращает булево значение «истина» или «ложь».

Пример. Найти имена поставщиков, которые поставляют деталь Д1:

SELECT DISTINCT П.Имя_П FROM Поставщики AS ПEXISTS

(SELECT * FROM Поставки AS Пк

                   WHERE Пк.ПN=П.ПN

                            AND Пк.ДN='Д1');

Для каждого кортежа отношения Поставщики, которое обрабатывается во внешнем запросе, для вложенного запроса будет возвращено значение “истина”, если существует хотя бы один кортеж в отношении Поставки с тем же значением П№, который рассматривает внешний запрос. Чтобы это определить, выполняется соединение по Пк.П№=П.П№. Во вложенном запросе используется предложение SELECT *, но можно указать имя любого атрибута, т.к. этот вложенный запрос возвращает не данные, а значение истинности.

Чтобы получить имена поставщиков, которые не поставляют деталь Д1, можно использовать отрицание предложения EXISTS:

SELECT DISTINCT П.Имя_П FROM Поставщики AS ПNOT EXISTS

(SELECT * FROM Поставки AS ПК

                   WHERE ПК.ПN=П.ПN

                            AND ПК.ДN='Д1');

Пример решения задачи двумя способами - с оператором EXISTS и без него: Найти номера деталей, поставляемых поставщиком из города, название которого начинается на букву М.

I. SELECT DISTINCT Пк.ДN FROM Поставки AS Пк WHERE Пк.ПN IN (SELECT П.ПN FROM Поставщики AS П WHERE П.Гор LIKE 'М*');. SELECT DISTINCT Пк.Д№ FROM Поставки Пк WHERE EXISTS (SELECT * FROM Поставщики П WHERE П.П№ = Пк.П№ AND Гор LIKE ′М*′);

Если надо указать имя детали, т.е. получить сведения из 3-й таблицы, то команда SQL выглядит так:

SELECT DISTINCT Д.Имя_Д FROM Детали AS ДEXISTS

(SELECT DISTINCT Пк.ДN FROM Поставки AS Пк

                   WHERE EXISTS

                   (SELECT * FROM Поставщики AS П