web-dev-qa-db-ja.com

オプションの「WHERE」パラメーターを持つストアード・プロシージャー

ユーザーがいくつかのデータ(ステータス、日付など)を介してDigにさまざまなパラメーターを指定できるフォームがあります。

次のようなクエリを作成できます。

SELECT * FROM table WHERE:
status_id = 3
date = <some date>
other_parameter = <value>

etc.各WHEREはオプションです(status = 3ですべての行を選択したり、date = 10/10/1980ですべての行を選択したり、status = 3 AND date = 10/10/1980ですべての行を選択したりできます。

多数のパラメーターがあり、すべてオプションである場合、動的ストアード・プロシージャーを構成する最良の方法は何ですか?

MySQL、Oracle、SQLServerなど、さまざまなDBに取り組んでいます。

40
pistacchio

これを達成する最も簡単な方法の1つ:

SELECT * FROM table 
WHERE ((@status_id is null) or (status_id = @status_id))
and ((@date is null) or ([date] = @date))
and ((@other_parameter is null) or (other_parameter = @other_parameter))

これにより、動的SQLが完全に排除され、1つ以上のフィールドで検索できるようになります。動的SQLを排除することにより、SQLインジェクションに関するさらに別のセキュリティ上の懸念を取り除きます。

59
NotMe

次のような手順を作成します。

CREATE PROCEDURE [dbo].[spXXX]
    @fromDate datetime = null,
    @toDate datetime = null,
    @subCode int = null
as
begin
set NOCOUNT ON
/* NOCOUNT limits the server feedback on select results record count */
SELECT
    fields...
FROM
    source
WHERE
    1=1
--Dynamic where clause for various parameters which may or may not be passed in.
and ( @fromDate is null or [dateField] >= @fromDate)
and ( @toDate is null or [dateField] <= @toDate)
and ( @subCode is null or subCode= @leaveTypeSubCode)
order by fields...

これにより、0個のパラメーター、すべてのパラメーター、または#個のパラメーターを使用してプロシージャを実行できます。

13
Eppz

これは私が使うスタイルです:

t-sql

SELECT    *        
FROM    table        
WHERE     
status_id    =    isnull(@status_id ,status_id)     
and    date    =    isnull(@date ,date )     
and    other_parameter    =    isnull(@other_parameter,other_parameter) 

Oracle

SELECT    *        
FROM    table        
WHERE     
status_id    =    nval(p_status_id ,status_id)     
and    date    =    nval(p_date ,date )     
and    other_parameter    =    nval(p_other_parameter,other_parameter)
5
Rich

それを行うための読みやすく保守可能な方法(JOIN/APPLYでも使用可能):

where 
      (@parameter1 IS NULL OR your_condition1)
  and (@parameter2 IS NULL OR your_condition2) 
-- etc

ただし、実行プランはNULL値を無視せず、大規模なパフォーマンスループホールを生成するため(例:すべてのテーブルをスキャンしてNULL値を検索する)、ほとんどの大きなテーブル(さらにJOIN/APPLYを使用)ではお勧めできません。

SQL Serverの迂回方法は、クエリでWITH(RECOMPILE)オプションを使用することです(SQL 2008 SP1 CU5(10.0.2746)以降で使用可能)。

これを(パフォーマンスに関して)実装する最良の方法は、可能な組み合わせごとに1つ、IF ... ELSEブロックを使用することです。たぶん疲れ果てているかもしれませんが、最高のパフォーマンスが得られ、データベース設定は関係ありません。

詳細が必要な場合は、KMを検索できます。答え ここ

4
Lostblue

あなたは次のようなことができます

WHERE 
(
 ParameterA == 4 OR ParameterA IS NULL
)

AND
(
 ParameterB == 12 OR ParameterB IS NULL
)
3
kemiller2002

SQL文字列の動的な構築を回避したい場合(多くの場合は回避するのが最善です)、where句の各基準をデフォルト値と比較することで、ストアドプロシージャでこれを行うことができます。これは、「無視」に相当します。例えば。:

select * from Table where
   (@Col1 IS NULL OR Col1 = @Col1) /*If you don't want to filter in @col, pass in NULL*/
   AND
   (@Col2 IS NULL OR Col2 = @Col2)
1
JonoW