JOIN条件の中でCASE文を使用することはできますか?

次の画像は、Microsoft SQL Server 2008 R2 System Views の一部です。画像から、sys.partitionssys.allocation_units の関係は sys.allocation_units.type の値に依存することが分かります。そこで、これらを結合するために、次のようなことを書きます。

SELECT  *
FROM    sys.indexes i
        JOIN sys.partitions p
            ON i.index_id = p.index_id 
        JOIN sys.allocation_units a
            ON CASE
               WHEN a.type IN (1, 3)
                   THEN a.container_id = p.hobt_id 
               WHEN a.type IN (2)
                   THEN a.container_id = p.partition_id
               END 

しかし、上のコードではシンタックスエラーが発生します。CASE`ステートメントが原因だと思います。 どなたか少し解説していただけませんか?


エラーメッセージを追加する。

Msg 102, Level 15, State 1, Line 6 Incorrect syntax near '='.

!これはイメージです]1

質問へのコメント (7)
ソリューション

CASE式は、句のTHEN` 部分の値を返します。 このように使うことができます。

SELECT  * 
FROM    sys.indexes i 
    JOIN sys.partitions p 
        ON i.index_id = p.index_id  
    JOIN sys.allocation_units a 
        ON CASE 
           WHEN a.type IN (1, 3) AND a.container_id = p.hobt_id THEN 1
           WHEN a.type IN (2) AND a.container_id = p.partition_id THEN 1
           ELSE 0
           END = 1

この文は代入の値を返そうとしたり、等号のテストをしようとしていますが、どちらも CASE/THEN 節の文脈では意味を持ちません。 (もし BOOLEAN がデータ型であれば、等質性のテストは意味を持つでしょう)。

解説 (6)

その代わり、両方のテーブルにJOINして、SELECT句で指定します。 一致したほうのデータを返す。

このリンクConditional Joins in SQL Serverとhttps://stackoverflow.com/questions/8361183/t-sql-case-statement-in-a-join-on-clause を参照することをお勧めします。

    SELECT  *
FROM    sys.indexes i
        JOIN sys.partitions p
            ON i.index_id = p.index_id 
        JOIN sys.allocation_units a
            ON a.container_id =
            CASE
               WHEN a.type IN (1, 3)
                   THEN  p.hobt_id 
               WHEN a.type IN (2)
                   THEN p.partition_id
               END 

編集:コメント通りです。

結合条件をそのまま指定することはできません。以下の項目を確認してください。 上のクエリでは、エラーは出ていません。上の共通列を削除しています。 右の列の値は、条件によって評価されます。

解説 (9)

これを試してみてください。

...JOIN sys.allocation_units a ON 
  (a.type=2 AND a.container_id = p.partition_id)
  OR (a.type IN (1, 3) AND a.container_id = p.hobt_id)
解説 (1)

2つのケースステートメントが必要だと思います。

SELECT  *
FROM    sys.indexes i
    JOIN sys.partitions p
        ON i.index_id = p.index_id 
    JOIN sys.allocation_units a
        ON 
        -- left side of join on statement
            CASE
               WHEN a.type IN (1, 3)
                   THEN a.container_id
               WHEN a.type IN (2)
                   THEN a.container_id
            END 
        = 
        -- right side of join on statement
            CASE
               WHEN a.type IN (1, 3)
                   THEN p.hobt_id
               WHEN a.type IN (2)
                   THEN p.partition_id
            END             

これは、
のためです。

-CASEステートメントは、END
で単一の値を返します。 -ONステートメントは2つの値を比較します
。 -CASEステートメントは、CASEステートメントの_内部_の比較を行っていました。 CASEステートメントをSELECTに入れると、ブール値「1」または「0」が表示され、CASEステートメントがTrueまたはFalse
のいずれと評価されたかが示されると思います。

解説 (0)

これはいいようです。

https://bytes.com/topic/sql-server/answers/881862-joining-different-tables-based-condition

FROM YourMainTable
LEFT JOIN AirportCity DepCity ON @TravelType = 'A' and DepFrom =  DepCity.Code
LEFT JOIN AirportCity DepCity ON @TravelType = 'B' and SomeOtherColumn = SomeOtherColumnFromSomeOtherTable
解説 (1)

私はあなたの例を取り、それを編集しました:

SELECT  *
FROM    sys.indexes i
    JOIN sys.partitions p
        ON i.index_id = p.index_id 
    JOIN sys.allocation_units a
        ON CASE
           WHEN a.type IN (1, 3)
               THEN p.hobt_id 
           WHEN a.type IN (2)
               THEN p.partition_id
           ELSE NULL
           END = a.container_id
解説 (0)

DonkeyKongの例を取りました。

問題は、宣言された変数を使用する必要があることです。 これにより、比較する必要があるものの左側と右側を述べることができます。 これは、ユーザーの選択に基づいてさまざまなフィールドをリンクする必要があるSSRSレポートをサポートするためのものです。

最初のケースでは、選択に基づいてフィールド選択を設定します。 次に、結合のために照合する必要があるフィールドを設定できます。

2番目のケースステートメントを右側に追加できます。 変数は、さまざまなフィールドから選択する必要があります。

LEFT OUTER JOIN Dashboard_Group_Level_Matching ON
       case
         when @Level  = 'lvl1' then  cw.Lvl1
         when @Level  = 'lvl2' then  cw.Lvl2
         when @Level  = 'lvl3' then  cw.Lvl3
       end
    = Dashboard_Group_Level_Matching.Dashboard_Level_Name
解説 (0)

ここで、2つの異なる結果セットの違いを比較しました。 これが役立つことを願っています。

SELECT main.ColumnName, compare.Value PreviousValue,  main.Value CurrentValue
FROM 
(
    SELECT 'Name' AS ColumnName, 'John' as Value UNION ALL
    SELECT 'UserName' AS ColumnName, 'jh001' as Value UNION ALL
    SELECT 'Department' AS ColumnName, 'HR' as Value UNION ALL
    SELECT 'Phone' AS ColumnName, NULL as Value UNION ALL
    SELECT 'DOB' AS ColumnName, '1993-01-01' as Value UNION ALL
    SELECT 'CreateDate' AS ColumnName, '2017-01-01' as Value UNION ALL
    SELECT 'IsActive' AS ColumnName, '1' as Value
) main
INNER JOIN
(
    SELECT 'Name' AS ColumnName, 'Rahul' as Value UNION ALL
    SELECT 'UserName' AS ColumnName, 'rh001' as Value UNION ALL
    SELECT 'Department' AS ColumnName, 'HR' as Value UNION ALL
    SELECT 'Phone' AS ColumnName, '01722112233' as Value UNION ALL
    SELECT 'DOB' AS ColumnName, '1993-01-01' as Value UNION ALL
    SELECT 'CreateDate' AS ColumnName, '2017-01-01' as Value UNION ALL
    SELECT 'IsActive' AS ColumnName, '1' as Value
) compare
ON main.ColumnName = compare.ColumnName AND
CASE 
    WHEN main.Value IS NULL AND compare.Value IS NULL THEN 0
    WHEN main.Value IS NULL AND compare.Value IS NOT NULL THEN 1
    WHEN main.Value IS NOT NULL AND compare.Value IS NULL THEN 1
    WHEN main.Value  compare.Value THEN 1
END = 1 
解説 (0)