Usando o mesmo caso em que condições para várias colunas de consulta

12

Existe uma maneira "melhor" de reescrever uma SELECTcláusula em que várias colunas usam as mesmas CASE WHENcondições para que as condições sejam verificadas apenas uma vez?

Veja o exemplo abaixo.

SELECT
    CASE testStatus 
        WHEN 'A' THEN 'Authorized'
        WHEN 'C' THEN 'Completed'
        WHEN 'P' THEN 'In Progress'
        WHEN 'X' THEN 'Cancelled'
    END AS Status,

    CASE testStatus 
        WHEN 'A' THEN authTime
        WHEN 'C' THEN cmplTime
        WHEN 'P' THEN strtTime
        WHEN 'X' THEN cancTime
    END AS lastEventTime,

    CASE testStatus 
        WHEN 'A' THEN authBy
        WHEN 'C' THEN cmplBy
        WHEN 'P' THEN strtBy
        WHEN 'X' THEN cancBy
    END AS lastEventUser
FROM test

No código psuedo não-sql, o código pode se parecer com:

CASE testStatus
    WHEN 'A'
        StatusCol        = 'Authorized'
        lastEventTimeCol = authTime 
        lastEventUserCol = authUser
    WHEN 'C'
        StatusCol        = 'Completed'
        lastEventTimeCol = cmplTime
        lastEventUserCol = cmplUser
    ...
END

Nota:

  • Estou ciente dos problemas óbvios de normalização implícitos na consulta. Eu só queria demonstrar o problema.
Steven
fonte
E todas essas colunas authTime, authUser, cmplTimeestão na mesma mesa?
ypercubeᵀᴹ

Respostas:

7

Mesmo no Oracle (e de fato no padrão SQL), CASEé uma expressão que retorna um único valor. É não usado para o controle de fluxo como é em alguns outros idiomas. Portanto, não pode ser usado para decidir condicionalmente entre várias colunas ou outras operações.

Eu diria que coloque a versão mais longa do código (que já funciona) em uma exibição e não se preocupe com isso em suas consultas formais.

Você também pode considerar um design mais normalizado. Por exemplo, por que não armazenar os detalhes da auditoria em uma tabela separada, com o tipo como parte da chave? Isso torna seu código muito mais fácil de manter, especialmente à medida que mais tipos são adicionados ...

Aaron Bertrand
fonte
7

Se todas essas colunas forem da mesma tabela, você pode usar algo como isto:

    SELECT  
        'Authorized' AS StatusCol,
        authTime     AS lastEventTimeCol, 
        authUser     AS lastEventUserCol 
    FROM test
    WHERE testStatus = 'A'

  UNION ALL

    SELECT  
        'Completed', 
        cmplTime,
        cmplUser    
    FROM test
    WHERE testStatus = 'C'

  UNION ALL

    SELECT  
        'In Progress', 
        strtTime,
        strtUser    
    FROM test
    WHERE testStatus = 'P'

  UNION ALL

    SELECT  
        'Cancelled', 
        cancTime,
        cancUser    
    FROM test
    WHERE testStatus = 'X' ;
ypercubeᵀᴹ
fonte
2
Eu pensei em postar isso, mas é tão demorado. Eu não acho que haja uma boa maneira de fazer isso.
21412 Philh
Responde à pergunta +1, mas como outros indicaram, o que você começou é melhor. Você também pode concatenar os valores que correspondem a cada testStatus e depois separá-los, mas isso seria ainda pior.
Leigh Riffel