Resposta básica
Existem CTEs (Expressões de tabela comuns) em Postgres (como em qualquer grande RDBMS moderno, exceto MySQL). Desde a versão 9.1 que inclui CTEs de modificação de dados. Esses podem ser "aninhados".
Atualização:MySQL 8.0 finalmente adiciona CTEs.
Ao contrário das subconsultas Os CTEs se apresentam como barreiras de otimização. O planejador de consulta não pode inserir comandos triviais no comando principal ou reordenar junções entre a consulta principal e os CTEs. O mesmo é possível com subconsultas. Pode ser (muito) bom ou (muito) ruim para o desempenho, depende.
De qualquer forma, CTEs exigem um pouco mais de sobrecarga (custo de desempenho) do que subconsultas.
Atualização:Postgres 12 pode finalmente inserir CTEs simples em linha na consulta principal.
Detalhes que você não pediu
Sua pergunta é muito básica, o acima provavelmente é suficiente para responder. Mas vou adicionar um pouco para usuários avançados (e um exemplo de código para mostrar a sintaxe).
Todos os CTEs de uma consulta são baseados no mesmo instantâneo do banco de dados. O próximo CTE pode reutilizar a saída das CTEs anteriores (tabelas temporárias internas), mas os efeitos nas tabelas subjacentes são invisíveis para outras CTEs. A sequência de vários CTEs é arbitrária a menos que algo é retornado com o
RETURNING
cláusula para INSERT
, UPDATE
, DELETE
- irrelevante para SELECT
, já que não altera nada e apenas lê a partir do instantâneo. Isso pode ter efeitos sutis com várias atualizações que afetariam a mesma linha. Apenas um atualização pode afetar cada linha. Qual deles é influenciado pela sequência de CTEs.
Tente prever o resultado:
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;
Fiddle SQL
Não fique desapontado, duvido que haja muitos aqui que poderiam ter feito isso. :)
A essência disso:evitar comandos conflitantes em CTEs.