Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка SQL(14) (оптимизация).docx
Скачиваний:
62
Добавлен:
17.03.2015
Размер:
452.16 Кб
Скачать

4.2.1 Простые вложенные подзапросы

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

Пример 25.

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

SELECT *

Результат

Блюдо

Продукт

Вес

18

5

10

18

6

30

18

8

140

18

14

15

18

16

15

FROM Соcтав

WHERE Блюдо = ( SELECT ID_блюда

FROM Блюда

WHERE Блюдо = 'Сырники');

Чтобы оценить внешний (основной) запрос, SQL сначала должен оценить внутренний запрос (или подзапрос) внутри предложения WHERE. Единственной найденной строкой естественно будет ID_блюда = 18. Однако SQL, не просто выдает это значение, а помещает его в предикат основного запроса вместо самого подзапроса, так чтобы предиката принял вид

WHERE Блюдо = 18

Основной запрос затем выполняется как обычно. Конечно же, подзапрос должен выбрать один и только один столбец, а тип данных этого столбца должен совпадать с тем значением, с которым он будет сравниваться в предикате. При использовании подзапросов в предикатах, основанных на операторах сравнения ( =, <>, < и т.д.), вы должны убедиться, что использовали подзапрос, который будет выдавать одну и только одну строку вывода (в некоторых случаях, можно использовать DISTINCT, чтобы вынудить подзапрос генерировать одиночное значение).

Если заменить условие WHERE Блюдо=’Сырники’ на условие WHERE Основа = 'Молоко’, мы получим в результате подзапроса несколько строк. Это сделает условие основного запроса невозможным для оценки, и команда выдаст ошибку. Если вы используете подзапрос, который не выводит никаких значений вообще, команда будет выполнена; но основной запрос не выведет никаких значений. Подзапросы, которые не производят никакого вывода (или нулевой вывод) вынуждают рассматривать предикат ни как верный, ни как неверный, а как неизвестный. Однако, неизвестный предикат имеет тот же самый эффект что и неверный: никакие строки не выбираются основным запросом.

Синтаксис использования простого подзапроса

< столбец | выражение > < оператор > < подзапрос >

Варианты < подзапрос > < оператор > < столбец | выражение > или, < подзапрос > < оператор > < подзапрос > недопустимы.

Если не удается построить подзапрос, возвращающий единственное значение необходимо использовать предикат IN.

Пример 26:

SELECT *

FROM Соcтав

WHERE Блюдо IN ( SELECT ID_блюда

FROM Блюда

WHERE Основа = 'Молоко');

При обработке полного запроса система выполняет, прежде всего, вложенный подзапрос. Этот подзапрос выдает множество номеров блюд, основой которых является молоко, а именно множество (7, 8, 12, 18, 22, 24, 28, 31). Поэтому первоначальный запрос эквивалентен такому простому запросу:

SELECT *

FROM Соcтав

WHERE Блюдо IN (7, 8, 12, 18, 22, 24, 28, 31);

Приведем пример запроса с несколькими уровнями вложенности:

Пример 27.

SELECT p.*, Количество, Цена

FROM Продукты p LEFT JOIN Наличие n ON p. ID_Продукта = n.Продукт

WHERE p.ID_Продукта IN (SELECT Продукт

FROM Соcтав

WHERE Блюдо IN ( SELECT ID_блюда

FROM Блюда

WHERE Основа = ’Молоко’) );

Результат

ID_Продукта

Про

дукт

Белки

Жиры

Угле

воды

К

Са

Na

B2

PP

C

Коли

чество

Цена

3

Масло

60

825

90

230

220

740

0,1

1

NULL

73

274,61

5

Яйца

127

115

7

1530

550

710

4,4

1,9

NULL

61

111,83

6

Сметана

26

300

28

950

850

320

1

1

2

88

206,60

7

Молоко

28

32

47

1460

1210

1500

1,3

1

10

214

83,80

8

Творог

167

90

13

1120

1640

1410

2,7

4

5

92

82,80

13

Рис

70

6

773

540

240

260

0,4

16

NULL

54

51,17

14

Мука

106

13

732

1760

240

120

1,2

22

NULL

91

43,77

15

Яблоки

4

NULL

113

2480

160

260

0,3

3

NULL

117

189,92

16

Сахар

NULL

NULL

998

30

20

10

NULL

NULL

130

98

96,14

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

В любой ситуации, где вы можете использовать реляционный оператор сравнения (=), вы можете использовать IN. В отличие от реляционных операторов, IN не может заставить команду потерпеть неудачу, если больше чем одно значение выбрано подзапросом. Заметим, что использование IN соответствует операции пересечения реляционной алгебры, а NOT IN разности.