Używanie tego samego PRZYPADKU, GDY Warunki dla wielu kolumn zapytań

12

Czy istnieje „lepszy” sposób przepisania SELECTklauzuli, w której wiele kolumn używa tych samych CASE WHENwarunków, aby warunki były sprawdzane tylko raz?

Zobacz przykład poniżej.

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

W kodzie psuedo innym niż SQL, kod może wyglądać następująco:

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

Uwaga:

  • Mam świadomość oczywistych problemów normalizacyjnych wynikających z zapytania. Chciałem tylko zademonstrować ten problem.
Steven
źródło
I wszystkie te kolumny authTime, authUser, cmplTimesą w tej samej tabeli?
ypercubeᵀᴹ
podobne pytanie: stackoverflow.com/q/13713316/4632019
Eugen Konkov

Odpowiedzi:

7

Nawet w Oracle (a właściwie w standardzie SQL) CASEjest wyrażenie, które zwraca pojedynczą wartość. To jest nie używany do kontroli przepływu, jak to jest w innych językach. Dlatego nie można go używać do warunkowego decydowania o wielu kolumnach lub innych operacjach.

Powiedziałbym, że umieść dłuższą wersję kodu (która już działa) w widoku i nie martw się o to w formalnych zapytaniach.

Możesz również rozważyć bardziej znormalizowany projekt. Na przykład, dlaczego nie przechowywać szczegółów audytu w osobnej tabeli, z typem jako częścią klucza? Dzięki temu kod jest znacznie łatwiejszy w utrzymaniu, szczególnie gdy dodaje się więcej typów ...

Aaron Bertrand
źródło
Even in Oracle... ale w Postgres jest to możliwe poprzez rozwinięcie typu kompozytu.
Eugen
7

Jeśli wszystkie te kolumny pochodzą z tej samej tabeli, możesz użyć czegoś takiego:

    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ᵀᴹ
źródło
2
Zastanawiałem się nad opublikowaniem tego, ale jest tak samo rozwlekłe. Nie wydaje mi się, żeby można to zrobić w przyjemny sposób.
Philᵀᴹ
Odpowiada na pytanie +1, ale jak wskazali inni, to, od czego zacząłeś, jest lepsze. Można także połączyć wartości odpowiadające każdemu testowi, a następnie rozdzielić je, ale byłoby jeszcze gorzej.
Leigh Riffel