Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ПЛЕЩ.docx
Скачиваний:
47
Добавлен:
13.05.2015
Размер:
3.97 Mб
Скачать

1.8.3.3. Вложенные и коррелированные запросы

С помощью SQL можно вкладывать запросы внутрь друг друга. Обычно внутренний (вложенный) запрос генерирует значение, которое проверяется в условии внешнего запроса (в фразе WHERE или HAVING), определяющего, верно оно или нет. Совместно с подзапросом можно использовать предикат EXISTS, который возвращает истину, если вывод подзапроса не пуст. Подзапрос заключается в круглые скобки.

Пример. Вывести крупные стройки со сметой выше средней по стройкам:

SELECT * FROM Stroiki WHERE Ss > (SELECT AVG(Ss) FROM Stroiki).

Пример. Вывести из базы «Сессия» список тех, кто сдал все положенные экзамены.

SELECT ФИО

FROM R1

WHERE Оценка > 2

GROUP BY ФИО

HAVING COUNT(*) = (SELECT COUNT(*)

FROM R2, R3

WHERE R2.Группа=R3.Группа AND R2.ФИО=R1.ФИО)

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

Особенностью этого запроса является то, что в подзапросе используется поле (R1.ФИО) таблицыR1, которая указана во внешнем запросе. Такой подзапрос называетсякоррелированным. В этом случае подзапрос выполняется для каждой текущей записи таблицыR1 (что может существенно увеличить время выполнения всего запроса – подза*прос будет выполняться для каждого студента; лучшим решением является оформление подзапроса в форме представления, в котором выводятся число всех экзаменов по группам). Например, если первая запись таблицыR1 содержит значения: Иванов, Информатика и 4, то выполнится подзапрос, в котором будут связаны таблицыR2 иR3 по полюГруппав которой учится Иванов (можно заметить, что связь таблицR1 иR2 по полюФИОне допускает полных тезок, лучше связывать по учетным номерам студентов). В результате, определится число экзаменов в группе, в которой учится Иванов и далее, выполнится группировка по Иванову и посчитается число положительных оценок за экзамены и если это число совпадет с числом экзаменов по группе, то фамилия Иванова выведется в результирующую таблицу запроса.

Можно заметить, что фразы FROMиWHEREможно написать более современно, используя фразу установки связи между таблицами –JOIN:

FROM R2, R3 INNER JOIN ON (R2.Группа=R3.Группа)

WHERE R2.ФИО=R1.ФИО

1.8.3.4. Запросы, использующиеExist, any, all

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

Ключевое слово ANY означает, что предикат будет истинен, если хотя бы для одного значения из подзапроса предикат сравнения истинен.

Ключевое слово ALL требует, чтобы предикат сравнения был бы истинен при сравнении со всеми строками подзапроса.

Пример. Вывести список тех, кто должен был сдавать экзамен по БД, но пока еще не сдавал.

SЕLЕСТ ФИО

FROM R2 a, R3

WHERE R2.Fpynna=R3.Группа AND Дисциплина = "БД" AND NOT EXISTS

(SELECT ФИО FROM Rl WHERE ФИО=а.ФИО AND Дисциплина = "БД")

Пример. Вывести студентов, которые сдали все экзамены на оценку не ниже чем «хорошо»:

SELECT R1.ФИО FROM R1 WHERE 4 > = ALL

(SELECT R1.Оценка FROM R1 AS R11 WHERE R1.ФИО = R11.ФИО)

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

SELECT R1.ФИО

FROM R1 WHERE R1.Оценка >= ANY

(SELECT R4.Оценка FROM R4

WHERE R1.Дисциплина = R4. Дисциплина AND R1.ФИО = R4.ФИО)

Пример.Выдать фамилии поставщиков, которые поставляют деталь P2.SELECT ФАМИЛИЯ FROM S WHERE EXISTS (SELECT * FROM SP WHERE

НОМЕР_ПОСТАВЩИКА=S.НОМЕР_ПОСТАВЩИКА

AND НОМЕР_ДЕТАЛИ = 'P2');

Пример. Выдать фамилии поставщиков, которые не поставляют деталь Р2.

SELECT ФАМИЛИЯ FROM S WHERE NOT EXIST (SELECT * FROM SP WHERE НОМЕР_ПОСТАВЩИКА=S.НОМЕР_ПОСТАВЩИКА AND НОМЕР_ДЕТАЛИ = 'Р2');

Пример. Выдать фамилии поставщиков, которые поставляют вседетали.

SELECT ФАМИЛИЯ FROM S WHERE NOT EXISTS (SELECT * FROM P WHERE NOT EXISTS

(SELECT * FROM SP WHERE НОМЕР_ПОСТАВЩИКА= S.НОМЕР_ПОСТАВЩИКА AND НОМЕР_ДЕТАЛИ= Р.НОМЕР_ДЕТАЛИ));