使用 osql.exe 執行 SQL 腳本檔時,遭遇錯誤 「Missing end comment mark */」,但同樣腳本在 SSMS 查詢視窗執行完全正常。經排查發現,osql 解析器將註釋區塊內的 GO 視為批次結束,導致註釋解析狀態機錯亂,屬於 osql 早期版本的已知缺陷。
-- 測試腳本 TestScript.sql
/*
這是多行註釋
GO <-- 這行 GO 導致 osql 解析錯誤
繼續註釋內容
*/
SELECT 1;
GO
osql.exe -S .\SQLDEV -U sa -P MyRoot -b -n -r 1 -i ".\TestScript.sql" -o "c:\output.txt"
輸出錯誤:
osql Missing end comment mark "*/"
| 工具 | 解析器行為 | 結果 |
|---|---|---|
| SSMS / sqlcmd | 完整 T-SQL 解析器,識別 /* ... */ 區塊內的 GO 為註釋內容,不作為批次分隔 | ✅ 正常 |
| osql (舊版) | 簡易行導向解析,遇到行首 GO 即視為批次結束,忽略註釋狀態 | ❌ 錯誤:以為註釋在 GO 前結束,後續找不到 */ |
/*
這是多行註釋
-- GO 已移除或改為註釋
繼續註釋內容
*/
SELECT 1;
GO
/*
這是多行註釋
-- GO <-- 單行註釋,osql 不會誤判
繼續註釋內容
*/
SELECT 1;
GO
sqlcmd -S .\SQLDEV -U sa -P MyRoot -b -i ".\TestScript.sql" -o "c:\output.txt"
sqlcmd 為 osql 繼任者 (SQL 2005+),完整支援 T-SQL 解析、Unicode、變數替換、錯誤處理osql 自 SQL Server 2012 起標記淘汰,2016 移除在部署前以 PowerShell/Python 移除註釋內的 GO:
# PowerShell 範例
$content = Get-Content -Raw -Path ".\Deploy.sql"
# 簡易移除 /* ... */ 內的 GO (需更健全的解析器)
$content = [regex]::Replace($content, '(?s)/\*.*?\*/', {
return $_.Value.Replace("GO", "-- GO")
})
Set-Content -Path ".\Deploy_Clean.sql" -Value $content
osql 為 sqlcmd:所有部署腳本、維護作業、CI/CD 管線/* ... */ 內嚴禁出現 GO、;、未閉合引號等可能干擾解析器的標記GO 必須獨佔一行、行首無縮進、大寫,避免出現在字串常數、註釋、動態 SQL 中sqlcmd -f 65001 指定編碼GO 導致「Missing end comment mark」GO 被誤判為批次分隔:on error、:setvar 等進階腳本控制指令結論:osql 屬舊世代工具,解析器缺陷無修補可能。遇到此類問題,直接遷移至 sqlcmd 是唯一正確、永久的解決方案,同時獲得 Unicode、變數化、錯誤控制等現代化功能。