Иллюстрированный самоучитель по PostgreSQL

Подзапросы

Поддержка подзапросов, впервые реализованная в 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 запись об авторе с именем "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, который группирует поле isbn с целочисленной константой 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)
Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.