Являются ли запросы типа SELECT единственным типом, который может быть вложенным?

Можно ли встроить запрос без выбора (обновить, вставить, удалить) в другой запрос?

Что-то вроде (вставка внутри выбора)

A single query:

select such,and,such from .... where .... insert into .... ;

1 ответ

Решение

Основной ответ

В Postgres есть CTE (Common Table Expressions) (как в любой современной современной СУБД, кроме MySQL). Начиная с версии 9.1, это включает CTE, модифицирующие данные. Они могут быть "вложенными".
Обновление: MySQL 8.0 наконец добавляет CTE.

В отличие от подзапросов, CTE представляют собой барьеры для оптимизации. Планировщик запросов не может встроить тривиальные команды в основную команду или изменить порядок соединений между основным запросом и CTE. То же самое возможно с подзапросами. Это может быть (очень) хорошо или (очень) плохо для производительности, это зависит.
В любом случае, CTE требует немного больше накладных расходов (производительности), чем подзапросы.

Подробности вы не просили

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

Все CTE запроса основаны на одном и том же снимке базы данных. Следующий CTE может повторно использовать выходные данные предыдущих CTE (внутренних временных таблиц), но влияние на базовые таблицы невидимо для других CTE. Последовательность нескольких CTE является произвольной, если что-то не возвращается с RETURNING пункт для INSERT, UPDATE, DELETE - не имеет отношения к SELECT, так как он ничего не меняет и просто читает из снимка.

Это может иметь незначительные эффекты с несколькими обновлениями, которые будут влиять на одну и ту же строку. Только одно обновление может повлиять на каждую строку. Какой из них зависит от последовательности CTE.

Попробуйте предсказать результат:

CREATE TEMP TABLE t (t_id int, txt text);
INSERT INTO t VALUES (1, 'foo'), (2, 'bar'), (3, 'baz');

WITH sel AS (SELECT * FROM t)
   , up1 AS (UPDATE t SET txt = txt || '1' WHERE t_id = 1 RETURNING *)
   , up2 AS (UPDATE t SET txt = t.txt || '2'
             FROM   up1
             WHERE  up1.t_id = t.t_id
             RETURNING t.*)
   , ins AS (INSERT INTO t VALUES (4, 'bamm'))
   , up3 AS (UPDATE t SET txt = txt || '3' RETURNING *)
SELECT 'sel' AS source, * FROM sel
UNION ALL
SELECT 'up1' AS source, * FROM up1
UNION ALL
SELECT 'up2' AS source, * FROM up2
UNION ALL
SELECT 'up3' AS source, * FROM up3
UNION ALL
SELECT 't'   AS source, * FROM t;

SQL Fiddle

Не разочаровывайтесь, я сомневаюсь, что многие здесь могли бы это сделать.:)
The gist of this: avoid conflicting commands in CTEs.

Другие вопросы по тегам