適用情境
- 執行 .sql 腳本檔:建表、建預存程序、DDL 部署腳本,需在應用程式安裝/升級時自動執行。
- 大量資料操作逾時:UPDATE/DELETE 百萬列資料,透過 ADO/ADO.NET 執行極易逾時(CommandTimeout 預設 30 秒,即使調大也易遭網路/鎖定中斷)。
OSQL 簡介
- SQL Server 命令列查詢工具(
osql.exe),支援執行腳本檔、批次處理、非互動模式。
- SQL Server 2005+ 已由
sqlcmd 取代,功能更強(支援 Unicode、變數、錯誤處理)。
T-SQL 呼叫語法
EXEC master..xp_cmdshell
'osql -S "ServerName" -U "UserName" -P "Password" -i "ScriptFilePath"';
| 參數 | 說明 |
| -S | 伺服器名稱/實例 |
| -U / -P | 登入帳號密碼 |
| -i | 輸入腳本檔案路徑(.sql) |
| -o | 輸出結果/錯誤導向檔案 |
| -b | 發生錯誤時返回錯誤碼(供批次檔判斷) |
| -n | 移除編號提示符 |
| -w 寬度 | 輸出行寬度(預設 80) |
C++ Builder 實作:寫 .bat 再 ShellExecute
// 1. 產生 .bat 內容
AnsiString batContent =
"osql -S \"MyServer\" -U \"sa\" -P \"pwd\" "
"-i \"C:\\Scripts\\deploy_schema.sql\" "
"-o \"C:\\Logs\\deploy_$(date).log\" -b";
// 2. 寫入 .bat
AnsiString batPath = "C:\\Temp\\run_osql.bat";
std::ofstream ofs(batPath.c_str());
ofs << batContent.c_str();
ofs.close();
// 3. 執行
HINSTANCE hResult = ShellExecute(NULL, "open", batPath.c_str(), NULL, NULL, SW_HIDE);
if ((int)hResult <= 32) { /* 失敗處理 */ }
為何 OSQL 能解決逾時問題?
| 維度 | ADO/ADO.NET Execute | OSQL / sqlcmd |
| 執行位置 | 用戶端進程 → 網路 → 伺服器 | 用戶端進程啟動 OSQL → OSQL 直連伺服器 |
| 逾時控制 | 受 CommandTimeout/ConnectionTimeout 限制 | 無內建逾時,由伺服器端查詢執行時間決定 |
| 網路中斷影響 | 連線斷開即失敗 | OSQL 進程獨立,較穩健 |
| 大批次適用性 | 差(記憶體壓力、記錄日誌膨脹) | 佳(串流處理、可分批 GO 區塊) |
現代化替代:sqlcmd (SQL Server 2005+)
sqlcmd -S "ServerName" -U "UserName" -P "Password"
-i "ScriptFilePath" -o "OutputLog" -b -V 16
-V 16:嚴重性 ≥ 16 的錯誤返回錯誤碼。
- 支援
:setvar 變數替換、:on error exit 流程控制、Unicode 輸出。
進階自動化:SSIS / PowerShell / DACPAC
- SSIS 套件:資料流/執行 SQL 工作,部署至 SSISDB,支援參數化、記錄、事件處理。
- PowerShell + Invoke-Sqlcmd:原生 .NET 整合,物件導向結果處理,跨平台(Core)。
- DACPAC (Data-tier Application):資料庫結構版本化部署,
SqlPackage.exe /Action:Publish 自動比對差異產生增量腳本,CI/CD 首選。
實務建議
- 腳本檔案以
GO 分批,避免單一批次過大。
- 導出執行日誌(
-o),失敗時可追溯。
- 生產環境部署前,必須在測試環境完整演練。
- 考慮冪等性設計:
IF NOT EXISTS CREATE...、IF EXISTS DROP...。
- 敏感資訊(密碼)勿硬編碼於 .bat,使用環境變數、加密設定檔或 Windows 整合驗證(
-E)。
OSQL/sqlcmd 是資料庫腳本自動化部署、大量維護操作的經典利器,配合現代 CI/CD 流程可構建穩健的資料庫變更管理管道。