需在預存程序或批次腳本中動態建立暫存表,表名包含呼叫端電腦的主機名稱 (如 #temp_WORKSTATION01),結構固定。直接在 DDL 中使用變數會報錯:
-- ❌ 錯誤寫法
DECLARE @TableName CHAR(50);
SELECT @TableName = '#temp_' + HOST_NAME();
CREATE TABLE [dbo].[@TableName] (...); -- 語法錯誤:無法在 DDL 使用變數作為物件名稱
SQL Server DDL 不支援參數化物件名稱,必須構建字串並透過 EXEC 或 sp_executesql 執行。
DECLARE @TableName NVARCHAR(128);
DECLARE @SQL NVARCHAR(MAX);
-- 1. 取得主機名並移除非法字元 (如連字號)
SET @TableName = N'#temp_' + REPLACE(HOST_NAME(), N'-', N'');
-- 2. 構建動態 SQL,使用 QUOTENAME 防止注入與處理特殊字元
SET @SQL = N'CREATE TABLE ' + QUOTENAME(@TableName) + N' (
id INT PRIMARY KEY,
col NVARCHAR(200) NOT NULL,
created_dt DATETIME2 DEFAULT SYSUTCDATETIME()
);';
-- 3. 執行
EXEC sp_executesql @SQL;
-- 後續操作同樣需動態 SQL
-- INSERT: EXEC sp_executesql N'INSERT INTO ' + QUOTENAME(@TableName) + N' (id, col) VALUES (1, N''test'');';
-- SELECT: EXEC sp_executesql N'SELECT * FROM ' + QUOTENAME(@TableName) + N';';
-- DROP: EXEC sp_executesql N'DROP TABLE ' + QUOTENAME(@TableName) + N';';
| 技術點 | 說明 |
|---|---|
QUOTENAME() | 將識別符包裹在方括號 [] 中,自動處理內含空格、保留字、特殊字元,防止 SQL 注入。 |
sp_executesql vs EXEC() | 優先使用 sp_executesql:支援參數化、查詢計畫重用、型別安全;EXEC('string') 僅適合極簡單、無參數場景。 |
| 暫存表作用域 | #temp_... (Local Temp Table) 僅對當前 Session 可見,Session 結束自動清理;##temp_... (Global) 對所有 Session 可見,最後一個參考 Session 結束時清理。 |
| 主機名淨化 | HOST_NAME() 可能包含連字號、空格等非法識別符字元,REPLACE 或正則淨化必要。 |
若表結構也需動態,可建立結構定義表或使用 JSON/XML 傳遞欄位定義,再動態組裝 DDL。但強烈建議固定結構,動態結構會導致計畫快取膨脹、除錯困難、維護成本高。
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 動態 SQL + 暫存表 | 原生支援、隔離性好、自動清理 | 需動態 SQL 操作、計畫重用受限 | Session 級暫存資料、ETL 中繼 |
| 永久資料表 + GUID 後綴 | 可跨 Session、可索引、統計資訊完整 | 需手動清理、命名衝突風險 | 跨程序/作業共享中繼資料 |
資料表變數 @t TABLE(...) | 無重編譯、記憶體優先、自動清理 | 無統計資訊、大量資料效能差、無法動態命名 | 小資料量 (<1k rows)、固定結構 |
| 應用層建立 (C#/Java) | 型別安全、IDE 支援、易測試 | 多一次網路往返、連線池壓力 | 複雜邏輯、ORM 框架專案 |
NVARCHAR(MAX) 儲存動態 SQL,避免截斷。QUOTENAME() 處理。sp_executesql 並參數化資料值。TRY...CATCH 捕捉 DDL 錯誤並記錄。動態建表是 SQL Server 進階開發的必備技能,核心在於「字串構建 + QUOTENAME + sp_executesql」三部曲。掌握此模式,即可靈活應對「表名/欄位名/結構動態化」等多變需求,同時維護程式碼安全與可維護性。