对多个查询列使用相同的CASE WHEN条件


12

是否存在一种“更好”的方式来重写SELECT子句,其中多个列使用相同的CASE WHEN条件,以便仅检查条件一次?

请参见下面的示例。

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

在非sql伪代码中,代码可能类似于:

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

注意:

  • 我知道查询隐含的明显标准化问题。我只想演示这个问题。

而所有这些列authTimeauthUsercmplTime是在同一个表?
ypercubeᵀᴹ

Answers:


7

即使在Oracle中(实际上在SQL标准中),它CASE也是一个返回单个值的表达式。它不是用于流量控制就像它在某些其他语言。因此,它不能用于有条件地在多个列或其他操作之间进行决策。

我想说的是将较长版本的代码(已经可以使用)放在视图中,并且不必担心在正式查询中使用它。

您可能还会考虑更规范的设计。例如,为什么不将审核详细信息存储在单独的表中,并将类型作为键的一部分?这使您的代码更易于维护,尤其是当添加更多类型时。


Even in Oracle...但是在Postgres中,可以通过扩展复合类型来实现。
Eugen Konkov

7

如果所有这些列都来自同一张表,则可以使用以下内容:

    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
我曾想过要发布,但这是漫长的。我认为没有什么好办法。
Philᵀᴹ

它回答了+1问题,但是正如其他人指出的那样,您从开始做起就更好。您还可以连接与每个testStatus对应的值,然后将它们分开,但这会更糟。
雷·里菲尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.