Подзапросы

 

Поддержка подзапросов, впервые реализованная в PostgreSQL версии 6.3, существенно повысила гибкость команд SQL. Подзапросом называется команда SELECT, заключенная в круглые скобки, которая выполняется в контексте другой команды SQL. Подзапросы чаще используются для возвращения одной записи, но они также могут использоваться для определения подмножества записей.

Подзапросы могут находиться практически в любой части команды SQL — в списке целей, в секции WHERE и т. д. В листинге 4.59 приведен простой пример использования подзапроса для выборки критерия поиска из другой таблицы.

Листинг 4.59. Простой подзапрос

booktown=# SELECT title FROM books

30oktown-# WHERE author_id = (SELECT id FROM authors)

booktown(# WHERE last_name=’Geisel’

booktown(# AND first_name=’Theodor Seuss’);

title

The Cat in the Hat

Bartholomew and the Oobleck

(2 rows)

Оператор = сравнивает поле id подзапроса к таблице authors с полем author_id габлицы books. Подзапрос находит в таблице authors запись об авторе с именем c<Theodor Seuss» и фамилией «Geisel»; сравнивая поле id этой записи с полем Author_id таблицы books, мы отбираем все книги, написанные этим автором.

Построение подзапросов требует осторожности: чтобы результат запроса проверялся простым оператором, подзапрос должен возвращать только одну запись. Например, если использовать для выборки кода автора более общий запрос, возвращающий несколько записей, PostgreSQL выдаст сообщение об ошибке:

booktown=# SELECT title FROM books

booktown-# WHERE authoMd = (SELECT id FROM authors

booktown(# WHERE last_name ` ‘G’);

ERROR: More than one tuple returned by a subselect used as an expression.

Обычные операторы не могут сравнивать отдельную величину с несколькими шачениями, поэтому сравнение поля authoMd с несколькими полями приводит к ошибке. Проблема легко решается включением в подзапрос секции LIMIT 1, благодаря которой подзапрос никогда не вернет более одной записи.

Если требуется проверить присутствие отдельной величины в заданном наборе, замените оператор = ключевым словом IN. Подзапрос, приведенный в листинге 4.60, выбирает несколько значений, сравниваемых с полем author_id (для авторов, имена которых начинаются с букв А-Е). Сравнение осуществляется при юмощи ключевого слова IN. Средства поиска по регулярному выражению рассматриваются в разделе «Операторы» главы 5.

Листинг 4.60. Подзапрос с ключевым словом IN

booktown=# SELECT title FROM books

booktown-# WHERE authorjd IN (SELECT id FROM authors

booktown(# WHERE last_name — ‘»[A-E]’);

title

2001: A Space Odyssey

Franklin in the Dark

Goodnight Moon

Little Women

The Velveteen Rabbit

Perl Cookbook

(6 rows)

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

Если вы хотите, чтобы секция IN сравнивала несколько полей, сгруппируйте их имена в круглых скобках в секции WHERE непосредственно перед IN. Сгруппированные поля должны соответствовать полям целевого списка как по количеству, так и по типу.

В листинге4.61 приведен подзапрос к таблице editions, который группирует поле i sbn с целочисленной константой 0 для всех книг в бумажной обложке (type=’ р’). Возвращаемые подзапросом записи сравниваются с полем isbn и полем stock таблицы stock с использованием ключевого слова IN. В результате команда SELECT выбирает данные обо всех книгах в бумажной обложке, отсутствующих на складе.

Листинг 4.61. Многоцелевой подзапрос в секции IN

booktown=# SELECT isbn, cost, retail FROM stock

booktown-# WHERE (isbn, stock)

booktown-# IN (SELECT isbn, 0 FROM editions

booktown(# WHERE type = ‘p’);

isbn | cost | retail

0394800753 | 16.00 | 16.95

0394900014 | 23.00 | 23.95

0451457994 | 17.00 | 22.95

(3 rows)