Como um seguimento a esta pergunta , eu tenho um de minha autoria.
A pergunta original diz respeito ao uso de uma CASE
instrução com > de 100 opções e a instrução deve ser usada em 4 lugares - então obviamente o SQL é bastante complicado. A pergunta do OP dizia respeito ao SQL Server 2012, minha pergunta, no entanto, é sobre o PostgreSQL.
Na minha resposta , propus o uso de a VIEW
como uma solução "one-stop-shop" - ou seja, declare o VIEW
uma vez, use-o em qualquer lugar - e isso se aplica a qualquer consulta no futuro também e a qualquer variante dela.
Outro pôster (@AndriyM) propôs o uso de a CROSS APPLY
para resolver o problema, que é outra solução. A sintaxe do PostgreSQL éJOIN LATERAL
Em seguida, adicionei um CTE ( Common Table Expression ) à minha resposta original como outra solução possível.
Então, o OP agora tem 5 opções:
CASE
VIEW
JOIN LATERAL
(CROSS APPLY
para SQL Server)CTE
Separate table
Excluí a opção de alterar os dados subjacentes, pois, frequentemente neste fórum, consultores/DBAs/programadores não têm permissão para alterar os dados subjacentes - torna as respostas mais interessantes também!
Obviamente, uma CASE
expressão com > 100 opções (x4) é terrivelmente complicada e complexa - mas quando é uma boa ideia usar CASE
e em que ponto ela se torna menos em vez de mais?
Na minha opinião (e não apenas porque é a minha resposta!), a VIEW
é a solução ideal - é simples, funcionará para todos os RDBMS e é permanente e funcionará para todas as consultas agora e no futuro, caso o OP deseje modificar a consulta .
A JOIN LATERAL
construção funcionará também como uma espécie de tabela derivada, que é praticamente o que a CTE
também é. Ambos podem ser usados na mesma linha na mesma consulta.
Qual das 5 abordagens é melhor/melhor e em que ponto a técnica (facilidade de uso, velocidade, otimização do plano de consulta) se inclina a favor da solução específica?
Eu usaria uma tabela de tradução em uma
LATERAL
subconsulta . Demonstração (Postgres 10+):Ver:
Manipule
ord_nr
para ajustar as prioridades.Consulta:
Ou com uma subconsulta correlacionada :
Isso é fácil de manusear, mantém a longa lista de opções fora do código e a coloca em uma tabela onde pode ser mantida adequadamente. E é moderadamente rápido.
Não podemos usar facilmente um plain
LEFT JOIN ac_translate
já queCASE
atravessa padrões para retornar o single , first match. Não podemos simplesmente juntar a um conjunto, que pode retornar várias correspondências se um padrão for o prefixo do outro, como 'AIR%' e 'AIR N%'. Portanto, usamos um número de pedido na tabela de tradução para priorizar correspondências na subconsulta.A
ELSE
cláusula na pergunta referenciada resolve para o valor original. Isso é implementado comCOALESCE
aqui. Basicamente, isso combina as virtudes das duas principais respostas por lá.Para completar, entrei
GROUP BY 1
como outra maneira de evitar repetir expressões longas (o que não é mais necessário aqui). Ver:Velocidade
O desempenho se deteriora com o número de linhas na tabela de tradução, pois o Postgres é forçado a percorrer todas elas sequencialmente e avaliar a
LIKE
expressão. Se isso não for mais rápido o suficiente, precisamos de index support , mas a expressão não é "sargable" - a expressão que precisamos indexar está à direita do operador e não háCOMMUTATOR
forLIKE
. Detalhes:Há uma solução alternativa, no entanto. Meu exemplo requer que os padrões tenham pelo menos 3 caracteres principais ( 3 é minha escolha arbitrária). Adicione uma
CHECK
restrição na tabela de tradução para impor essa regra e um índice de expressão no trigrama inicial:Adapte a consulta:
Com linhas suficientes na tabela de tradução (e estimativas favoráveis e configurações de custo), o Postgres usará uma varredura de índice muito rápida para reduzi-la aos poucos candidatos (se houver) e filtrar apenas o restante com a
LIKE
expressão. Deve escalar bem. Eu adicionei aEXPLAIN
saída ao violino como prova de conceito:db<>fique aqui