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

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

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 П

                            WHERE П.ПN=Пк.ПN

                                      AND Гор LIKE 'М*')

                                      AND Д.ДN=П.ДN);

Покажем, как при помощи оператора EXISTS можно реализовать операции пересечения, разности и деления.

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

SELECT DISTINCT Д.Гор FROM Детали AS ДEXISTS

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

                   WHERE Д.Гор=П.Гор);

Разностью между этими таблицами по полю Гор является множество городов, в которых есть детали, но нет поставщиков:

SELECT DISTINCT Д.Гор FROM Детали ДNOT EXISTS

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

                   WHERE Д.Гор=П.Гор);

Операция пересечения может быть реализована и без оператора EXISTS:

SELECT DISTINCT Д.Гор FROM Детали Д(SELECT COUNT (*) FROM Поставщики П

                   WHERE Д.Гор = П.Гор) >0;

(если количество найденных строк больше 0, значит они есть и оператор EXISTS принял бы значение “истина”).

При таком запросе производительность ниже, чем при использовании EXISTS, т.к. EXISTS возвращает результат, как только ему встретится хотя бы одна строка, удовлетворяющая условию, а COUNT (*) подсчитывает строки, просматривая таблицу до конца.

Пример реализации реляционной операции деления DIVIDED BY: Получить номера поставщиков, поставляющих все детали

SELECT DISTINCT Пк.ПNПоставки AS ПкNOT EXISTS

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

                   WHERE NOT EXISTS

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

                            WHERE Пк1.ПN=Пк.ПN

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

Внешний запрос исследует каждый кортеж отношения Поставки и возвращает из него ПN, если вложенный запрос возвращает значение «Ложь». Вложенный запрос создает множество всех возможных значений ДN из отношения Детали. Из этого множества удаляются те значения ДN, которые состоят в паре с ПN в кортеже с тем же значением ПN, что и кортеж, рассматриваемый во внешнем запросе. Если рассматриваемый ПN комбинируется со всеми возможными значениями ДN, то результатом будет пустое множество и вложенный запрос возвратит значение «Ложь», т.е., не существует значений ДN, которые не состоят в паре с этим конкретным ПN.

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

SELECT П.Имя_ППоставщики AS ПП.ПN IN

(SELECT DISTINCT Пк.ПNПоставки AS ПкNOT EXISTS

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

                   WHERE NOT EXISTS

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

                            WHERE Пк1.ПN=Пк.ПN

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

2.9 Запросы на изменение

Запросы на изменение предназначены для добавления, удаления или обновления записей, а также для создания таблиц.

Синтаксис запроса на добавление записей:

INSERT INTO таблица-получатель

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

FROM таблица-источник;

Если в инструкции на добавление отсутствует предложение WHERE, то в таблицу-получатель будут добавлены все записи таблицы-источника.

Синтаксис запроса на удаление записей:

DELETE FROM имя таблицы [WHERE условие удаления];

В этой инструкции предложение WHERE также не обязательное. При его отсутствии из указанной таблицы будут удалены все записи.

Синтаксис запроса на создание таблицы:

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

INTO новая таблица

FROM исходная таблица

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

Полную копию исходной таблицы можно создать, указав вместо списка полей символ * и не используя предложение WHERE.

Запрос на обновление используется для присвоения новых значений отдельным столбцам при помощи операторов UPDATE и SET:

 имя таблицы

SET имя_поля_1=значение [,имя_поля_2=значение[,…]]

[WHERE условие обновления];

2.10 Перекрестные запросы

Перекрестные запросы позволяют создавать различные итоговые запросы, использующие статистические функции SQL. Когда данные группируются с помощью перекрестного запроса, можно выбирать значения из заданных полей или выражений как заголовки столбцов. Это позволяет просматривать данные в более компактной форме, чем при работе с запросом на выборку. <JavaScript:hhobj_3.Click()> Для организации перекрестных запросов используются операторы Jet-SQL TRANSFORM и PIVOT:

Источник: https://www.bibliofond.ru/view.aspx?id=869454