編集 - 可能であれば、LINQ ベースの ORM の設定
ADO でこれを行う必要がない場合、より良い解決策は、最終的にパラメーター化されたアドホック SQL を構築する ORM を使用することです。これは両方の長所です。動的クエリの柔軟性が得られ、オプティマイザーを混乱させる冗長なフィルターがなく、クエリ プラン自体がキャッシュ可能であり、インジェクション攻撃などの厄介な問題から安全です。また、Linq ベースの ORM クエリを使用すると、読みやすくなります。
// Build up a non-materialized IQueryable<>
var usersQuery = db.Users;
if (!string.IsNullOrEmpty(userID))
{
usersQuery = usersQuery.Where(u => u.Name == userId);
}
// Of course, you wouldn't dream of storing passwords in cleartext.
if (!string.IsNullOrEmpty(anotherField))
{
usersQuery = usersQuery.Where(u => u.AnotherColumn == anotherField);
}
...
// Materialize (and execute) the query
var filteredUsers = usersQuery.ToList();
複雑なクエリについては、 PredicateBuilderを確認することをお勧めします
ADO / 手動クエリ作成
sp_executesql
以下のように、SQL を動的に構築するために使用できます。変数をパラメータ化すれば、SQL インジェクションや引用符のエスケープなどの問題から安全に処理されます。
CREATE PROCEDURE [dbo].[PROC001]
@userID varchar(20),
@pwdHash varchar(20),
@optionalParam1 NVARCHAR(50) = NULL -- Other optional parameters
AS
BEGIN
SET NOCOUNT ON
DECLARE @SQL NVARCHAR(MAX)
-- Mandatory / Static part of the Query here.
-- Cleartext passwords are verboten, and RTRIM is redundant in filters
SET @SQL = N'SELECT * FROM tUsers WHERE Name = @userID AND PwdHash = @pwdHash'
IF @OptionalParam1 IS NOT NULL
BEGIN
SET @SQL = @SQL + N' AND AnotherField = @OptionalParam1'
END
EXEC sp_executesql @SQL,
N'@userID varchar(20),
@pwdHash varchar(20),
@optionalParam1 NVARCHAR(50)'
,@userID = @userID
,@pwdHash = @pwdHash
,@optionalParam1 = @optionalParam1
END
Re、なぜWHERE (@x IS NULL OR @x = Column)
悪い考えなのですか?
(以下、私のコメントより)
「オプション パラメータ」パターンは、小さなテーブルで使用される場合、オプション フィルタの多数の順列をクエリするための「スイス アーミー ナイフ」としてうまく機能しますが、残念ながら、大きなテーブルでは、フィルタのすべての順列に対して 1 つのクエリ プランになります。これにより、パラメーター スニッフィングの問題により、オプションのパラメーターの特定の順列でクエリのパフォーマンスが低下する可能性があります。可能であれば、冗長なフィルターを完全に削除する必要があります。
Re: 述語で関数を適用するのはなぜ悪い考えなのですか?
例えば
WHERE SomeFunction(Column) = @someParameter
述部で関数を使用すると、RDBMS によるインデックスの使用が不適格となることがよくあります ( "non-sargable" )。
この場合、RTRIM
SQL サーバーは比較中に末尾のスペースを無視するため、 は不要です。