web-dev-qa-db-ja.com

複数のクエリ列に同じCASE WHEN条件を使用する

複数の列が同じCASE WHEN条件を使用するSELECT句を書き換えて条件を1回だけチェックする「より良い」方法はありますか?

以下の例を参照してください。

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

注意:

  • クエリが意味する明らかな正規化の問題を認識しています。私は問題を実証したかっただけです。
13
Steven

Oracle(実際にはSQL標準でも)では、CASEは単一の値を返す式です。 notは、他の一部の言語と同様に、フローの制御に使用されます。したがって、複数の列やその他の操作を条件付きで決定するために使用することはできません。

より長いバージョンのコード(既に機能しているもの)をビューに配置し、正式なクエリではそれを心配しないでください。

より正規化された設計を検討することもできます。たとえば、キーの一部としてタイプを使用して、監査の詳細を別のテーブルに保存しませんか?これにより、特に型が追加されるので、コードの保守がはるかに容易になります...

7
Aaron Bertrand

これらのすべての列が同じテーブルからのものである場合は、次のようなものを使用できます。

    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' ;
7
ypercubeᵀᴹ