Чтение онлайн

на главную - закладки

Жанры

Понимание SQL

Грубер Мартин

Шрифт:

Таблица 10.1: Использование подзапроса

Основной запрос затем выполняется как обычно с вышеупомянутыми результатами. Конечно же, подзапрос должен выбрать один и только один столбец, а тип данных этого столбца должен совпадать с тем значением с которым он будет сравниваться в предикате. Часто, как показано выше, выбранное поле и его значение будут иметь одинаковые имена(в этом случае, snum), но это необязательно.

Конечно, если бы мы уже знали номер продавца Motika, мы могли бы просто напечатать

WHERE snum=1004

и выполнять далее с подзапросом в целом, но это было бы не так универсально.

Это будет продолжать работать даже если номер Motika изменился, а, с помощью простого изменения имени в подзапросе, вы можете использовать его для чего угодно.

ЗНАЧЕНИЯ, КОТОРЫЕ МОГУТ ВЫДАВАТЬ ПОДЗАПРОСЫ

Скорее всего было бы удобнее, чтобы наш подзапрос в предыдущем примере возвращал одно и только одно значение.

Имея выбранным поле 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 - это первичный ключ таблицы Заказчика, запрос выбирающий его должен произвести только одно значение. Это рационально только если вы как пользователь имеете доступ к таблице Порядков но не к таблице Заказчиков. В этом случае, вы можете использовать решение которое мы показали выше. (SQL имеет механизмы которые определяют - кто имеет привилегии чтобы делать что-то в определенной таблице. Это будет объясняться в Главе 22.) Пожалуйста учтите, что методика используемая в предшествующем примере применима только когда вы знаете, что два различных поля в таблице должны всегда совпадать, как в нашем случае. Эта ситуация не является типичной в реляционных базах данных, она являеться исключением из правил.

ПРЕДИКАТЫ С ПОДЗАПРОСАМИ ЯВЛЯЮТСЯ НЕОБРАТИМЫМИ

Вы должны обратить внимание что предикаты включающие подзапросы, используют выражение

< скалярная форма > < оператор > < подзапрос >, а не

< подзапрос > < оператор > < скалярное выражение > или,

< подзапрос > < оператор > < подзапрос >.

Другими словами, вы не должны записывать предыдущий пример так:

SELECT *

FROM Orders

WHERE (SELECT DISTINCT snum

FROM Orders

WHERE cnum=2001 )

=snum;

В строгой ANSI реализации, это приведет к неудаче, хотя некоторые программы и позволяют делать такие вещи. ANSI также предохраняет вас от появления обеих значений при сравнении, которые нужно вывести с помощью подзапроса.

ИСПОЛЬЗОВАНИЕ АГРЕГАТНЫХ ФУНКЦИЙ В ПОДЗАПРОСАХ

Один тип функций, который автоматически может производить одиночное значение для любого числа строк, конечно же, - агрегатная функция.

Поделиться:
Популярные книги

Гобелены Фьонавара (сборник)

Кей Гай Гэвриел
Гобелены Фьонавара
Фантастика:
фэнтези
эпическая фантастика
6.25
рейтинг книги
Гобелены Фьонавара (сборник)

Фавориты Фортуны

Маккалоу Колин
3. Мастер из Рима
Проза:
историческая проза
7.86
рейтинг книги
Фавориты Фортуны

Повелитель. Тетралогия

Седых Александр Иванович
1. Повелитель
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
6.17
рейтинг книги
Повелитель. Тетралогия

Чистилище

Кастнер Йорг
Фантастика:
ужасы и мистика
6.40
рейтинг книги
Чистилище

Хроники Максима. Трилогия

Бадей Сергей
Фантастика:
юмористическое фэнтези
8.26
рейтинг книги
Хроники Максима. Трилогия

Приключения Гаррета. том.2

Кук Глен Чарльз
Фантастика:
фэнтези
6.80
рейтинг книги
Приключения Гаррета. том.2

"Фантастика 2024-120". Компиляция. Книги 1-24

Сухов Лео
Фантастика 2024. Компиляция
Фантастика:
героическая фантастика
боевая фантастика
попаданцы
альтернативная история
фэнтези
5.00
рейтинг книги
Фантастика 2024-120. Компиляция. Книги 1-24

Газлайтер. Том 20

Володин Григорий Григорьевич
20. История Телепата
Фантастика:
боевая фантастика
аниме
попаданцы
5.25
рейтинг книги
Газлайтер. Том 20

Генрик Сенкевич. Собрание сочинений. Том 6-7

Сенкевич Генрик
6. Собрание сочинений в девяти томах
Проза:
историческая проза
5.00
рейтинг книги
Генрик Сенкевич. Собрание сочинений. Том 6-7

История Европы. Том 1. Древняя Европа

Коллектив авторов
Научно-образовательная:
история
5.00
рейтинг книги
История Европы. Том 1. Древняя Европа

Золотое руно (сборник)

Сойер Роберт Джеймс
Шедевры фантастики
Фантастика:
научная фантастика
5.00
рейтинг книги
Золотое руно (сборник)

Простолюдин

Рокотов Алексей
1. Путь князя
Фантастика:
боевая фантастика
рпг
5.25
рейтинг книги
Простолюдин

Жемчужница

Anice and Jennifer
Фантастика:
фэнтези
5.00
рейтинг книги
Жемчужница

Долг

Кораблев Родион
7. Другая сторона
Фантастика:
боевая фантастика
5.60
рейтинг книги
Долг