Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СУБД Особливості мови SQL.doc
Скачиваний:
4
Добавлен:
16.08.2019
Размер:
651.78 Кб
Скачать

3412 Поляків Анатолій Олексійович

В даному прикладі внутрішній запит, як і в попередньому варіанті, повідомляє, що студент отримав декілька оцінок. Зовнішній запит - це об'єднання таблиць успішності і студентів. Нова пропозиція основного предиката, що з'явилася, AND FIRST.SNUM = SECOND.SNUM оцінюється на тому ж самому рівні, що і пропозиція EXISTS, т.к. це елемент предиката самого об'єднання двох таблиць із зовнішнього запиту.

З урахуванням того, що EXISTS може працювати в комбінації з булевими операторами, найбільш очевидним способом його використовування є поєднання з оператором NOT. Наприклад, для отримання інформації про студентів, що мають тільки одну оцінку, можна скористатися наступним запитом:

SELECT DISTINCT FIRST.SNUM, FIRST.SFAM

FIRST.SIMA, FIRST.SOTCH

FROM STUDENTS FIRST, USP SECOND

WHERE NOT EXISTS

(SELECT *

FROM USP THIRD

WHERE SECOND.SNUM = THIRD.SNUM

AND SECOND.PNUM < > THIRD. PNUM)

AND FIRST.SNUM = SECOND.SNUM;

Висновок цього запиту приведений нижче:

SNUM SFAM SIMA' SOTCH

3413 Огарева Любов Михайлівна

3414 Гріценко Володимир Миколайович

3416 Нагірний Євгеній Васильович

Важливою властивістю EXISTS є та. що він не може узяти агрегатну функцію в підзапиті, т.к. якщо агрегатна функція знайшла які-небудь записи для операцій з ними, то EXISTS буде вірний в жодному разі. Виходом з такої ситуації є використовування вкладеного підзапиту в підзапиті, в предикаті якого присутній EXISTS. Це дозволяє ретельно структурувати запити, роблячи їх більш зрозумілими. Повертаючись наприклад із знаходженням інформації про студентів, що мають більше однієї оцінки, можна запропонувати такий варіант запиту:

SELECT *

FROM STUDENTS FIRST

WHERE EXISTS (SELECT *

FROM USP SECOND

WHERE FIRST.SNUM = SECOND.SNUM AND 1 <

(SELECT COUNT (*)

FROM USP

WHERE USP.SNUM = SECOND.SNUM));

В результаті буде отримано:

SNUM SFAM SIMA SOTCH STIP

3412 Поляків Анатолій Олексійович 25.50

Така конструкція працює таким чином: зовнішній запит вибирає з таблиці студентів STUDENTS поточний рядок і виконує підзапити. Для поточного рядка середнім запитом береться у відповідність кожний рядок з таблиці успішності USP. Всякий раз, коли виявляється інформація в середньому запиті, який співпадає по номеру студентського квитка з поточним рядком в зовнішньому запиті. SQL повинен розглядати внутрішній підзапит для того, щоб визначити, чи буде предикат середнього запиту вірний. Внутрішній запит рахує кількість оцінок поточного студента, і, якщо це число більше, ніж 1. робить предикат середнього запиту вірним. Це. у свою чергу, робить EXISTS-предикат зовнішнього запиту вірним для поточного рядка таблиці.

Таким чином, не дивлячись на уявну простоту, EXISTS може виявитися одним з найважчих з погляду використовування операторів в SQL. Існує ще три спеціальні оператори, орієнтуються на підзапити - це ANY. ALL і SOME, нагадуючі EXISTS, які сприймають підзапити, як аргументи. Проте ці оператори відрізняються від EXISTS тим, що використовуються спільно з реляційними операторами, аналогічно IN в підзапитах

Оператори SOME і ANY достатньо часто взаємозамінні, і в наших прикладах будуть працювати однаково. Відмінність в термінології полягає в тому, щоб дозволити користувачам використовувати той термін, який найбільш однозначний. Тому все сказане щодо ANY в рівному ступені відноситься і до SOME.

Розглянемо наступний спосіб знаходження студентів, які одержували оцінки по різних учбових предметах:

SELECT *

FROM STUDENTS WHERE SNUM = ANY

(SELECT SNUM FROM USP) ;

Висновок цього запиту приведений нижче:

