Подзапросы
Поддержка подзапросов, впервые реализованная в 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)