0

私はこのようなことをする必要があります:

select *
from  Table 
      inner join Few more tables
where t2.ID IN( case when @Param1 = 0 then 
                        (select ID FROM tbl10 WHERE ForeignKey = @param2) 
                else @Param1 end)

したがって、@Param1 が 0 の場合は、値のセットを (@param2 に基づいて) 一致させ、0 でない場合は @Param1 のみを一致させたいと考えています。私はいくつかの構文バリエーションを試しましたが、うまくいきません。

同様の質問も見ましたが、役に立ちませんでした。

4

6 に答える 6

5

使用するOR

SELECT * 
FROM   table1 t1 
       INNER JOIN table2 t2 
               ON t1.t1col = t2.t1col 
WHERE  ( @param1  <>  0  AND t2.id = @Param1 ) 
    OR ( @param1  =   0  AND t2.id IN (SELECT id 
                           FROM   tbl10 
                           WHERE  foreignkey = @param2) ) 
于 2013-09-27T14:35:09.623 に答える
1

私はこれをまったく別の方法でアプローチし、 を使用しますIF/ELSE。カーディナリティが異なる 2 つの異なる基準を組み合わせると、オプティマイザーが最適なクエリ プランを選択する可能性が低くなります。次のようなものを使用すると、パフォーマンスが大幅に向上します。

IF @Param = 0
    BEGIN
        SELECT  *
        FROM    T
        WHERE   A IN (SELECT TID FROM T2 WHERE ID = 1 @param2);
    END
ELSE
    BEGIN
        SELECT  *
        FROM    T
        WHERE   ID = @Param1;
    END

より多くのコードのように見えるため、効率が低下するはずですが、実際にはそうではありません。このテスト シナリオの使用:

CREATE TABLE T (ID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY, A INT NOT NULL, B INT NULL);
INSERT T (A, B)
SELECT  A, Number
FROM    (   SELECT  TOP 1000 A = RANK() OVER(ORDER BY a.object_id)
            FROM    sys.all_objects a
        ) a
        CROSS JOIN (VALUES (1), (2), (3)) n (Number);

CREATE TABLE T2 (ID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY, TID INT NOT NULL);
INSERT T2 (TID)
SELECT  T.ID
FROM    T
        CROSS JOIN (VALUES (1), (2), (3)) n (Number);

CREATE NONCLUSTERED INDEX IX_T_A ON T (A);
CREATE NONCLUSTERED INDEX IX_T2_TID ON T2 (TID);
GO
CREATE PROCEDURE dbo.Proc1 @Param1 INT, @Param2 INT
AS
    SELECT ID, A, B 
    FROM   T
    WHERE  ( @param1  <>  0  AND t.A = @Param1 ) 
        OR ( @param1  =   0  AND t.A IN(SELECT TID FROM T2 WHERE ID = @param2));

-- (SORRY TIM, BUT YOURS WAS THE BEST OF THE REST)
GO

CREATE PROCEDURE dbo.Proc2 @Param1 INT, @Param2 INT
AS
    IF @Param1 = 0
        BEGIN
            SELECT  ID, A, B
            FROM    T
            WHERE   A IN (SELECT TID FROM T2 WHERE ID = @param2);
        END
    ELSE
        BEGIN
            SELECT  ID, A, B
            FROM    T
            WHERE   A = @Param1;
        END

GO

最初のプロシージャを (IF なしで) 実行すると、SQL-Server はコンパイル時に @Param1 と @Param2 が何であるかがわからないため、どの条件が満たされるかがわからないため、それに応じて最適化できません。両方の条件に対して同じ計画を作成します

EXECUTE dbo.Proc1 1, 1;
EXECUTE dbo.Proc1 0, 1;

ここに画像の説明を入力

一方、IF/ELSESQL-Server を使用すると、条件ごとに最適なプランを作成できます。

EXECUTE dbo.Proc2 1, 1;
EXECUTE dbo.Proc2 0, 1;

ここに画像の説明を入力

この場合、実際の影響はクエリ プランが示唆するほど悪くはありません。SQL-Server は、実行時に T2 if から選択するサブクエリを評価しないほど十分にスマートである@Param1 = 0ためです。ORただし、通常、必要な述語に影響を与える定数がある場合は、2 つの述語をマッシュアップするよりも、IF/ELSE で分離するのが最善です。

より少ないコードが常により効率的なクエリであるとは限りません。

SQL-Fiddle での DDL とクエリ

于 2013-09-27T15:39:42.887 に答える
1

これを試してもらえますか

select * from Table 
inner join Few more tables
where t2.ID IN(select case when  @Param1 = 0  then ID else @Param1 end FROM tbl10 WHERE ForeignKey    = @param2)
于 2013-09-27T14:29:42.287 に答える
1
SELECT *
FROM  Table 
      JOIN Few more tables
WHERE t2.ID IN (
   SELECT @Param1 WHERE @Param1 <> 0
   UNION ALL
   SELECT ID FROM tbl10 WHERE ForeignKey = @param2 AND ISNULL(@Param1, 0) = 0
   )
于 2013-09-27T15:02:07.177 に答える
0

シンプルで効果的:

select * from Table 
inner join Few more tables
where 

    -- IF
    @Param1 = 0 
       and t2.id in (select ID FROM tbl10 WHERE ForeignKey = @param2)

    -- ELSE
    or t2.id = @Param1
于 2013-09-27T14:39:44.597 に答える