0

My WHERE 句では、パラメーターが空白または null の場合にすべての行を返す CASE を使用しています。これは、単一の値でうまく機能します。ただし、IN 句を使用する場合はあまりうまくいきません。例えば:

これは非常にうまく機能し、一致しない場合はすべてのレコードが返されます!

AND 
Name = CASE WHEN @Name_ != '' THEN @Name_ ELSE Name END
AND

これも機能しますが、CASE 式を使用する方法がないため、値を指定しないとレコードが表示されません。

AND
Name IN (Select Names FROM Person Where Names like @Name_)
AND 

2 番目の例で CASE を使用できますか? 一致するものがない場合、すべての名前が返されますか?

4

5 に答える 5

2

たぶんcoalesceあなたの問題を解決します

AND
Name IN (Select Names FROM Person Where Names like coalesce(@Name,Name))
AND 

isnullMattfew Lakeが言って使用したように、関数も使用できます

Name IN (Select Names FROM Person Where Names like isnull(@Name,Name)) 
于 2013-09-05T18:52:58.330 に答える
1

おそらくこのようなものですか?

AND
Name IN (Select Names FROM Person Where Names LIKE 
         CASE WHEN @Name_ = '' OR @Name_ IS NULL THEN '%' ELSE @Name_ END)
AND 

@Name_これは、null または空白のパラメーターが指定された場合にのみパターン '%' (すべてに一致する)を使用し、それ以外の場合は で指定されたパターンを使用します@Name_

または、次のようなものが機能するはずです。

AND
Name IN (Select Names FROM Person Where Names LIKE 
         ISNULL( NULLIF( @Name_, '' ), '%' ))
AND 
于 2013-09-05T18:52:09.183 に答える
1

ほぼ間違いなく、2 つの選択で IF ステートメントを使用する必要があります。例えば

IF @Name IS NULL
    BEGIN
        SELECT  *
        FROM    Person
    END
ELSE
    BEGIN
        SELECT  *
        FROM    Person
        --WHERE Name LIKE '%' + @Name + '%'
        WHERE   Name = @Name
    END

注意LIKE : ワイルドカードがなくても equals , と変わらないため、 like を equals に変更しました。パフォーマンスの点では何の違いもありませんが、クエリを読む次の人にとってあいまいさがなくなります。正確でない一致が必要な場合は、コメントアウトされたものを使用し、WHERE必要に応じてワイルドカードを削除してください。

その理由はIF、2 つのクエリの実行計画が大きく異なる可能性があるためです。ただし、それらを 1 つのクエリに結合することで、オプティマイザにいずれかの計画を選択させることになります。次のスキーマを想像してください。

CREATE TABLE Person
(       PersonID        INT IDENTITY(1, 1) NOT NULL,
        Name            VARCHAR(255) NOT NULL,
        DateOfBirth     DATE NULL
    CONSTRAINT PK_Person_PersonID PRIMARY KEY (PersonID)
);
GO
CREATE NONCLUSTERED INDEX IX_Person_Name ON Person (Name) INCLUDE (DateOfBirth);
GO
INSERT Person (Name)
SELECT  DISTINCT LEFT(Name, 50)
FROM    sys.all_objects;
GO

CREATE PROCEDURE GetPeopleByName1 @Name VARCHAR(50)
AS
    SELECT  PersonID, Name, DateOfBirth
    FROM    Person
    WHERE   Name IN (SELECT Name FROM Person WHERE Name LIKE ISNULL(@Name, Name));
GO

CREATE PROCEDURE GetPeopleByName2 @Name VARCHAR(50)
AS
    IF @Name IS NULL
        SELECT  PersonID, Name, DateOfBirth
        FROM    Person
    ELSE
        SELECT  PersonID, Name, DateOfBirth
        FROM    Person
        WHERE   Name = @Name;
GO

ここで、値がある場合とない場合の両方の手順を実行すると、次のようになります。

EXECUTE GetPeopleByName1 'asymmetric_keys';
EXECUTE GetPeopleByName1 NULL;

EXECUTE GetPeopleByName2 'asymmetric_keys';
EXECUTE GetPeopleByName2 NULL;

結果は両方の手順で同じですが、最初の手順では毎回同じ計画が得られますが、2 番目の手順では 2 つの異なる計画が得られます。どちらも最初の手順よりもはるかに効率的です。

ここに画像の説明を入力

を使用できない場合IF(たとえば、インライン テーブル値関数を使用している場合) は、以下を使用して同様の結果を得ることができますUNION ALL

SELECT  PersonID, Name, DateOfBirth
FROM    Person
WHERE   @Name IS NULL
UNION ALL
SELECT  PersonID, Name, DateOfBirth
FROM    Person
WHERE   Name = @Name;

これは IF を使用するほど効率的ではありませんが、最初のクエリよりも効率的です。要するに、少ないほど常に多いとは限らないということです。はい、usingIFはより冗長であり、より多くの作業を行っているように見えるかもしれませんが、実際にははるかに少ない作業を行っており、はるかに効率的です。

于 2013-09-06T10:25:41.203 に答える
1

CASE ステートメントは必要ありません。ネストされた OR 条件を使用するだけです。

AND (   Name IN (Select Names FROM Person Where Names like @Name_)
    OR
        @Name_ IS NULL 
    )
AND
于 2013-09-05T18:52:50.063 に答える
1

これは機能します

DECLARE @Name NVARCHAR(100)

SET @Name = ''

DECLARE @Person TABLE ( NAME NVARCHAR(100) )

INSERT  INTO @Person VALUES  ( 'fred' )
INSERT  INTO @Person VALUES  ( 'jo' )

DECLARE @Temp TABLE
    (
      id INT ,
      NAME NVARCHAR(100)
    )

INSERT  INTO @Temp ( id, NAME ) VALUES  ( 1, N'' )
INSERT  INTO @Temp ( id, NAME ) VALUES  ( 5, N'jo' )
INSERT  INTO @Temp ( id, NAME ) VALUES  ( 2, N'fred' )
INSERT  INTO @Temp ( id, NAME ) VALUES  ( 3, N'bob' )
INSERT  INTO @Temp ( id, NAME ) VALUES  ( 4, N'' )

SELECT  * FROM    @Temp
WHERE   name IN ( SELECT    name
                  FROM      @Person
                  WHERE     name = CASE WHEN @name != '' THEN @Name
                                        ELSE name
                                   END )
于 2013-09-05T18:55:36.637 に答える