Есть в SQL, а в том числе и в MySQL такая замечательная вещь как вложенные запросы (знаком с ней давно), бывают разные случаи, когда использование таких запросов может пригодиться.
1 | SELECT * FROM table1 WHERE field > (SELECT max(id) FROM table2) |
Совершенно абстрактный пример, чтобы показать смысл.
В данном случае, когда результат вложенного запроса используется в линейном условии в основном, он (результат) должен быть только одним полем, потому что иначе запрос просто не имеет смысла
Также, в WHERE можно прописывать такую замечательную вещь как IN (NOT IN) (об этом я также знал уже довольно давно)
1 | SELECT * FROM table WHERE field in ('value1', 'value2') |
И вот тут самое интересное:
Долгое время, используя вложенные подзапросы только как в примере 1, я думал, что вложенные подзапросы всегда должны возвращать только одно поле, но оказывается, результат вложенного подзапроса можно скармливать в IN, и тогда результатом вложенного запроса может быть не одна строка.
Например, следующий нехитрый подзапрос выберет из таблицы с многоуровневым бесконечным каталогом все конечные элементы не имеющие потомков
1 | SELECT t1.* FROM table as t1 WHERE id NOT IN (SELECT top FROM table as t2) |
Ну не прекрасно ли это?
Другими словами, мы выбираем все записи, id которых никому не являются top’ами в этой же таблице.
Единственный пугающий и узкий момент в подобном запросе — это время выполнения. Но к счастью в MySQL есть кэширование результатов запроса, и для каких-то выгрузок данных, действий в панелях управления подобный запрос неплохо подойдет (на небольших таблицах более усложненные подобные запросы отрабатывали в районе 1 секунды на шаред-хостинге). Конечно пихать такое на посещаемый сайт для вывода каких-то рюшечек при выводе элементов каталога не стоит, но как уже сказано выше, где-нибудь в редко-используемом месте это неплохо подходит, ну и к тому же есть смысл кешировать такое уже средствами языка программирования и тогда проблем тоже нет.
Тут важна идея.
Подобное можно реализовать несколькими запросами и несклолькими циклами в программном коде, а можно все это сформировать в виде одного запроса и отдать это на аутсорсинг серверу MySQL 🙂 Второе лучше и интересней
Вообще вложенные подзапросы с использование конструкции in очень тормознутые!
Например:
SELECT * FROM t1 WHERE id NOT IN (SELECT id FROM t2);
Или тоже самое, но с использованием джоина:
SELECT t1.*
FROM t1 LEFT JOIN t2 ON t1.id = t2.id
WHERE t2.id IS NULL;
С джоином подобный запрос работать будет в разы быстрее…