Обычно в результирующий набор добавляются предложения WHERE или HAVING, содержащие одно (и более) условное выражение, предназначенное для удаления ненужных записей из результирующего набора. Чаще всего в этих условных проверках используются фиксированные константы, например: "перечислить всех пользователей старше 40 лет" или "отобразить все счета-фактуры за период с января по июнь", что упрощает их написание и выполнение.
Однако возможны ситуации, когда условная проверка, используемая одним из запро­сов, использует значение, полученное вторым запросом, например, "перечислить всех пользователей старше среднего возраста" или "вывести счет-фактуру на самую большую сумму, полученный от самой малочисленной группы пользователей". Во всех таких случаях результаты, полученные одним запросом, зависят от данных, полученных с помощью другого запроса, что делает использование констант во внешнем запросе невозможным.
До версии 4.1 MySQL, в подобных случаях выполнялись запросы по отдельности, с последующим использованием наборов данных, полученных предыдущим запросом. На­чиная с версии MySQL 4.1, появилась возможность выполнять подзапросы.

На свой страх и риск
Несмотря на то, что подзапросы очень полезны, они существенно снижают произ­водительность СУБД MySQL. Так происходит потому, что еще на время издания этой книги, подзапросы поддерживались только альфа-версией MySQL 4.1, а производи­тельность была неоптимальной для данных любого объема больше среднего. Правда, лучше вместо подзапросов в сценариях использовать объединения, удаление и моди­фикацию сразу нескольких таблиц и временные таблицы, хотя в недалеком будущем ожидается существенное улучшение рабочих характеристик.

Что такое подзапрос?
Название подзапрос говорит само за себя: это запрос SELECT, вложенный в другой за­прос. MySQL 4.1 позволяет вкладывать запросы один в другой, используя во внешнем
запросе результирующий набор, полученный внутренним запросом. В результате вместо выполнения одного (и более) отдельного запроса выполняется один запрос, содержащий один (и более) подзапрос.
При обнаружении такого вложенного запроса, MySQL сначала обрабатывает внут­ренний запрос, постепенно продвигаясь вверх по направлению к внешнему (основному) запросу. Результирующий набор, созданный каждым внутренним запросом по пути про­движения, присваивается внешнему порождающему запросу, который в свою очередь выполняется, и его результаты присваиваются внешнему запросу.
Подзапрос работает аналогично обычному запросу SELECT, за исключением того, что результирующий набор состоит из одного столбца, содержащего одно значение. Подзапрос может использоваться в любом месте, где используются выражения, он должен быть заключен в скобки и, как обычный запрос SELECT, содержать список столбцов (как замечено выше, это список, состоящий из одного столбца), предложение FROM с одним именем таблицы (и более), необязательные предложения WHERE, HAVING и GROUP BY.
Для того чтобы лучше понять, насколько полезным может быть подзапрос, рассмот­рим простой пример с бухгалтерской базой данных воображаемой компании. Эта база данных состоит из следующих четырех таблиц.
Подзапросы
Подзапросы
4. Таблица branches_services: в этой таблице дается перечень филиалов и услуг, которыми они пользуются (это пара "идентификатор филиала - идентификатор услуги"). Она имеет внешние ключи по таблицам branches и services, соответственно.
Подзапросы
А теперь, как вы уже знаете, можно получить полный перечень всех записей таблицы с помощью простого запроса SELECT * FROM .... Например, ниже представлен пере-
чень всех заказчиков.
Подзапросы
С помощью объединения и предложения WHERE в операторе SELECT можно ограни­чить список записей только теми, что соответствуют определенному критерию - напри­мер, список заказчиков, филиалы которых расположены в Калифорнии.
Подзапросы
А теперь немного усложним задачу. Скажем, нам необходимо получить список фи­лиалов заказчика "Rabbit Foods Inc". Сейчас это можно сделать с помощью последова­тельности запросов SELECT, расположенных один за другим, сначала для получения идентификатора заказчика, который присвоен компании "Rabbit Foods", а затем, вос­пользовавшись этим идентификатором в другом запросе (он равен 104), получить список филиалов этого заказчика.
Подзапросы
Подзапросы
Таким образом, подзапрос позволяет объединять два и более запроса в один оператор и использовать результаты работы одного запроса в условном выражении другого.
Подзапрос должен возвратить один столбец, в противном случае MySQL не будет "знать", как обработать результирующий набор. Следующий листинг, демонстрирует что получится, если подзапрос возвратит результирующий набор, содержащий два столбца.
Листинг 11.6.
mysql> SELECT bdesc FROM branches WHERE cid = (SELECT cid, cname FROM clients WHERE cname = 'Rabbit Foods Inc');
ERROR 1239: Cardinality error (more/less than 1 columns)
Заметим, что допускается любая глубина вложения подзапросов. Рассмотрим пример со списком услуг, которыми пользуется заказчик "Sharp Eyes Detective Agency".
Подзапросы