現代のBIおよびCRMシステムでは、ユーザー定義のフィルターを実装する必要があることが多く、日付、性別、ステータス、タグなどの任意の条件を柔軟に組み合わせ、SQL言語上でそれらを正しく交差させて結合することが重要です。生成されたコードは読みやすく、簡単に変更でき、期待される結果を得られる必要があります。
多くの場合、開発者はユーザー定義のフィルターからWHERE句を即興で生成し、多くのAND/ORを使うことで論理的エラーやメンテナンスが難しいクエリを引き起こします。この問題は、フィルターの値が存在しない場合や、IN/EXISTS/LIKEと組み合わされる場合にさらに悪化します。
動的フィルターには、「条件が指定されていない場合は常にTRUEとなるOR条件」というパターンが便利です:
SELECT * FROM users WHERE (status = @status OR @status IS NULL) AND (gender = @gender OR @gender IS NULL) AND (created >= @from_date OR @from_date IS NULL) AND (city IN (@cities) OR @cities IS NULL);
または、動的SQLを使用することもできます:
DECLARE @sql NVARCHAR(MAX) = N'SELECT * FROM users WHERE 1=1'; IF @status IS NOT NULL SET @sql += N' AND status = @status'; IF @gender IS NOT NULL SET @sql += N' AND gender = @gender'; -- ... EXEC sp_executesql @sql, N'@status NVARCHAR(10),@gender NVARCHAR(10)', @status, @gender;
主な特徴:
条件が存在するかどうかをチェックする代わりに、WHERE 1=1をどこでも使用できますか?
いいえ、1=1はWHERE句を連結するためのスタート条件であり、フィルターを置き換えるものではなく、クエリの生成を便利にするためにのみ使用されます。
IN()に空のリストが含まれると、どんな問題が発生しますか?
IN(NULL)またはIN()は常にfalseを返し、フィルターがない場合でも空のセットを返します。正しく機能させるためには、リストが空であるかどうかを別々に確認し、条件を全く含めないようにする必要があります。
このような構文はインデックスの使用とパフォーマンスにどのように影響を与えますか?
フィルターがORまたはNULLチェックで実装されている場合、多くのDBMSはインデックスを効果的に使用できなくなり、テーブル全体のスキャンが実行されます。プランナーがインデックスを選択できるようにするために、動的SQLまたはパラメータ化されたクエリを使用したフィルターのアプローチを適用するべきです。
10個のフィルターを持つ古典的なレポートで、コードは多くのORを使ってWHERE句を構築します。複数のフィルターが存在しない場合、結果は空のセット、または非常に大きなスキャンとなり、サーバへの負荷が何倍にもなります。
利点:
別の関数が指定されたパラメーターのみに基づいてフィルターを構築し、条件の各グループごとに別々のJOIN/FILTERを有効にします。WhereにはORやNULLに対する余分なチェックが含まれていません。
利点: