PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

As consultas do tipo SELECT são o único tipo que pode ser aninhado?

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.