Основание и пример
Понякога нужните кортежи не могат да се получат с една заявка. Пример: таблица Успех (Име, Фамилия, Average). Търсим учениците с личен среден успех по-висок от средния за класа. Не можем да напишем директен SELECT — средният успех на класа не ни е известен предварително. Двете стъпки:
- Стъпка 1:
SELECT Avg(Average) FROM Успех;— една стойност X (средният успех на класа). - Стъпка 2:
SELECT * FROM Успех WHERE Average > X;
SQL позволява да заменим X направо с кода на първата заявка, затворена в кръгли скоби:
Ключово
SELECT * FROM Успех WHERE Average >
(SELECT Avg(Average) FROM Успех);
Механизмът е подобен на извикване на функция в израз: пресмята се стойността и замества извикването.
Внимание
Същото влагане работи и в DELETE: DELETE FROM Успех WHERE Average < (SELECT Avg(Average) FROM Успех); — изтрива слабите ученици. Не правете този експеримент с таблица, която ви е нужна!
Правилата на влагането
Влагане на заявки
Поставянето на една заявка на мястото на елемент на друга. Външна е заявката, в която влагаме; вътрешна — вложената (най-често SELECT).
- Вътрешната заявка е винаги в кръгли скоби.
- В клаузата WHERE на външната може да се използва резултат само с една колона; в клаузата FROM — таблица с няколко колони.
- Ако вътрешната връща колона с повече от един ред — в WHERE ползваме операциите за сравняване с множество:
IN,NOT IN,ANY,ALL. Иначе — само сравнение стойност със стойност. - Вътрешната заявка не може да бъде сортирана.
За ефективността
Влагане във влагане е допустимо, но конструкцията е сложна и не се препоръчва. Заявките с влагане не са много ефективни при големи таблици — избягвайте ги, ако могат да се заменят с умна употреба на JOIN.
Влагане в клаузата WHERE
IN / NOT IN
Бележка
SELECT Ученик.Фамилия FROM Ученик WHERE Ученик.Клас IN
(SELECT Клас FROM Учител WHERE [Фамилия на учител] = 'Иванов');
— фамилиите на всички ученици, на които преподава учителят Иванов. С NOT IN — на които НЕ преподава.
ANY и ALL
атрибут > ANY (вътрешна)— кортежите, в които стойността е по-голяма от някоя от извлечените.атрибут > ALL (вътрешна)— по-голяма от всички извлечени стойности.
Влагане в клаузата FROM
На мястото на таблицата във FROM може да застане цяла заявка — например резултатът от тройното INNER JOIN от предишния урок.
Най-важното правило
Когато влагаме SELECT във FROM и после извличаме стойности от атрибути на временната таблица — задаваме на тези атрибути наши имена с AS. Иначе SQL им поставя служебни имена, които не знаем и не можем да използваме във външната заявка.
Помисли (въпроси от учебника)
Имат ли смисъл заявките: SELECT * FROM (SELECT * FROM Успех WHERE Average >= 4.00) WHERE Average < 5.50; и SELECT * FROM (SELECT Име AS ИИме, Фамилия AS ФФамилия FROM Успех) WHERE Average >= 4.00; Първата се заменя с една заявка (AND); втората е грешна — Average не съществува във временната таблица!
Какво трябва да запомниш
- Влагане = заявка на мястото на елемент; вътрешната е винаги в кръгли скоби.
- В WHERE: една колона; един ред → сравнение, много редове → IN/NOT IN/ANY/ALL.
- Вътрешната заявка не се сортира.
- Във FROM: задължително AS имена на атрибутите, ползвани отвън.
- При големи таблици — предпочитай JOIN пред влагане.