Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lab_4.doc
Скачиваний:
2
Добавлен:
21.11.2019
Размер:
142.85 Кб
Скачать

Значення, які підзапит може виводити

Швидше за все, було б зручніше, щоб наш підзапит в попередньому прикладі повертав одно, і тільки одно, значення.

Маючи вибране поле snum " WHERE city = "London" замість "WHERE sname = 'Motika", можна отримати декілька різних значень. Це може зробити в предикаті основного запиту неможливим оцінку вірності або невірності, і команда видасть помилку.

При використанні підзапитів в предикатах, заснованих на реляційних операціях (рівняннях або нерівностях, як пояснено в главі 4), ви повинні переконатися, що використовували підзапит, який видаватиме одну, і тільки одну, рядок виводу. Якщо ви використовуєте підзапит, який не виводить ніяких значень взагалі, команда не потерпить невдачі, але основний запит не виведе ніяких значень. Підзапити, які не проводять ніякого виводу (чи нульовий вивід), змушують розглядати предикат ні як вірний, ні як невірний, а як невідомий. Проте невідомий предикат має той же самий ефект, що і невірний: ніякі рядки не вибираються основним запитом (дивися в главі 5 детальну інформацію про невідомий предикат).

Ось приклад поганої стратегії :

SELECT *

FROM Orders

WHERE snum =

(SELECT snum

FROM Salespeople

WHERE city = Barcelona);

Оскільки ми маємо тільки одного продавця в Barcelona - Rifkin, то підзапит вибиратиме поодиноке значення snum, і, отже, буде прийнятий. Але це тільки в даному випадку. Більшість БД SQL мають численних користувачів, і, якщо інший користувач додасть нового продавця з Barcelona в таблицю, підзапит вибере два значення, і ваша команда потерпить невдачу.

Distinct з підзапитами

В деяких випадках ви можете використовувати DISTINCT щоб змусити підзапит генерувати поодиноке значення. Припустимо що ми хочемо знайти усі порядки кредитування для тих продавців, які обслуговують Hoffman 'а (cnum = 2001).

Ось спосіб зробити це (висновок показаний на Малюнку 10.2) :

SELECT *

FROM Orders

WHERE snum =

(SELECT DISTINCT snum

FROM Orders

WHERE cnum = 2001);

=============== SQL Execution Log ==============

| |

| SELECT * |

| FROM Orders |

| WHERE snum = |

| (SELECT DISTINCT snum |

| FROM Orders |

| Where cnum = 2001); |

| =============================================== |

| onum amt odate cnum snum |

| ----- --------- --------- ------ ------- |

| 3003 767.19 10/03/1990 2001 1001 |

| 3008 4723.00 10/05/1990 2006 1001 |

| 3011 9891.88 10/06/1990 2006 1001 |

================================================

Малюнок 10.2 Використання DISTINCT для набуття одного значення з підзапиту

Підзапит встановив, що значення поля snum співпало з Hoffman - 1001, а потім основний запит виділив усі замовлення з цим значенням snum з таблиці Замовлень (не розбираючи, відносяться вони до Hoffman або ні). Оскільки кожен замовник призначений продавцеві, ми знаємо, що кожен рядок в таблиці Замовлень з цим значенням cnum повинен мати таке ж значення snum. Проте, оскільки там може бути будь-яке число таких рядків, підзапит міг би вивести багато (хоча і ідентичних) значень snum для цього поля cnum. Аргумент DISTINCT запобігає цьому. Якщо наш підзапит поверне більше за одне значення, це вказуватиме на помилку в наших даних - хороша річ для тих, що знають про це.

Має бути і альтернативний підхід, щоб посилатися до таблиці Замовників, а не до таблиці Замовлень в підзапиті. Оскільки поле cnum це первинний ключ таблиці Замовників, запит, що вибирає його, повинні видати тільки одно значення. Це раціонально, тільки якщо ви як користувач маєте доступ до таблиці Замовлень, але не до таблиці Замовників. В цьому випадку ви можете використовувати рішення, яке ми показали вище.

Будь ласка, врахуйте, що методика, використовувана в попередньому прикладі, застосовна, тільки коли ви знаєте, що два різні поля в таблиці повинні завжди співпадати, як в нашому випадку. Ця ситуація не є типовою в реляційних базах даних (РБД), вона є виключенням з правил.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]