sql >> データベース >  >> RDS >> Sqlserver

Sql IN 内の Sql Case ステートメント

    OR を使用して実行できます :

    WHERE   (@Id > 0 AND Table1.Field = @Id)
    OR      (@Id = 0 AND Table1.Field IN (6,16,18))
      

    ただし、(あなたが言ったように) IF/ELSE を使用することをお勧めします 、このように 2 つの条件を組み合わせると、次善の計画を強制することがよくあります。たとえば、あなたの例では、これを次のようにスキーマに単純化できます:

    CREATE TABLE T
    (   ID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY, 
        Field INT NOT NULL, 
        SomeOtherField INT NULL
    );
    GO
    INSERT T  (Field)
    SELECT  Number
    FROM    Master..spt_values
            CROSS JOIN (VALUES (1), (2), (3)) t (A)
    WHERE   Type = 'P'
    GO
    CREATE NONCLUSTERED INDEX IX_T_Field ON T (Field) INCLUDE (SomeOtherField);
      

    これは、列の 1 つに 0 ~ 2047 の数字をそれぞれ 4 回繰り返して入力するだけです (いくつかのサンプル データの場合)。次に、上記の条件を組み合わせた「IF/ELSE」を使用する 2 つのプロシージャを作成すると、次のようになります。

    CREATE PROCEDURE dbo.Test @ID INT
    AS
        SELECT  ID, Field, SomeOtherField
        FROM    T
        WHERE   (@Id > 0 AND T.Field = @Id)
        OR      (@Id = 0 AND T.Field IN (6,16,18))
    
    GO
    CREATE PROCEDURE dbo.Test2 @ID INT
    AS
        IF @ID = 0
            SELECT  ID, Field, SomeOtherField
            FROM    T
            WHERE   T.Field IN (6, 16, 18)
        ELSE
            SELECT  ID, Field, SomeOtherField
            FROM    T
            WHERE   T.Field = @Id
    GO
      

    クエリのコンパイルは 1 回しか行われないため (別の方法で明示的に指定しない限り)、オプティマイザはプロシージャに 0 を渡すか ID> 0 を渡すかに応じて異なるプランを選択しません。したがって、次の両方が行われます:

    EXECUTE dbo.Test 0;
    EXECUTE dbo.Test 1;
      

    このプランを提供します:

    2 番目の手順では、最適な実行計画をより正確に見積もることができるため、これを実行します:

    EXECUTE dbo.Test2 0;
    EXECUTE dbo.Test2 1;
      

    次のプランを提供します:

    実際の例は明らかに異なるため、私の主張を証明する例を意図的に作成しました。 IF/ELSE を使用して多くのコードを複製するのは少し手間がかかります 、しかし多くの場合、それだけの価値があります。



    1. geodjangoのk最近傍を取得するにはどうすればよいですか?

    2. phpunitでPDOをあざける

    3. cx_Oracleと例外処理-グッドプラクティス?

    4. MySQL Workbench 5.2を使用してテーブルでupdateコマンドを実行中にエラー(エラーコード:1175)