Скачиваний:
25
Добавлен:
01.04.2014
Размер:
761.34 Кб
Скачать

112 Понимание sql

______________________________________________________________________

ГЛ. 10

Имея выбранным поле 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 ).

РАЗМЕЩЕНИЕ ЗАПРОСОВ ВНУТРИ ДРУГА ДРУГА 113

______________________________________________________________________

Имеется один способ чтобы сделать это ( вывод показывается в

Рисунке 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 предотвращает это.

Если наш подзапрос возвратит более одного значения, это будет указывать на

ошибку в наших данных - хорошая вещь для знающих об этом.

Соседние файлы в папке ПОНИМАНИЕ SQL