web-dev-qa-db-ja.com

T-SQLでNULLパラメータを無視する

パラメータのリストを渡して、NULLのパラメータを無視できるようにしたい。そのため、クエリは事実上、フィルターが存在しないふりをして無視します。

私はこのようにそれをしていました:

(@thing IS NULL or Thing=@thing) 

これは正しいですか、もしそうなら、それは悪いパフォーマンスをしますか? SQLを個別に作成するよりもはるかに遅いようです。

これを行うための最適な方法は何ですか?

修繕! MarcGravellの回答を参照してください。要約すると、IS NULLを何度も使用すると、bigパフォーマンスが低下します。

24
Damien

これらを2つ以上取得すると、そうです。かなり遅くなり始めます。このような場合、生成されたTSQLを使用する傾向があります。

DECLARE @sql nvarchar(4000)
SET @sql = /* core query */

IF @name IS NOT NULL
    SET @sql = @sql + ' AND foo.Name = @name'

IF @dob IS NOT NULL
    SET @sql = @sql + ' AND foo.DOB = @dob'

// etc

EXEC sp_ExecuteSQL @sql, N'@name varchar(100), @dob datetime',
        @name, @dob

Sp_ExecuteSQLはクエリプランをキャッシュするため、同じ引数を持つクエリはプランを再利用できる可能性があることに注意してください。

欠点は、SPROCに署名しない限り、呼び出し元にはテーブルに対するSELECTアクセス許可が必要なことです(SPROCに対するEXECアクセス許可だけではありません)。

21
Marc Gravell

私はそれをこのように扱います。

WHERE Thing = ISNULL(@Thing, Thing)

Where句のフィルターとしてパラメーターを使用しているだけの場合、これは非常にうまく機能します。 nullの場合、パラメーターは無視されます。

12
Brendan Enrick

私は一般的に使用します

WHERE (id = @id OR @id IS NULL)
AND (num = @num OR @num IS NULL)

等.

7
atfergs

このシナリオで過去に使用した手法は、WHERE句の一部としてCOALESCE関数を利用することです。 Books Onlineは、関数に関するより詳細な情報を提供しますが、説明したシナリオで関数を使用する方法のスニペットを次に示します。

create procedure usp_TEST_COALESCE
(
    @parm1 varchar(32) = null,
    @parm2 varchar(32) = null,
    @parm3 int = null
)
AS

SELECT * 
FROM [TableName]
WHERE Field1 = COALESCE(@parm1, Field1)
AND Field2 = COALESCE(@parm2, Field2)
AND Field3 = COALESCE(@parm3, Field3)

COALESCE関数は、引数から最初のnull以外の式を返します。上記の例では、パラメーターのいずれかがnullの場合、COALESCE関数は基になるフィールドの値を使用します。

この手法を使用する際の重要な注意点の1つは、テーブルの基になるフィールド(where句を構成する)がnull不可である必要があることです。

2
Tim Lentine

「ケーススタディ:注文の検索」というタイトルのセクションで、次の リンク を確認してください。これにより、すべてのオプションが詳細に調査され、これらの各オプションに関連するコストの概要がわかります。警告、COALESCEを使用するときは、それがあなたが思っているものを返さないかもしれないので、非常に注意してください。

よろしく、

ティム

1
user466015

それが「最適な」方法であるかどうかはわかりませんが、これは、同じ目的でストアドプロシージャで行うこととまったく同じです。私の直感では、これは、純粋に実行プランの観点から、動的に作成されたクエリよりも高速です。もう1つのオプションは、渡すこれらの「フラグ」の組み合わせごとにクエリを作成することですが、実際にはそれほどスケーラブルではありません。

1
Sean Bright

これは私が通常使用する方法です。 @thingがnullの場合、ステートメントはtrueに短絡するはずであり、したがってテーブルスキャンを必要としないため、非効率である理由はわかりません。この比較によってクエリが遅くなっているという証拠はありますか?そうでなければ、私はそれについて心配しません。

0
Karmic Coder

パラメータを宣言するときに、nullなどの値を設定した場合は、もちろん必要な場合を除いて、値を渡す必要はありません。この機能を使用して、別のクエリを実行する必要があるかどうかにフラグを立てます。これは、パラメータがnullでない特別な場合です。

私は通常、このようにチェックします

IFフィールドIS NULL

0
Josh Mein

ありがとう、これは役に立ちました。上記の潜在的なパフォーマンス上の利点のため、sp_ExecuteSQLメソッドを使用することにしました。私はあなたが役に立つと思うかもしれないそれについて少し違う見方をしています。

DECLARE @sql nvarchar(4000) 
DECLARE @where nvarchar(1000) =''

SET @sql = 'SELECT * FROM MyTable'

IF @Param1 IS NOT NULL 
    SET @where = @where + ' AND Field1 = @Param1'

IF @Param2 IS NOT NULL 
    SET @where = @where + ' AND Field2 = @Param2' 

IF @Param3 IS NOT NULL 
    SET @where = @where + ' AND Field3 = @Param3' 

-- Add WHERE if where clause exists, 1=1 is included because @where begins with AND
IF @where <> ''
    SET @sql = @sql + ' WHERE 1=1' + @where

--Note that we could also create order parameters and append here
SET @sql = @sql + ' ORDER BY Field1'
0
user247632

Thing(列の値)もNULL可能である場合は、次を使用します。アプローチ:

WHERE COALESCE(Thing,'')=COALESCE(@thing,Thing,'')
0
variable