Melhor maneira de executar lógica de instrução de caso aninhada no SQL Server


185

Estou escrevendo uma Consulta SQL, onde algumas das colunas retornadas precisam ser calculadas dependendo de várias condições.

Atualmente, estou usando instruções de caso aninhadas, mas está ficando confuso. Existe uma maneira melhor (mais organizada e / ou legível)?

(Estou usando o Microsoft SQL Server, 2005)


Um exemplo simplificado:

SELECT
    col1,
    col2,
    col3,
    CASE
        WHEN condition 
        THEN
            CASE
                WHEN condition1 
                THEN
                    CASE 
                        WHEN condition2
                        THEN calculation1
                        ELSE calculation2
                    END
                ELSE
                    CASE 
                        WHEN condition2
                        THEN calculation3
                        ELSE calculation4
                    END
            END
        ELSE 
            CASE 
                WHEN condition1 
                THEN 
                    CASE
                        WHEN condition2 
                        THEN calculation5
                        ELSE calculation6
                    END
                ELSE
                    CASE
                        WHEN condition2 
                        THEN calculation7
                        ELSE calculation8
                    END
            END            
    END AS 'calculatedcol1',
    col4,
    col5 -- etc
FROM table

Oi, você usou uma ferramenta (como SQLinForm) para recuar tão bem as consultas aninhadas?
Guido

Aprecio você me ensinar um método de formatação mais agradável para aninhadosCASE WHEN
Simon1979

Certamente, há momentos em que isso seria eficiente e útil, mas, em geral, eu gosto de manter a lógica longe das minhas consultas SQL. Apenas uma dica para a posteridade.
tschwab

Respostas:


188

Você pode tentar algum tipo de truque do COALESCE, por exemplo:

SELECIONAR COALESCE (
  CASO QUANDO condição1 ENTÃO cálculo1 ELSE NULL END,
  CASO QUANDO condição2 ENTÃO cálculo2 ELSE NULL END,
  etc ...
)

Bom, acabei de testar para garantir que ele funcione em curto-circuito e fiquei surpreso ao descobrir que sim. Portanto, se a condição1 tiver verificado uma divisão por zero, parece que é seguro fazê-lo na condição2. Não tenho certeza se isso é garantido.
Cade Roux

13
Um problema é que, se um dos seus casos quiser legitimamente retornar um NULL, não será mais possível.
22420 Chris KL

8
Esse é um ótimo truque, mas lembre-se de que ele pode não ter um desempenho tão bom quanto usar apenas as instruções CASE. Isso está "documentado" na seção Adições da comunidade aqui - msdn.microsoft.com/en-us/library/ms190349.aspx . Meu DBA acabou de
soltar

Quando isso é melhor do que apenas uma declaração de caso (resposta da @ beach)?
perfil completo de Ronnie Overby

Como renomear uma coluna nesta resposta .. por exemplo, se eu quiser renomear 'cálculo1' para 'CAL1' ... Como é possível sintaticamente?
Renascent

89

Envolva todos os casos em um.


SELECT
    col1,
    col2,
    col3,
    CASE
        WHEN condition1 THEN calculation1 
        WHEN condition2 THEN calculation2
        WHEN condition3 THEN calculation3
        WHEN condition4 THEN calculation4
        WHEN condition5 THEN calculation5
        ELSE NULL         
    END AS 'calculatedcol1',
    col4,
    col5 -- etc
FROM table

31

Você pode combinar várias condições para evitar a situação:

CASE WHEN condition1 = true AND condition2 = true THEN calculation1 
     WHEN condition1 = true AND condition2 = false 
     ELSE 'what so ever' END,

21

Eu pessoalmente faço dessa maneira, mantendo as expressões CASE incorporadas confinadas. Eu também colocaria comentários para explicar o que está acontecendo. Se for muito complexo, divida-o em função.

SELECT
    col1,
    col2,
    col3,
    CASE WHEN condition THEN
      CASE WHEN condition1 THEN
        CASE WHEN condition2 THEN calculation1
        ELSE calculation2 END
      ELSE
        CASE WHEN condition2 THEN calculation3
        ELSE calculation4 END
      END
    ELSE CASE WHEN condition1 THEN 
      CASE WHEN condition2 THEN calculation5
      ELSE calculation6 END
    ELSE CASE WHEN condition2 THEN calculation7
         ELSE calculation8 END
    END AS 'calculatedcol1',
    col4,
    col5 -- etc
FROM table

11

Aqui está uma solução simples para a declaração de caso "Complexa" aninhada: - Expressão complexa de caso aninhada

select  datediff(dd,Invdate,'2009/01/31')+1 as DaysOld, 
    case when datediff(dd,Invdate,'2009/01/31')+1 >150 then 6 else
        case when datediff(dd,Invdate,'2009/01/31')+1 >120 then 5 else 
            case when datediff(dd,Invdate,'2009/01/31')+1 >90 then 4 else 
                case when datediff(dd,Invdate,'2009/01/31')+1 >60 then 3 else 
                    case when datediff(dd,Invdate,'2009/01/31')+1 >30 then 2 else 
                        case when datediff(dd,Invdate,'2009/01/31')+1 >30 then 1 end 
                    end
                end
            end
        end
    end as Bucket
from rm20090131atb

Apenas certifique-se de ter uma declaração final para cada declaração de caso


5
Você pode formatar sua resposta se quiser que seja lida por outras pessoas.
IsmailS

6

Podemos combinar várias condições para reduzir a sobrecarga de desempenho.

Vamos existir três variáveis ​​abc nas quais queremos executar casos. Podemos fazer isso como abaixo:

CASE WHEN a = 1 AND b = 1 AND c = 1 THEN '1'
     WHEN a = 0 AND b = 0 AND c = 1 THEN '0'
ELSE '0' END,

5

uma função definida pelo usuário pode servidor melhor, pelo menos para esconder a lógica - esp. se você precisar fazer isso em mais de uma consulta


2

Eu passei por isso e achei todas as respostas super legais, no entanto, quero adicionar uma resposta dada por @deejers

    SELECT
    col1,
    col2,
    col3,
    CASE
        WHEN condition1 THEN calculation1 
        WHEN condition2 THEN calculation2
        WHEN condition3 THEN calculation3
        WHEN condition4 THEN calculation4
        WHEN condition5 THEN calculation5         
    END AS 'calculatedcol1',
    col4,
    col5 -- etc
FROM table

você pode tornar o ELSE opcional, pois não é obrigatório, é muito útil em muitos cenários.


2

Este exemplo pode ajudá-lo. A figura mostra como a instrução SQL case será exibida quando houver if e mais de um loop interno se

insira a descrição da imagem aqui

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.