JASE条件でCASEステートメントを使用できますか?


141

次の画像は、Microsoft SQL Server 2008 R2のシステムビューの一部です。画像から、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声明のせいだと思います。誰かが少し説明するのを手伝ってくれる?


エラーメッセージを追加:

メッセージ102、レベル15、状態1、行6「=」付近の構文が正しくありません。

これは画像です


36
この美しいDBダイアグラムを作成するためにどのソフトウェアを使用しましたか?
LearnByReading 2017年

2
@LearnByReading使用されたソフトウェアを見つけたことがありますか?
User632716

1
@ User632716残念ながらありません!
LearnByReading

2
@ User632716本当にMySQL Workbenchだと思いますが。しかし、私は応答を受け取りませんでした
LearnByReading 2018

@LearnByReadingわかりません。それはマイクロソフトによって提供されます。
学習者のみ

回答:


223

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

戻り値を使用して何かをする必要があることに注意してください。たとえば、1と比較してください。ステートメントは代入の値を返すか、等しいかどうかをテストしようとしましたが、どちらもCASE/ THEN句のコンテキストでは意味がありません。(BOOLEANデータ型の場合、等価性のテストは理にかなっています。)


@HABOおかげでうまくいきました...しかし、問題はこれを行うときに条件が崩れることです...どのようにそれを壊すか教えてください?
Sagar Tandel 2013年

1
@SagarTandel-すみません、「フォールスルースルー」と「どうやってそれを壊すか」がわかりません。コメントを明確にしていただけませんか?(最近、サバ沖のダイビングから浮上しました。ナイトロックスかもしれません。)
HABO 2013年

それは私が望まないすべての条件をチェックします。条件に一致したらケースを終了します。
Sagar Tandel 2013年

3
@SagarTandel- MSDNから:「CASEステートメントはその条件を順番に評価し、条件を満たす最初の条件で停止します。」明示的に指定された条件のいずれにも一致しないすべての結合行が必要な場合は、末尾をから= 1に変更するだけ= 0ですが、結果が気に入らないと思います。
HABO 2013年

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あなたはあなたのソリューションの上にエンティティフレームワークでそれを書くことができます
r.hamd

36

代わりに、両方のテーブルにJOINし、SELECT句で、一致するテーブルからデータを返します。

このリンクをSQL Serverの条件付き結合JOIN ON句のT-SQL Caseステートメントで確認することをお勧めします

例えば

    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 

編集:コメントどおり。

現在のように結合条件を指定することはできません。エラーがない上記のクエリを確認してください。共通の列を上に取り出しましたが、正しい列の値が条件で評価されます。


1
どういうconditional join意味?各結合(クロスを除く)は条件付きです。このケースは他のケースとどう違うのですか?サンプルには条件付きの内部結合があり、OPsクエリには条件付きの結合があります。
zerkms 2012

@zerkms:私は同意します、それは混乱するように聞こえます。この文脈での条件付き結合は、条件が別の条件に依存する結合を意味すると思います。
Andriy M

@Andriy M:を使って些細な条件の別の用語を考える理由はOR何ですか?
zerkms

@zerkms:ええ、そうです、それは混乱するように聞こえるからです。:)しかし、私はあなたがどんな理由があったかどうか尋ねるためのものと考えていない私は確認することはできません、その場合には別の用語、と思うが。私の理由について質問しいるなら、まあ、私は十分に気にすることができなかったと思います。:) 代替条件を使用し結合はどうですか?私は造語があまり得意ではありません。ただし、これは概念的には「条件付き条件」に関するものであり、「条件付き」に関するものではないことに注意してくださいOR。使用ORは、それを実装する1つの方法にすぎません。
Andriy M

@Andriy M:わかりました。しかし、個人的には、1 と2 または1 で、些細な状態の名前を付ける理由がまだわかりません。これは、他との違いがないルーチンクエリです。ORANDsCASE
zerkms 2012

17

これを試して:

...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)

問題なく機能しますが、問題のクエリは完全に有効に見えます。OPのコードの何が問題なのかはまだ説明されていません
zerkms

10

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に入れると、CASEステートメントがTrueとFalseのどちらに評価されたかを示すブール値「1」または「0」が得られると思います

5

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

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
           ELSE NULL
           END)


1

はい、できます。例を示します。

SELECT a.*
FROM TableA a
LEFT OUTER JOIN TableB j1 ON  (CASE WHEN LEN(COALESCE(a.NoBatiment, '')) = 3 
                                THEN RTRIM(a.NoBatiment) + '0' 
                                ELSE a.NoBatiment END ) = j1.ColumnName 

1
このコードは問題を解決する可能性がありますが、これが問題を解決する方法と理由の説明含めると、投稿の品質が向上し、おそらく投票数が増えることになります。あなたが今尋ねている人だけでなく、あなたが将来の読者のための質問に答えていることを忘れないでください。回答を編集して説明を追加し、適用される制限と前提を示してください。
ダブルビープ

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 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.