Quero retornar minhas linhas de postagem em uma das três ordens de classificação, controladas por um sorting_param
parâmetro de função. A classificação é complexa, não se presta a um simples ORDER BY CASE ...
. Então, estou pensando em escrever cada classificação em seu próprio CTE e, em seguida, escolher um dos CTEs como a saída final. No entanto, não gostaria que o PostgreSQL perdesse tempo com todos os três, apenas com o que selecionei. Então, todos os três serão materializados ou apenas o que escolhi? Ou há uma maneira melhor de fazer isso? PostgreSQL versão 16. Código simplificado abaixo.
WITH posts_by_order1 AS
(
SELECT p.id
FROM post p
ORDER BY [some complex ordering 1]
LIMIT 10
),
posts_by_order2 AS
(
SELECT p.id
FROM post p
ORDER BY [some complex ordering 2]
LIMIT 10
),
posts_by_order3 AS
(
SELECT p.id
FROM post p
ORDER BY [some complex ordering 3]
LIMIT 10
)
SELECT * FROM posts_by_order1 WHERE sorting_param = 0
UNION ALL
SELECT * FROM posts_by_order2 WHERE sorting_param = 1
UNION ALL
SELECT * FROM posts_by_order3 WHERE sorting_param = 2;
Infelizmente não posso fazer isso:
ORDER BY
CASE
WHEN sorting_param = 0 THEN p.date
WHEN sorting_param = 1 THEN p.name
ELSE NULL
END DESC, ...
O manual:
Ênfase em negrito minha.
A palavra-chave opcional
MATERIALIZED
não tem impacto nisso. O conjunto de resultados de um CTE só pode ser "materializado" depois de ter sido executado, mas nunca chegamos lá...Então sua construção basicamente funciona . Teste sua consulta com
EXPLAIN ANALYZE
e você verá(never executed)
ao lado os planos para CTEs que não foram realmente chamados. Os CTEs ainda precisam ser planejados , o que incorre em uma pequena sobrecarga de qualquer maneira.Além disso, a ordem de classificação em subconsultas ou CTEs é transferida para o externo,
SELECT
desde que nada aconteça lá que possa disparar uma classificação diferente:UNION
(semALL
),JOIN
, cláusula adicionalWHERE
, ... Mas este é um detalhe de implementação e não há garantias. Isso aborda a ordem dentro do conjunto de resultados de uma subconsulta. Considerações semelhantes se aplicam à ordem entreUNION ALL
as pernas. Relacionado:Dependendo de como você pretende usar essa construção, pode haver opções melhores, incluindo:
Basta alternar para a declaração correta no seu código de cliente.
Use uma função PL/pgSQL e alterne com
CASE
dentro. Exemplo:Ligue para:
Tome cuidado para não introduzir SQL-injeção com SQL dinâmico. Veja: