Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
conspect.pdf
Скачиваний:
376
Добавлен:
17.03.2016
Размер:
27.86 Mб
Скачать

Базы данных

БГУИР, ПОИТ

 

 

6.5. Подзапросы (SUBQUERIES)

6.5.1. Общие сведения о подзапросах

Подзапросы – это «запросы внутри запроса» (вложенные запросы), которые используются как источник данных для:

получения некоего значения, используемого в операциях сравнения;

получения набора данных, из которого в дальнейшем производится выборка «основной частью запроса».

Например: удалить из основной таблицы все статьи, копии которых есть в архивной таблице.

DELETE FROM `articles_main`

WHERE `a_id` IN (SELECT `a_id` FROM `articles_archive`)

Подзапросы могут возвращать:

одно значение – скалярные подзапросы;

одну строку – строчные подзапросы;

одну колонку – столбцовые подзапросы;

таблицу – табличные подзапросы.

Каждый из этих видов подзапросов может использоваться в своём определённом контексте.

6.5.2.Скалярные подзапросы и сравнение с использованием подзапросов

Скалярный подзапрос возвращает одно значение.

Если в результате выполнения подзапроса получается пустой результат, значением подзапроса считается NULL.

Подзапросы не могут использоваться в случае, если синтаксис требует явного указания значений (например, в LIMIT).

Подробности можно изучить здесь: http://dev.mysql.com/doc/refman/5.5/en/scalar-subqueries.html

Пример: показать людей, чей возраст больше среднего возраста.

 

Исходная таблица

 

Запрос

Результат

 

 

 

SELECT * FROM `people`

 

 

 

 

 

 

WHERE `age` >

 

 

 

 

 

 

(SELECT AVG(`age`) FROM `people`)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Стр: 209/248

Базы данных

БГУИР, ПОИТ

 

 

Общий принцип использования подзапросов в операциях сравнения может быть выражен так:

ОПЕРАНД операция_сравнения (ПОДЗАПРОС)

Особенность MySQL.

Операциями сравнения могут быть:

= > < >= <= <> != <=>

LIKE

 

 

Подробности можно изучить здесь: http://dev.mysql.com/doc/refman/5.5/en/comparisons-using-subqueries.html

Как правило, сравнение с использованием запросов используется в случае, если запрос невозможно (или вычислительно сложно) реализовать с помощью

JOIN.

Одним из таких примеров может быть уже рассмотренный поиск людей с возрастом больше среднего:

SELECT * FROM `people`

WHERE `age` > (SELECT AVG(`age`) FROM `people`)

Ещё один пример – поиск записей, результат выборки которых с некоторым полем, встречается заданное количество раз.

Например: найти всех однофамильцев, которых в таблице по трое.

Исходная таблица

 

Запрос

 

Результат

 

 

SELECT `name` FROM `people2`

 

 

 

 

AS `OuterTable` WHERE

 

 

 

 

(SELECT COUNT(*) FROM

 

 

 

 

`people2` AS `InnerTable`

 

 

 

 

WHERE `OuterTable`.`surname` =

 

 

 

 

`InnerTable`.`Surname`) = 3

 

 

 

 

 

 

 

Стр: 210/248

Базы данных

БГУИР, ПОИТ

 

 

6.5.3. Подзапросы с ключевыми словами ANY, IN, SOME, ALL

Для понимания того, как работают подзапросы с этими ключевыми словами, нужно вспомнить логику.

Проще всего – со словом IN. Оно определяет вхождение (IN) или не вхождение (NOT IN) элемента в некий набор.

Теперь рассмотрим ANY (синоним SOME):

И, наконец, рассмотрим ALL:

Стр: 211/248

Базы данных

БГУИР, ПОИТ

 

 

Пример 1 (очень жизненный, часто бывают ошибки): удалить статьи, id которых нам известны.

Варианты решений:

[ПЛОХО!] Цикл с запросами вида:

DELETE … WHERE `id` = {id}

[ПЛОХО!] Запрос вида:

DELETE … WHERE `id`={id1} OR `id`={id2} OR … OR `id`={id999}

[ХОРОШО!] Запрос вида:

DELETE … WHERE `id` IN (10, 14, 87, 174)

[ХОРОШО!] Запрос вида:

DELETE … WHERE `id` IN (SELECT `id` FROM `victims`)

 

Пример 2: показать людей моложе ЛЮБОГО из

В ANY нельзя пере-

указанных возрастов.

дать список значений.

 

Такой вариант НЕ работает:

SELECT `name`, `age` FROM `people` WHERE `age` < ANY (35, 45, 55)

Работает вот такой:

Исходные таблицы

 

Запрос

 

Результат

`people`

`ages`

 

SELECT `name`, `age` FROM

 

 

 

 

 

`people` WHERE `age` < ANY

 

 

 

 

 

(SELECT `age` FROM `ages`)

 

 

 

 

 

 

 

 

Эту задачу можно решить и другим способом,

 

с использованием функции MAX().

Так тоже нельзя.

 

Такой запрос тоже не работает:

SELECT `name`, `age` FROM `people` WHERE `age` < MAX (35, 45, 55)

А такой вернёт результат, аналогичный запросу с ANY:

SELECT `name`, `age` FROM `people`

WHERE `age` < (SELECT MAX(`age`) FROM `ages`)

Стр: 212/248

Базы данных

БГУИР, ПОИТ

 

 

Пример 3: показать, сколько в таблице людей, моложе ВСЕХ указанных возрастов.

Исходные таблицы

 

Запрос

 

Результат

`people`

`ages`

 

SELECT `name`, `age` FROM

 

 

 

 

 

`people` WHERE `age` < ALL

 

 

 

 

 

(SELECT `age` FROM `ages`)

 

 

 

 

 

 

 

 

Второй вариант решения этой задачи выглядит так:

SELECT `name`, `age` FROM `people`

WHERE `age` < (SELECT MIN(`age`) FROM `ages`)

Важный момент! При использовании ALL надо помнить, что результат будет TRUE, если подзапрос вернёт пустое значение. При этом агрегирующие функции (MIN, MAX, etc) на пустом множестве возвращают NULL.

Исходные таблицы

 

Запросы

 

Результаты

`people`

`ages`

 

SELECT `name`,

`age` FROM

 

 

 

 

 

`people` WHERE `age` > ALL

 

 

 

 

 

(SELECT `age` FROM `ages`

 

 

 

 

 

WHERE `age` = 999)

 

 

 

 

 

 

 

 

 

 

 

 

SELECT `name`,

`age` FROM

 

 

 

 

 

`people` WHERE `age` < ALL

 

 

 

 

 

(SELECT `age` FROM `ages`

 

 

 

 

 

WHERE `age` = 999)

 

 

 

 

 

 

 

 

 

 

 

 

SELECT `name`,

`age` FROM

 

 

 

 

 

`people` WHERE `age` <

 

 

 

 

 

(SELECT MAX(`age`) FROM `ages`

 

 

 

 

 

WHERE `age` = 999)

 

 

 

 

 

 

 

 

 

Стр: 213/248

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]