T-SQL 無原生陣列型別,需將多值參數序列化為字串或 XML 傳入預存程序。
CREATE PROCEDURE UpdateSpecialList
@ProductIdArray VARCHAR(800),
@ModuleId INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE @PtrPrev INT = 1, @PtrCurr INT, @PId INT;
BEGIN TRAN;
DELETE FROM ProductListSpecial WHERE ModuleId = @ModuleId;
-- 處理第一個值 (無前置逗號)
SET @PtrCurr = CHARINDEX(',', @ProductIdArray, @PtrPrev);
IF @PtrCurr = 0 SET @PtrCurr = LEN(@ProductIdArray) + 1;
SET @PId = CAST(SUBSTRING(@ProductIdArray, @PtrPrev, @PtrCurr - @PtrPrev) AS INT);
INSERT INTO ProductListSpecial (ModuleId, ProductId) VALUES (@ModuleId, @PId);
SET @PtrPrev = @PtrCurr + 1;
-- 迴圈處理剩餘
WHILE @PtrPrev <= LEN(@ProductIdArray)
BEGIN
SET @PtrCurr = CHARINDEX(',', @ProductIdArray, @PtrPrev);
IF @PtrCurr = 0 SET @PtrCurr = LEN(@ProductIdArray) + 1;
SET @PId = CAST(SUBSTRING(@ProductIdArray, @PtrPrev, @PtrCurr - @PtrPrev) AS INT);
INSERT INTO ProductListSpecial (ModuleId, ProductId) VALUES (@ModuleId, @PId);
SET @PtrPrev = @PtrCurr + 1;
END
IF @@ERROR = 0 COMMIT TRAN ELSE ROLLBACK TRAN;
END
GO
CREATE PROCEDURE UpdateSpecialList_XML
@ProductIdXML NVARCHAR(2000),
@ModuleId INT
AS
BEGIN
SET NOCOUNT ON;
IF @ProductIdXML IS NULL OR LEN(LTRIM(RTRIM(@ProductIdXML))) = 0 RETURN;
DECLARE @hDoc INT;
EXEC sp_xml_preparedocument @hDoc OUTPUT, @ProductIdXML;
DELETE FROM ProductListSpecial WHERE ModuleId = @ModuleId;
INSERT INTO ProductListSpecial (ModuleId, ProductId)
SELECT @ModuleId, Id
FROM OPENXML(@hDoc, '/Products/Id', 2)
WITH (Id INT '.');
EXEC sp_xml_removedocument @hDoc;
END
GO
// 字串版
string ids = "1,2,3,4,5";
cmd.Parameters.AddWithValue("@ProductIdArray", ids);
// XML 版
string xml = "1 2 3 ";
cmd.Parameters.AddWithValue("@ProductIdXML", xml);
| 維度 | 字串分割 | XML + OPENXML |
|---|---|---|
| 相容性 | 所有版本 | SQL 2000+ (需 MSXML) |
| 效能 | 中等 (迴圈插入) | 高 (集合操作、剖析優化) |
| 可讀性/維護性 | 低 | 高 (結構化、可擴充屬性) |
| 資料型別支援 | 單一型別 | 多欄位、多型別、巢狀結構 |
建議:SQL Server 2000/2005 專案優先採用 XML 方案;2008+ 可直接使用 資料表值參數 (TVP),原生支援陣列傳遞,效能最佳且程式碼最簡潔。