Sử dụng cùng CASE KHI Điều kiện cho nhiều cột truy vấn


12

Có cách nào "tốt hơn" để viết lại một SELECTmệnh đề trong đó nhiều cột sử dụng cùng một CASE WHENđiều kiện để các điều kiện chỉ được kiểm tra một lần không?

Xem ví dụ dưới đây.

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

Trong mã psuedo không phải sql, mã có thể trông như sau:

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

Ghi chú:

  • Tôi nhận thức được các vấn đề bình thường hóa rõ ràng ngụ ý bởi truy vấn. Tôi chỉ muốn chứng minh vấn đề.

Và tất cả các cột authTime, authUser, cmplTimeđang ở trong cùng một bảng?
ypercubeᵀᴹ

Câu trả lời:


7

Ngay cả trong Oracle (và trên thực tế trong tiêu chuẩn SQL), CASElà một biểu thức trả về một giá trị duy nhất. Nó không được sử dụng để kiểm soát dòng chảy như trong một số ngôn ngữ khác. Do đó, nó không thể được sử dụng để quyết định có điều kiện giữa nhiều cột hoặc các hoạt động khác.

Tôi muốn đặt phiên bản mã dài hơn (đã hoạt động) vào dạng xem và đừng lo lắng về nó trong các truy vấn chính thức của bạn.

Bạn cũng có thể xem xét một thiết kế bình thường hơn. Ví dụ, tại sao không lưu trữ chi tiết kiểm toán anh ta trong một bảng riêng biệt, với loại là một phần của khóa? Điều này làm cho mã của bạn dễ bảo trì hơn nhiều, đặc biệt là khi nhiều loại được thêm vào ...


7

Nếu tất cả các cột này từ cùng một bảng, bạn có thể sử dụng một cái gì đó như thế này:

    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' ;

2
Tôi suy nghĩ về việc đăng nó, nhưng nó chỉ dài dòng. Tôi không nghĩ có một cách hay để làm điều đó.
Philᵀᴹ

Nó trả lời câu hỏi +1, nhưng như những người khác đã chỉ ra, những gì bạn bắt đầu với là tốt hơn. Bạn cũng có thể nối các giá trị tương ứng với từng testStatus và sau đó tách chúng ra, nhưng điều đó thậm chí còn tồi tệ hơn.
Leigh Riffel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.