前言
SQLCMD 是隨 SQL Server 一起安裝的命令列工具,日常用途涵蓋執行維護腳本、匯入匯出資料、串接 Windows 排程器自動跑批次作業。比起 SSMS 的 GUI,它的優勢在於可以寫成批次檔、進版控、在沒有桌面環境的伺服器上執行。
SQLCMD 基本語法
常用旗標一覽:
1 | sqlcmd |
Windows 整合驗證(-E)
在 Windows 網域環境下,-E 比帳密更常用也更安全——執行帳號的 Windows 身份直接對應到 SQL Server 登入,不需要在指令或環境變數裡放密碼:
1 | sqlcmd -S ServerName -E -d MyDB -i "D:\scripts\maintenance.sql" |
若伺服器設定了具名執行個體或非預設埠:
1 | sqlcmd -S ServerName\SQLEXPRESS -E -d MyDB -Q "SELECT @@VERSION" |
主要應用場景
1. 執行 SQL 指令檔
-i 一次只接受一個輸入檔,重複寫 -i file1 -i file2 後面的會蓋掉前面的,只有最後一個生效。要依序執行多個腳本,有兩種做法:
做法一:用 :r 在主腳本內 include 其他檔案
建一支 run_all.sql,用 :r 逐一引入:
1 | -- run_all.sql |
然後只呼叫一次 sqlcmd:
1 | sqlcmd -S ServerName -E -d MyDB -i "D:\scripts\run_all.sql" -o "D:\logs\run.log" |
做法二:在批次檔裡分次呼叫
1 | @echo off |
2. 資料匯入
執行外部 SQL 腳本把資料匯入目標資料庫(常見於還原純文字備份或跑遷移腳本):
1 | sqlcmd -S 192.168.0.3 -E -d TargetDB -i "D:\backup.sql" |
若伺服器只開 SQL Server 驗證:
1 | sqlcmd -S 192.168.0.3 -U DBAdmin -P MyPassword -d TargetDB -i "D:\backup.sql" |
-r 旗標的用途是把錯誤訊息導向 stderr(以便在 shell 管線中分離正常輸出與錯誤),跟「匯入」本身無直接關係,加不加不影響匯入行為。
3. 查詢結果輸出
用 -Q 加 -o 把查詢結果寫入檔案:
1 | sqlcmd -S ServerName -E -d SourceDB -Q "SELECT * FROM Users" -o "D:\export.txt" |
注意:-o 輸出的是 sqlcmd 預設的純文字表格格式(含欄位對齊空白),不是 CSV。若要後續用程式處理這份輸出,建議改用 -s"," 設定欄位分隔符加 -W 去掉尾端空白:
1 | sqlcmd -S ServerName -E -d SourceDB -Q "SET NOCOUNT ON; SELECT col1, col2 FROM Users" -s"," -W -o "D:\export.csv" |
若資料量大或格式需求複雜,bcp 工具是更適合的選擇。
4. 資料庫備份
透過 SQLCMD 執行 BACKUP 語句:
1 | :: 完整備份 |
5. 自動化排程(批次檔)
結合 Windows 工作排程器:
1 | @echo off |
進階技巧
變數使用
SQLCMD 腳本變數($(變數名))只在腳本內容或 -Q 的查詢字串中做替換,不適用於 -S、-U、-P 這些連線參數——那些位置由 shell 展開,不是 SQLCMD 處理。
用 -v 定義變數,在腳本或查詢字串內引用:
1 | :: 腳本內使用(maintenance.sql 內寫 $(DB)) |
注意:變數值直接做字串替換,沒有任何 quoting 或逸出。若變數值來自外部輸入,攻擊者可以注入任意 SQL。僅在受控的管理腳本中使用 -v,不要把外部輸入直接當作變數值帶入。
若要讓伺服器名稱也可替換,用 shell 變數帶入連線參數(批次檔的 %SERVER%、PowerShell 的 $env:SERVER);或在腳本內用 :connect $(MyServer) 語法。
錯誤處理
SQLCMD 有兩套獨立的機制,用途不同:
- SQLCMD 端:
:on error exit讓 sqlcmd 遇到批次錯誤時立即結束並回傳非零結束碼。 - T-SQL 層:
BEGIN TRY / BEGIN CATCH在伺服器端攔截執行錯誤。
:setvar、:on error 等 SQLCMD 命令在解析階段就無條件處理,跟 T-SQL 執行流程無關——把 :setvar 寫進 BEGIN CATCH 裡不會讓它變成「只在錯誤時執行」。
實務上兩者分開各司其職:
1 | :: 批次檔層:判斷 sqlcmd 結束碼 |
1 | -- task.sql:T-SQL 層的錯誤處理 |
安全注意事項
密碼管理:避免把密碼直接寫在指令裡(容易出現在 shell history 和批次檔裡)。有兩種常見替代方式:
1 | :: 方式一:用 SQLCMDPASSWORD 環境變數 |
1 | :: 方式二(Windows 網域環境首選):-E 整合驗證,完全不需要密碼 |
其他要點:
- 大型檔案匯入時建議用批次處理,避免單一交易過大導致記錄檔爆增
- SQLCMD 執行帳號應遵循最小權限原則,不要用
sa跑日常維護腳本 - 務必加入錯誤處理與記錄機制,方便排除問題




