首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 批量插入/更新兩種模式:游標 vs 表變量+WHILE,附 split 函數依賴說明

     編輯:關於SqlServer

前置條件:字符串分割函數 split

兩種方案均依賴自定義表值函數 split(@str, @delimiter) 返回單列表(每行一個片段),請確保數據庫已部署該函數(網上開源實現眾多,此處不贅述)。

方案一:雙層游標(適合複雜邏輯、需逐行事務控制)

DECLARE @Data NVARCHAR(MAX) = '1,tanw;2,keenboy';  -- 格式:Id,Name;Id,Name...
DECLARE @dataItem NVARCHAR(100);

DECLARE data_cursor CURSOR LOCAL FAST_FORWARD FOR
    SELECT * FROM split(@Data, ';');  -- 外層:按分號切分記錄
OPEN data_cursor;
FETCH NEXT FROM data_cursor INTO @dataItem;

WHILE @@FETCH_STATUS = 0
BEGIN
    DECLARE @Id INT, @Name NVARCHAR(50);

    DECLARE dataItem_cursor CURSOR LOCAL FAST_FORWARD FOR
        SELECT * FROM split(@dataItem, ',');  -- 內層:按逗號切分字段
    OPEN dataItem_cursor;
    FETCH NEXT FROM dataItem_cursor INTO @Id;
    FETCH NEXT FROM dataItem_cursor INTO @Name;
    CLOSE dataItem_cursor; DEALLOCATE dataItem_cursor;

    -- ===== 在這裡寫業務邏輯:MERGE / IF EXISTS UPDATE ELSE INSERT =====
    -- MERGE INTO TargetTable USING (VALUES(@Id,@Name)) AS S(Id,Name) ...
    -- 或傳統 IF EXISTS ... UPDATE ... ELSE INSERT ...

    FETCH NEXT FROM data_cursor INTO @dataItem;
END
CLOSE data_cursor; DEALLOCATE data_cursor;

方案二:表變量 + WHILE 循環(集合思維、性能較好、易調試)

DECLARE @Data NVARCHAR(MAX) = 'tanw,keenboy';  -- 僅演示 Name 列表
DECLARE @Temp TABLE (Id INT IDENTITY(1,1), Name NVARCHAR(50));

INSERT @Temp SELECT * FROM split(@Data, ',');  -- 一次性拆分入表變量

DECLARE @Id INT, @Name NVARCHAR(50), @Results NVARCHAR(MAX) = '';

WHILE EXISTS (SELECT 1 FROM @Temp)
BEGIN
    SELECT TOP 1 @Id = Id, @Name = Name FROM @Temp;
    DELETE @Temp WHERE Id = @Id;
    SET @Results = @Results + @Name + ',';

    -- ===== 在這裡寫業務邏輯 =====
END

SELECT @Results AS ProcessedNames;

核心對比

維度游標表變量+WHILE
內存佔用低(流式處理)中(需載入全量到表變量)
並發/鎖較長持有鎖(游標默認鎖行)短鎖(單條 DELETE 快速釋放)
代碼複雜度高(雙層嵌套、資源釋放易漏)低(線性邏輯、自動清理)
適用場景極大數據流、需逐行提交事務、外部 API 調用中小批次、純數據庫邏輯、易維護

簡單批量插入:別用以上兩種!

若僅是「將分割後的數據批量 INSERT 同一張表」,請直接用 集合操作:

INSERT INTO TargetTable (Name)
SELECT * FROM split(@Data, ',');
-- 或配合 MERGE 實現 UPSERT
MERGE TargetTable AS T
USING (SELECT * FROM split(@Data, ',')) AS S(Name)
ON T.Name = S.Name
WHEN NOT MATCHED THEN INSERT (Name) VALUES (S.Name);

結語

游標是「手術刀」,精準但沉重;表變量+WHILE 是「瑞士軍刀」,輕便實用。現代 SQL Server (2016+) 優先考慮 STRING_SPLIT / OPENJSON 內置分割 + 集合化 MERGE,告別循環才是正道。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved