需求:定期將特定目錄下的多個 CSV/文字檔一次性匯入資料庫。本文提供兩種純 T-SQL 方案:xp_cmdshell + BULK INSERT (資料庫端執行) 與 xp_cmdshell + BCP.exe (客戶端工具),並內建匯入記錄功能。
CREATE DATABASE Bank; GO
USE Bank; GO
CREATE TABLE Account (
ID INT, Name VARCHAR(100), AccountNo VARCHAR(100), Balance MONEY
);
CREATE TABLE LogTable (
ID INT IDENTITY(1,1), Query VARCHAR(1000), ImportedDate DATETIME DEFAULT GETDATE()
);
-- 建立測試檔案 C:\MyImport\a.csv, b.csv, c.csv (內容略)
前提:SQL Server 服務帳號對檔案目錄具讀取權限;檔案需可從伺服器端路徑存取 (本機路徑或 UNC 路徑)。
CREATE PROCEDURE usp_ImportMultipleFiles
@FilePath VARCHAR(500), -- 目錄路徑,結尾需有 \
@Pattern VARCHAR(100), -- 檔案模式 *.csv
@TableName VARCHAR(128) -- 目標資料表
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Query VARCHAR(1000), @MaxID INT, @Cnt INT = 0, @FileName VARCHAR(100);
-- 1. 取得檔案清單
CREATE TABLE #Files (Name VARCHAR(200));
INSERT #Files EXEC master.dbo.xp_cmdshell 'dir "' + @FilePath + @Pattern + '" /b';
DELETE #Files WHERE Name IS NULL OR Name NOT LIKE '%.%';
-- 2. 加上流水號
SELECT IDENTITY(INT,1,1) AS ID, Name INTO #Seq FROM #Files;
DROP TABLE #Files;
SELECT @MaxID = MAX(ID) FROM #Seq;
-- 3. 迴圈匯入
WHILE @Cnt < @MaxID
BEGIN
SET @Cnt += 1;
SELECT @FileName = Name FROM #Seq WHERE ID = @Cnt;
SET @Query = 'BULK INSERT ' + QUOTENAME(@TableName) +
' FROM "' + @FilePath + @FileName + '"' +
' WITH (FIELDTERMINATOR = '','', ROWTERMINATOR = ''\n'', FIRSTROW = 1)';
EXEC (@Query);
INSERT LogTable (Query) VALUES (@Query); -- 記錄匯入指令
END
DROP TABLE #Seq;
END
GO
-- 執行範例
EXEC usp_ImportMultipleFiles 'C:\MyImport\', '*.csv', 'Account';
EXEC usp_ImportMultipleFiles 'C:\MyImport\', '*.*', 'Account';
前提:SQL Server Agent 服務帳號具檔案目錄與目標伺服器存取權;BCP.exe 需在伺服器路徑中。
CREATE PROCEDURE usp_ImportMultipleFilesBCP
@ServerName VARCHAR(128), @DatabaseName VARCHAR(128),
@FilePath VARCHAR(500), @Pattern VARCHAR(100), @TableName VARCHAR(128)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Query VARCHAR(2000), @MaxID INT, @Cnt INT = 0, @FileName VARCHAR(100);
CREATE TABLE #Files (Name VARCHAR(200));
INSERT #Files EXEC master.dbo.xp_cmdshell 'dir "' + @FilePath + @Pattern + '" /b';
DELETE #Files WHERE Name IS NULL OR Name NOT LIKE '%.%';
SELECT IDENTITY(INT,1,1) AS ID, Name INTO #Seq FROM #Files;
DROP TABLE #Files;
SELECT @MaxID = MAX(ID) FROM #Seq;
WHILE @Cnt < @MaxID
BEGIN
SET @Cnt += 1;
SELECT @FileName = Name FROM #Seq WHERE ID = @Cnt;
-- BCP 參數:-T 信任連線 -c 字元模式 -r\n 列結束 -t, 欄位分隔
SET @Query = 'bcp "' + @DatabaseName + '.dbo.' + @TableName + '" in "'
+ @FilePath + @FileName + '" -S' + @ServerName + ' -T -c -r\n -t,';
SET @Query = 'master.dbo.xp_cmdshell ' + QUOTENAME(@Query, '''');
EXEC (@Query);
INSERT LogTable (Query) VALUES (@Query);
END
DROP TABLE #Seq;
END
GO
| 需求 | 設定方式 |
|---|---|
| 啟用 xp_cmdshell | EXEC sp_configure 'show advanced options',1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell',1; RECONFIGURE; (僅 sysadmin 可執行) |
| 檔案系統權限 | SQL Server 服務帳號 (或 Agent 帳號) 需對匯入目錄具 讀取/列出資料夾 NTFS 權限 |
| UNC 路徑支援 | 使用 \\Server\Share\Path 而非對應磁碟機,避免服務帳號無法存取網路磁碟機 |
| 防止 SQL 注入 | 參數 @TableName/@FilePath 應加入白名單驗證或使用 QUOTENAME |