Якщо вам потрібен був список нових службовців, що надійшли за останній квартал в організацію, то ви можете написати запит у такому вигляді:
SELECT ENAME, HIREDATE, HIREDATE + 92 DAYS
FROM EMPLOYEE
WHERE HIREDATE + 92 DAYS > SYSDATE AND DEPNO=30;
Ключове слово SYSDATE завжди повертає поточну дату. У цьому прикладі також показано, як використовуються арифметичний оператор додавання зі змінними типу "дата". До змінного типу "дата" можна додавати й віднімати з нього ціле число днів, місяців, років, годин, хвилин, секунд, мікросекунд. Для цього використаються відповідні ключові слова (DAY, MONTH і т.д.), що випливають за цілою константою (дробова частина ігнорується, якщо ви вказуєте число з десятковою крапкою). Є обмеження на використання дужок у таких вираженнях (так, висновок у дужки вираження 1 DAYS + 1 YEARS приведе до помилки).
У мові SQL передбачені такі оператори агрегатних функцій:
AVG(X) = AVG(ALL X) AVG(DISTINCT X) Обчислює середнє значення аргументу, що може бути виразом будь-якого типу. Нуль-значення ігноруються, ключове слово DISTINCT придушує дублікати.
COUNT(*) COUNT(X) = COUNT(ALL X) COUNT(DISTINCT X) Обчислює числа ітемів. При вказівці * завжди повертається число рядків у таблиці. Вказівка DISTINCT придушує дублікати.
MAX(X) = MAX(ALL X) MAX (DISTINCT X) Обчислює максимальне значення аргументу, що може бути виразом будь-якого типу. Нуль-значення ігноруються, ключове слово DISTINCT придушує дублікати.
MIN(X) = MIN(ALL X) MIN (DISTINCT X) Обчислює мінімальне значення аргументу, що може бути виразом будь-якого типу. Нуль-значення ігноруються, ключове слово DISTINCT придушує дублікати.
SUM(X) = SUM(ALL X) SUM (DISTINCT X) Обчислює суму значення аргументу, що може бути виразом будь-якого типу. Нуль-значення ігноруються, ключове слово DISTINCT придушує дублікати.
STDDEV([DISTINCT|ALL]X) Обчислює стандартне відхилення на безлічі значень аргументу, що може бути виразом будь-якого типу. Нуль-значення ігноруються, ключове слово DISTINCT придушує дублікати.
VARIANCE([DISTINCT|ALL]) Обчислює квадрат дисперсії.
Приклад. Одержати загальну кількість постачальників (ключове слово COUNT):
SELECT COUNT(*) AS N
FROM P;
У результаті одержимо таблицю з одним стовпцем й одним рядком, що містить кількість рядків з таблиці P.
Приклад. Одержати загальну, максимальну, мінімальну й середню кількості деталей, що поставляють, (ключові слова SUM, MAX, MIN, AVG):
SELECT SUM(PD.VOLUME) AS SM,
MAX(PD.VOLUME) AS MX,
MIN(PD.VOLUME) AS MN,
AVG(PD.VOLUME) AS AV FROM PD;
В результаті одержимо таку таблицю з одним рядком:
2000 1000 100 333. 33333333
Приклад. Для кожної деталі одержати сумарну кількість, що поставляється (ключове слово GROUP BY…):
SELECT..DNUM, SUM(PD.VOLUME) AS SM
GROUP BY PD.DNUM;
Цей запит буде виконуватися в такий спосіб. Спочатку рядки вихідної таблиці будуть згруповані так, щоб у кожну групу потрапили рядки з однаковими значеннями DNUM. Потім усередині кожної групи буде просумовано поле VOLUME. Від кожної групи до результуючої таблиці буде включений один рядок.
У переліку полів оператора SELECT, який містить розділ GROUP BY можна включати тільки агрегатні функції й поля, які входять в умову групування. Наступний запит видасть синтаксичну помилку:
SELECT PD.PNUM, PD.DNUM,
SUM(PD.VOLUME) AS SM
GROUP BY PD.DNUM;
Причина помилки у тому, що у перелік полів, які відбираються, включене поле PNUM, що не входить у розділ GROUP BY. І дійсно у кожну отриману групу рядків може входити кілька рядків із різними значеннями поля PNUM. З кожної групи рядків буде сформовано по одному підсумковому рядку. При цьому немає однозначної відповіді на питання, яке значення вибрати для поля PNUM у підсумковому рядку.
Деякі діалекти SQL не вважають це за помилку. Запит буде виконаний, але передбачити, які значення будуть внесені у поле PNUM у результуючій таблиці, неможливо.
Приклад. Одержати номери деталей, сумарна кількість поставки яких перевершує 400 (ключове слово HAVING…).
Умова, що сумарна кількість поставки повинна бути більше 400, не може бути сформульована у розділі WHERE, тому що в цьому розділі не можна використовувати агрегатні функції. Умови, що використовують агрегатні функції повинні бути розміщені у спеціальному розділі HAVING:
SELECT PD.DNUM, SUM(PD.VOLUME) AS SM
GROUP BY PD.DNUM
HAVING SUM(PD.VOLUME) > 400;
В одному запиті можуть зустрітися як умови відбору рядків у розділі WHERE, так й умови відбору груп у розділі HAVING. Умови відбору груп не можна перенести з розділу HAVING у розділ WHERE. Аналогічно й умови відбору рядків не можна перенести з розділу WHERE у розділ HAVING, за винятком умов, що включають поля зі списку угруповання GROUP BY.
Дуже зручним засобом, що дозволяє формулювати запити більш зрозумілим чином, є можливість використання підзапитів, вкладених в основний запит.
Приклад. Одержати список постачальників, статус яких менше максимального статусу у таблиці постачальників (порівняння з підзапитом):
SELECT *
FROM P
WHERE P.STATYS < (SELECT MAX(P.STATUS) FROM P;
Тоді як поле P.STATUS рівняється з результатом підзапиту, то підзапит повинен бути сформульований так, щоб повертати таблицю, що складається рівно з одного рядка й однієї колонки.
Результат виконання запиту буде еквівалентний результату такої послідовності дій:
1. Виконати один раз вкладений підзапит й одержати максимальне значення статусу.
2. Просканувати таблицю постачальників P, щоразу порівнюючи значення статусу постачальника з результатом підзапиту, і відібрати тільки ті рядки, у яких статус менше максимального.
Приклад. Використання предиката IN. Одержати перелік постачальників, що поставляють деталь номер 2:
SELECT *
FROM P
WHERE P.PNUM IN (SELECT DISTINCT PD.PNUM FROM PD WHERE PD.DNUM = 2);
У цьому випадку вкладений підзапит може повертати таблицю, що містить кілька рядків.
Результат виконання запиту буде еквівалентний результату такої послідовності дій:
1. Виконати один раз вкладений підзапит й одержати список номерів постачальників, що поставляють деталь номер 2.
2. Просканувати таблицю постачальників P, щораз перевіряючи, чи втримується номер постачальника в результаті підзапиту.
Приклад. Використання предиката EXIST. Одержати перелік постачальників, що поставляють деталь номер 2:
SELECT *
FROM P
WHERE EXIST (SELECT *
FROM PD
WHERE PD.PNUM = P.PNUM AND PD.DNUM = 2);
Результат виконання запиту буде еквівалентний результату такої послідовності дій:
1. Просканувати таблицю постачальників P, щоразу виконуючи підзапит із новим значенням номера постачальника, узятим із таблиці P.
2. У результат запиту включити тільки ті рядки з таблиці постачальників, для яких вкладений підзапит повернув непусту множину рядків.
На відміну від двох попередніх прикладів, вкладений підзапит містить параметр (зовнішнє посилання), переданий з основного запиту - номер постачальника P.PNUM. Такі підзапити називаються корельованими (correlated). Зовнішнє посилання може приймати різні значення для кожного рядка-кандидата, оцінюваного за допомогою підзапиту, тому підзапит повинен виконуватися заново для кожного рядка, який відбирається в основному запиті. Такі підзапити характерні для предиката EXIST, але можуть бути використані й в інших підзапитах.
Може здатися, що запити, які містять корельовані підзапити будуть виконуватися повільніше, ніж запити з некорельованими підзапитами. Насправді це не так, тому що те, як користувач сформулював запит, не визначає, як цей запит буде виконуватися. Мова SQL є не процедурною, а декларативною. Це значить, що користувач, який формулює запит, просто описує, яким повинен бути результат запиту, а як цей результат буде отриманий - за це відповідає сама СКБД.
Приклад. Використання предиката NOT EXIST. Одержати перелік постачальників, що не поставляють деталь номер 2:
SELECT *
FROM P
WHERE NOT EXIST (SELECT *
FROM PD
WHERE PD.PNUM = P.PNUM AND PD.DNUM = 2);
Також як й у попередньому прикладі, тут використовується корельований підзапит. Відмінність у тому, що в основному запиті будуть відібрані ті рядки з таблиці постачальників, для яких вкладений підзапит не видасть ні одного рядка.
Приклад. Одержати імена постачальників, що поставляють всі деталі:
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 не повинно бути деталей, які не поставлялися б цим постачальником. Це в точності означає, що в зовнішньому запиті відбираються тільки постачальники, що поставляють всі деталі.
Приклад. Одержати імена постачальників, що мають статус, більший 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 від операції об'єднання у реляційній алгебрі. Найменування колонок у результуючому запиті будуть автоматично взяті з результату першого запиту в об'єднанні.