jj (1000 列),每列對應一張目標表table_index (序號, 資料表名)原始碼錯誤:嘗試直接使用變數 @table_name 作為表名 → T-SQL 不支援變數作為物件識別碼。
解法:動態 SQL + sp_executesql / EXEC()。
USE fff;
GO
CREATE PROCEDURE usp_BatchUpdateTables
AS
BEGIN
SET NOCOUNT ON;
DECLARE @table_name SYSNAME,
@qq INT, @tj INT, @yj INT, @ej INT, @sj INT,
@sij BIGINT, @wj BIGINT, @lj BIGINT, @zs BIGINT, @zjl CHAR(15);
-- 關聯查詢一次取得所有所需欄位,避免雙層游標
DECLARE cur CURSOR LOCAL FAST_FORWARD READ_ONLY FOR
SELECT b.資料表名, a.qq, a.tj, a.yj, a.ej, a.sj, a.sij, a.wj, a.lj, a.zs, a.zjl
FROM jj a
INNER JOIN table_index b ON a.table_index = b.序號;
OPEN cur;
FETCH NEXT FROM cur INTO @table_name, @qq, @tj, @yj, @ej, @sj, @sij, @wj, @lj, @zs, @zjl;
WHILE @@FETCH_STATUS = 0
BEGIN
-- 安全防禦:驗證表名合法性,防止 SQL 注入
IF @table_name NOT LIKE '%[^a-zA-Z0-9_@#$]%'
AND EXISTS (SELECT 1 FROM sys.objects WHERE name = @table_name AND type = 'U')
BEGIN
DECLARE @sql NVARCHAR(MAX);
SET @sql = N'INSERT INTO ' + QUOTENAME(@table_name) +
N' (qq, tj, yj, ej, sj, sij, wj, lj, zs, zjl) ' +
N'VALUES (@qq, @tj, @yj, @ej, @sj, @sij, @wj, @lj, @zs, @zjl)';
-- 參數化執行,效能優於 EXEC(字串),防注入
EXEC sp_executesql @sql,
N'@qq INT, @tj INT, @yj INT, @ej INT, @sj INT, @sij BIGINT, @wj BIGINT, @lj BIGINT, @zs BIGINT, @zjl CHAR(15)',
@qq, @tj, @yj, @ej, @sj, @sij, @wj, @lj, @zs, @zjl;
END
ELSE
BEGIN
PRINT '警告:跳過無效表名 ' + @table_name;
END
FETCH NEXT FROM cur INTO @table_name, @qq, @tj, @yj, @ej, @sj, @sij, @wj, @lj, @zs, @zjl;
END
CLOSE cur;
DEALLOCATE cur;
END;
GO
| 優化 | 原寫法 | 改進寫法 | 效益 |
|---|---|---|---|
| 游標合併 | 雙層游標 (外層 jj, 內層 table_index) | 單游標 JOIN 查詢 | 減少游標開銷、邏輯簡化 | 動態 SQL 參數化 | 字串拼接 VALUES('+@qq+',...) | sp_executesql + 參數定義 | 計畫重用、防注入、型別安全 |
| 表名驗證 | 無 | QUOTENAME + sys.objects 檢查 | 防止惡意表名注入、避免錯誤中斷 |
| 游標選項 | 預設 | LOCAL FAST_FORWARD READ_ONLY | 唯讀順向,最低資源佔用 |
| 錯誤處理 | 無 | TRY...CATCH (建議補充) | 單表失敗不影響後續、記錄日誌 |
-- 每 100 筆認可一次,避免長交易鎖定/日誌暴漲
DECLARE @batchCounter INT = 0;
WHILE @@FETCH_STATUS = 0
BEGIN
-- ... 執行 INSERT ...
SET @batchCounter += 1;
IF @batchCounter % 100 = 0
BEGIN
COMMIT TRANSACTION;
BEGIN TRANSACTION; -- 隱含交易模式下需顯式控制
END
FETCH NEXT FROM cur INTO ...;
END
COMMIT TRANSACTION; -- 尾數認可
| 方案 | 優點 | 缺點 | 適用性 |
|---|---|---|---|
| 動態 SQL + 游標 (本文) | 靈活、可參數化、邏輯集中 | 逐列執行、計畫緩存壓力 | 中等量級、邏輯複雜 |
| SSIS 套件 | 視覺化、平行、錯誤導向、記錄 | 部署複雜、需額外技能 | 企業級 ETL、長期維護 |
| 合併複寫 | 自動同步、衝突解決 | 拓撲複雜、延遲 | 異地多節點同步 |
| 分區表 | 單表管理、分區切換秒級 | 需重構結構、Enterprise Edition | 新架構設計階段 |
「偷懶」的最高境界是寫出可維護、可擴展、可觀測的自動化腳本。動態 SQL + 參數化 + 驗證 + 批次認可,是 T-SQL 自動化的專業標準配置。