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

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

Жанры

Понимание 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 также предохраняет вас от появления обеих значений при сравнении, которые нужно вывести с помощью подзапроса.

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

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

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

Вы не прошли собеседование

Олешкевич Надежда
1. Укротить миллионера
Любовные романы:
короткие любовные романы
5.00
рейтинг книги
Вы не прошли собеседование

Ученик. Книга третья

Первухин Андрей Евгеньевич
3. Ученик
Фантастика:
фэнтези
7.64
рейтинг книги
Ученик. Книга третья

Бастард Императора. Том 4

Орлов Андрей Юрьевич
4. Бастард Императора
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Бастард Императора. Том 4

Кодекс Охотника. Книга XII

Винокуров Юрий
12. Кодекс Охотника
Фантастика:
боевая фантастика
городское фэнтези
аниме
7.50
рейтинг книги
Кодекс Охотника. Книга XII

Хозяйка собственного поместья

Шнейдер Наталья
1. Хозяйка
Фантастика:
фэнтези
5.00
рейтинг книги
Хозяйка собственного поместья

Неудержимый. Книга XX

Боярский Андрей
20. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга XX

Законы Рода. Том 12

Flow Ascold
12. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Законы Рода. Том 12

Новый Рал 10

Северный Лис
10. Рал!
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Новый Рал 10

Как сбежать от дракона и открыть свое дело

Ардин Ева
Фантастика:
юмористическая фантастика
5.83
рейтинг книги
Как сбежать от дракона и открыть свое дело

Пограничная река. (Тетралогия)

Каменистый Артем
Пограничная река
Фантастика:
фэнтези
боевая фантастика
9.13
рейтинг книги
Пограничная река. (Тетралогия)

Комендант некромантской общаги 2

Леденцовская Анна
2. Мир
Фантастика:
юмористическая фантастика
7.77
рейтинг книги
Комендант некромантской общаги 2

Начальник милиции. Книга 3

Дамиров Рафаэль
3. Начальник милиции
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Начальник милиции. Книга 3

Черный Маг Императора 8

Герда Александр
8. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 8

Идеальный мир для Лекаря 6

Сапфир Олег
6. Лекарь
Фантастика:
фэнтези
юмористическая фантастика
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 6