SNUM SFAM SIMA SOTCH STIP

  1. Поляків Анатолій Олексійович 25.50

  2. Огарева Любов Михайлівна 17.00

3414 Гріценко Владимир Миколайович 0.00 3416 Нагірний Євгеній Васильович 25.50

Оператор ANY бере всі значення, виведені підзапитом, тобто в прикладі - всі значення поля SNUM, і оцінює їх як вірні, якщо будь-яке з їхнє дорівнює номеру студентського квитка поточного рядка зовнішнього запиту. Звідси витікає, що підзапит повинен вибирати значення такого ж типу, як і ті, які порівнюються в основному предикаті. В цьому його відмінність від EXISTS, який просто визначає, чи виробляє висновок підзапит чи ні. фактично не використовуючи ці результати.

Взагалі кажучи, у ряді випадків припускає використовування операторів IN або EXISTS замість оператора ANY. Наприклад, використовуючи оператор IN, можна створити запит, аналогічний попередньому:

SELECT *

FROM STUDENTS WHERE SNUM IN (SELECT SNUM FROM USP);

Висновок цього запиту такий, як в попередньому прикладі, по цьому приводити його не будемо.

Цікавий той факт, що оператор ANY може використати інші реляційні оператори, за виключенням дорівнює, і. таким чином, реалізовувати порівняння, які неприступні з IN Наприклад, можна виконати наступний запит:

SELECT PNAME

FROM PREDMET

WHERE HOURS > ANY (SELECT HOURS FROM PREDMET);

Результат цього запиту наступний:

PNAME

Фізика

Хімія

Математика

Тут виводяться назва учбових предметів, для яких існує хоча б одна учбова дисципліна з кількістю годинника, меншою, ніж в поточної.

У принципі, цей же запит може бути реалізований з використанням EXISTS, таким чином:

SELECT PNAME

FROM PREDMET FIRST

WHERE EXISTS

(SELECT *

FROM PREDMET SECOND

WHERE FIRST.HOURS > SECOND.HOURS);

В жодному разі запит, який може бути реалізований з ANY і ALL, може бути також сформульований з EXISTS, але не навпаки. Щоправда у ряді випадків, через відмінності в обробці NULL значень, варіант з EXISTS не абсолютно ідентичний, чим при використовуванні ANY, тому необхідно в таких випадках застосовувати команду IS NULL.

Основна перевага у використовуванні ANY і ALL в порівнянні з EXISTS полягає в тому, що останній вимагає співвіднесених підзапитів, деколи складних для розуміння. Крім того, підзапит ANY або ALL можуть виконуватися один раз і мати висновок, використовуваний для визначення предиката для кожного рядка основного запиту EXISTS вимагає, щоб весь підзапит повторно виконувався для кожного рядка основного запиту.

Оператор ALL працює таким чином, що предикат є вірним, якщо кожне значення, вибране підзапитом, задовольняє умові в предикаті зовнішнього запиту.

Наприклад, якщо необхідно вивести тільки тих студентів, чиї оцінки вище або рівні отриманим 10/06/1999, то можна скористатися наступним запитом:

SELECT * FROM USP

WHERE OCENKA >= ALL (SELECT OCENKA FROM USP WHERE UDATE = 10/06/1999);

Висновок цього запиту такий:

UNUM OCENKA UDATE SNUM PNUM

1001 5 10/06/1999 3412 2001

1005 5 12/06/1999 3416 2004

Запит працює так: підзапит перевіряє значення оцінок за 10/06/1999 для всіх студентів. Потім він знаходить студентів з оцінкою більшій або рівній в порівнянні з оцінками за 10/06/1999. Оскільки найвища оцінка цього дня - відмінне, то вибираються тільки запису з оцінкою 5.

Як і у випадку з ANY, припускає використати EXISTS для альтернативного формулювання такого ж запиту:

SELECT *

FROM USP FIRST

WHERE EXISTS (SELECT *

FROM USP SECOND

WHERE FIRST.OCENKA >= SECOND.OCENKA AND SECOND.UDATE = 10/06/1999);

Основне застосування ALL знаходить із знаком нерівності, т.к. предикат може бути вірним, якщо порівнюване значення рівне для всіх, тобто всі записи, фактично, ідентичні. Наприклад, запит

SELECT *

FROM USP

WHERE OCENKA = ALL

(SELECT OCENKA FROM USP WHERE UDATE = 10/06/1999) ;

