テーブル値パラメーターを使用してこれを処理できます。アプリケーション層は
のようになりますC#
var tvp = new DataTable();
tvp.Columns.Add("Id", typeof(int));
foreach(var id in RecIdsToDelete)
tvp.Rows.Add(new {id});
var connection = new SqlConnection("your connection string");
var delete = new SqlCommand("your stored procedure name", connection)
{
CommandType = CommandType.StoredProcedure
};
delete
.Parameters
.AddWithValue("@ids", tvp)
.SqlDbType = SqlDbType.Structured;
delete.ExecuteNonQuery();
SQL
IF NOT EXISTS(SELECT * FROM sys.table_types WHERE name = 'IDList')
BEGIN
CREATE TYPE IDList AS TABLE(ID INTEGER)
END
CREATE PROCEDURE School.GroupStudentDelete
(
@IDS IDLIST READONLY
)
AS
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRANSACTION
DECLARE @Results TABLE(id INTEGER)
DELETE
FROM TblName
WHERE Id IN (SELECT ID FROM @IDS)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
PRINT ERROR_MESSAGE();
ROLLBACK TRANSACTION
THROW; -- Rethrow exception
END CATCH
GO
このアプローチには、文字列を構築するよりも多くの利点があります
- アプリケーション レイヤーでクエリを作成することを避け、関心の分離を作成します
- より簡単に実行計画をテストし、クエリを最適化できます
- 指定されたアプローチではパラメータ化されたクエリを使用して IN 句を作成できないため、SQL インジェクション攻撃に対する脆弱性が低くなります
- コードがより読みやすく、わかりやすくなっています
- 過度に長い文字列を作成することはありません
パフォーマンス
大規模なデータセットでの TVP のパフォーマンスについて、いくつかの考慮事項があります。
TVP は変数であるため、統計を編集しません。これは、クエリ オプティマイザが実行計画を時々ごまかす可能性があることを意味します。これが発生した場合、いくつかのオプションがあります:
- set
OPTION (RECOMPILE)
インデックス作成が問題となる TVP ステートメント - TVP をローカル一時ファイルに書き込み、そこにインデックスを設定します
TVP に関する素晴らしい記事はこちら パフォーマンスに関する考慮事項と、いつ何を期待するかについての適切なセクションがあります。
そのため、文字列パラメーターの制限に達することが心配な場合は、テーブル値パラメーターを使用することをお勧めします。しかし、最終的には、使用しているデータ セットについて詳しく知らなければ、何とも言えません。