один раз вкладений підзапит і одержати список номерів постачальників, що поставляють деталь номер 2.
Просканувати таблицю постачальників P, кожного разу перевіряючи, чи міститься номер постачальника в результаті підзапиту.
Приклад 27. Використання предиката EXIST. Одержати список постачальників, що поставляють деталь номер 2:
SELECT *
FROM P
WHERE EXIST
(SELECT *
FROM PD
WHERE
PD.PNUM = P.PNUM AND
PD.DNUM = 2);
Зауваження. Результат виконання запиту буде еквівалентний результату наступної послідовності дій:
Просканувати таблицю постачальників P, кожного разу виконуючи підзапит з новим значенням номера постачальника, узятим з таблиці P.
У результат запиту включити тільки ті рядки з таблиці постачальників, для яких вкладений підзапит повернув непорожню безліч рядків.
Зауваження. На відміну від двох попередніх прикладів, вкладений підзапит містить параметр (зовнішнє посилання), передаваний з основного запиту - номер постачальника P.PNUM. Такі підзапити називаються корельованими (correlated). Зовнішнє посилання може приймати різні значення для кожного рядка-кандидата, оцінюваного за допомогою підзапиту, тому підзапит повинен виконуватися наново для кожного рядка, відбираного в основному запиті. Такі підзапити характерні для предиката EXIST, але можуть бути використані і в інших підзапитах.
Зауваження. Може показатися, що запити, що містять корельовані підзапити виконуватимуться повільніше, ніж запити з некорельованими підзапитами. Насправді це не так, оскільки те, як користувач, сформулював запит, не визначає, як цей запит виконуватиметься. Мова SQL є непроцедурною, а декларативним. Це значить, що користувач, що формулює запит, просто описує, яким повинен бути результат запиту, а як цей результат буде одержаний - за це відповідає сама СУБД.
Приклад 28. Використання предиката NOT EXIST. Одержати список постачальників, що не поставляють деталь номер 2:
SELECT *
FROM P
WHERE NOT EXIST
(SELECT *
FROM PD
WHERE
PD.PNUM = P.PNUM AND
PD.DNUM = 2);
Зауваження. Також як і в попередньому прикладі, тут використовується корельований підзапит. Відмінність в тому, що в основному запиті будуть відібрані ті рядки з таблиці постачальників, для яких вкладений підзапит не видасть жодного рядка.
Приклад 29. Одержати імена постачальників, що поставляють всі деталі:
SELECT DISTINCT PNAME
FROM P
WHERE NOT EXIST
(SELECT *
FROM D
WHERE NOT EXIST
(SELECT *
FROM PD
WHERE
PD.DNUM = D.DNUM AND
PD.PNUM = P.PNUM));
Зауваження. Даний запит містить два вкладені підзапити і реалізує реляційну операцію розподілу відносин.
Самий внутрішній підзапит параметризується двома параметрами (D.DNUM, P.PNUM) і має наступний сенс: відібрати всі рядки, що містять дані про поставки постачальника з номером PNUM деталі з номером DNUM. Заперечення NOT EXIST говорить про те, що даний постачальник не поставляє дану деталь. Зовнішній до нього підзапит, що сам є вкладеним і параметризувався параметром P.PNUM, має сенс: відібрати список деталей, які не поставляються постачальником PNUM. Заперечення NOT EXIST говорить про те, що для постачальника з номером PNUM не повинно бути деталей, які не поставлялися б цим постачальником. Це в точності означає, що в зовнішньому запиті відбираються тільки постачальники, що поставляють всі деталі.
Використання об'єднання, перетини і різниці
Приклад 30. Одержати імена постачальників, що мають статус, більший 3 або поставляючих хоча б одну деталь номер 2 (об'єднання двох підзапитів - ключове слово UNION):
SELECT P.PNAME
FROM P
WHERE P.STATUS > 3
UNION
SELECT P.PNAME
FROM P, PD
WHERE P.PNUM = PD.PNUM AND
PD.DNUM = 2;
Зауваження. Результуючі таблиці об'єднуваних запитів повинні бути сумісні, тобто мати однакову кількість стовпців і однакові типи стовпців в порядку їх переліку. Не вимагається, щоб об'єднувані таблиці мали б однакові імена колонок. Це відрізняє операцію об'єднання запитів в SQL від операції об'єднання в реляційній алгебрі. Найменування колонок в результуючому запиті будуть автоматично узяті з результату першого запиту в об'єднанні.
Приклад 31. Одержати імена постачальників, що мають статус, більший 3 і одночасно поставляючих хоча б одну деталь номер 2 (перетин двох підзапитів - ключове слово INTERSECT):
SELECT P.PNAME
FROM P
WHERE P.STATUS > 3
INTERSECT
SELECT P.PNAME
FROM P, PD
WHERE P.PNUM = PD.PNUM AND
PD.DNUM = 2;
Приклад 32. Одержати імена постачальників, що мають статус, більший 3, за винятком тих, хто поставляє хоча б одну деталь номер 2 (різниця двох підзапитів - ключове слово EXCEPT):
SELECT P.PNAME
FROM P
WHERE P.STATUS > 3
EXCEPT
SELECT P.PNAME
FROM P, PD
WHERE P.PNUM = PD.PNUM AND
PD.DNUM = 2;
Синтаксис оператора вибірки даних (SELECT)
BNF-нотация
Опишемо синтаксис оператора вибірки даних (оператора SELECT) більш точно. При описі синтаксису операторів звичайно використовуються умовні позначення, відомі як стандартні форми Бекуса-Наура (BNF).
У BNF позначеннях використовуються наступні елементи:
Символ "::=" означає рівність за визначенням. Зліва від знаку стоїть визначуване поняття, справа - власне визначення поняття.
Ключові слова записуються прописними буквами. Вони зарезервовані і складають частину оператора.
Мітки-заповнювачі конкретних значень елементів і змінних записуються курсивом.
Необов'язкові елементи оператора укладені в квадратні дужки [].
Вертикальна межа | указує на те, що всі попередні їй елементи списку є необов'язковими і можуть бути замінені будь-яким іншим елементом списку після цієї межі.
Фігурні дужки {} указують на те, що що все знаходиться усередині них є єдиним цілим.
Трикрапка "." означає, що попередня частина оператора може бути повторена будь-яка кількість раз.
Багатокрапка, усередині якої знаходиться кома ".,.." указує, що попередня частина оператора, що складається з декількох елементів, розділених комами, може мати довільне число повторень. Кому не можна ставити після останнього елементу. Зауваження: дана угода не входить в стандарт BNF, але дозволяє більш точно описати синтаксис операторів SQL.
Круглі дужки є елементом оператора.
Синтаксис оператора вибірки
У досить сильно спрощеному вигляді оператор вибірки даних має наступний синтаксис (для деяких елементів ми дамо не BNF-визначення, а словесний опис):
Оператор вибірки ::=
Табличний вираз
[ORDER{{Ім'я стовпця-результату [ASC | DESC]} | {Позитивне ціле [ASC | DESC]}}.,..];
Табличний вираз ::=
Select-вираз
[
{UNION | INTERSECT | EXCEPT} [ALL]
вираз