є допустимим, але висновок буде тільки у випадку, якщо всі оцінки за 10/06/1999 виявляться ідентичними. Ймовірно, не дуже добре використати запити, які працюють тільки в певних ситуаціях.

Проте ALL набагато більш ефективно використовується із знаком нерівності, тобто з оператором < >. При цьому обов'язково треба ураховувати, що якщо підзапит повертає багато різних значень, то це означає нерівність будь-якому результату. Інакше кажучи, предикат вірний, якщо дане значення не знайдено серед результатів підзапиту. Розглянемо такий запит:

SELECT *

FROM USP

WHERE OCENKA < > ALL

(SELECT OCENKA

FROM USP WHERE UDATE = 10/06/1999) ;

Висновок цього запиту такий:

UNUM OCENKA UDATE SNUM PNUM

1003 3 11/06/1999 3414 2005

• Даний запит зробить наступне: підзапит вибере всі оцінки за 10/06/1999 - це будуть 5 і 4. Після цього, основний запит виведе всі записи з оцінкою, не співпадаючою ні з однією з них. Аналогічний запит можна сформулювати з використовування оператора NOT IN:

SELECT *

FROM USP

WHERE OCENKA NOT IN

(SELECT OCENKA FROM USP

WHERE DАТЕ = 10/06/1999); або використовуючи оператор ANY:

SELECT *

FROM USP

WHERE NOT OCENKA = ANY

(SELECT OCENKA

FROM USP WHERE UDATE = 10/06/1999);

Висновок цих запитів такий же, як і першого. Таким чином, в SQL дати запит на порівняння з використанням команди ANY для набору значень - то ж саме, що виробити порівняння з будь-яким окремим значенням з набору. Якщо запитати значення за допомогою команди ALL, не рівні набору значень, то це те ж саме, що визначити факт відсутності цього значення у всьому наборі.

Як вже було сказано, є деякі відмінності між EXISTS і операторами ANY і ALL з погляду роботи з невідомими і відсутніми даними. Крім того, важливе різниця між ALL і ANY - це спосіб дії за ситуації, коли підзапит не повертає ніяких значень. Взагалі кажучи, у всіх випадках, коли допустимий підзапит не робить висновку, ALL автоматично повертає значення ІСТИНА, ANY -ЛОЖЬ. Наприклад, це означає, що запит:

SELECT *

FROM USP

WHERE OCENKA >= ANY

(SELECT OCENKA

FROM USP WHERE UDATE = 10/06/2000);

не виробить ніякого висновку, тоді як запит

SELECT *

FROM USP

WHERE OCENKA >= ALL

(SELECT OCENKA

FROM USP

WHERE UDATE = 10/06/2000) ;

виведе всю таблицю USP. Дійсно, якщо немає ніяких оцінок за 10/06/2000 те, природне, жодне з цих порівнянь не має значення.

NULL значення мають свої особливості при їхній обробці цими операторами. Коли SQL порівнює два значення в предикаті, одне з яких NULL, очевидне, результат цього невідомий. Невідомий предикат, аналогічно невірному, є причиною того, що запис не вибирається, проте працювати він буде трохи інакше, залежно від того, використовується ALL або ANY. Розглянемо попередній приклад з ANY і такий запит:

SELECT *

FROM USP FIRST

WHERE EXISTS

(SELECT *

FROM USP SECOND

WHERE FIRST.OCENKA > = SECOND.OCENKA

AND SECOND.UDATE = 10/06/1999);

Поки NULL значень в таблиці немає, обидва запити буде поводитися однаково. Але у разі появи NULL значення в полі OCENKA таблиці успішності, у варіанті з ANY значення предиката при обробці цього рядка стане невідомим і висновку для неї не буде в жодному разі, проте інші рядки будуть оброблятися звичайним способом. У варіанті з EXISTS, значення NULL використовується в предикаті підзапиту, роблячи його невідомим в кожному випадку, а це означає, що підзапит не буде не виробляти ніяких значень, і запит не виробить висновку взагалі. Це є важливим чинником на користь використовування варіанту з ANY.

Таким чином, підзапити найпростіше, що є в SQL, проте вони є одним з наймогутніших засобів цієї мови. Як правило, припускає виконувати той же запит з підзапитами декількома способами, і. кінець кінцем, користувачу вирішувати, яким варіантом скористатися.