K tomu můžete použít parametry s hodnotou tabulky. Aplikační vrstva by vypadala asi jako
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
Tento přístup má oproti budování řetězců řadu výhod
- Vyhnete se vytváření dotazů v aplikační vrstvě, což vytváří oddělení obav
- Můžete snadněji testovat plány provádění a optimalizovat dotazy
- Jste méně zranitelní vůči útokům SQL injection, protože váš daný přístup by nebyl schopen použít parametrizovaný dotaz k vytvoření klauzule IN
- Kód je čitelnější a názornější
- Neskončíte vytvářením příliš dlouhých řetězců
Výkon
Existuje několik úvah o výkonu TVP na velkých souborech dat.
Protože TVP jsou proměnné, nesestavují statistiky. To znamená, že optimalizátor dotazů může někdy zfalšovat plán provádění. Pokud k tomu dojde, existuje několik možností:
- nastavte
OPTION (RECOMPILE)
na všech prohlášeních TVP, kde je indexování problémem - zapište TVP do místního tempa a nastavte indexování tam
Zde je skvělý článek o TVP s dobrou částí o aspektech výkonu a o tom, co lze kdy očekávat.
Pokud se tedy obáváte, že narazíte na limity řetězcových parametrů, tabulkové parametry mohou být tou správnou cestou. Ale nakonec je těžké říci, aniž byste věděli více o datové sadě, se kterou pracujete.