SQL Server 2016 SQL 代理令牌不工作
我在整個企業中的數十個 SQL 代理作業步驟中都有這個,它按預期工作:
sqlcmd -E -S $(ESCAPE_SQUOTE(SRVR)) -d master -Q "EXECUTE MyStoredProc etc..."
但是在我的新 SQL Server 2016 實例上,它只會產生一個命名管道連接錯誤(這是一個完整的紅鯡魚)。
另一方面,這在我的新伺服器上執行良好:
sqlcmd -E -S MyExplicitServerName -d master -Q "EXECUTE MyStoredProc etc..."
為什麼 SRVR 代幣不起作用?
如果我在命令提示符下啟動 sqlcmd 並告訴它列印
$(ESCAPE_SQUOTE(SRVR))
它會說:'SRVR' scripting vaiable not defined.
這是一個非常基本的、簡潔的安裝,只有預設實例。
好的,我現在認為這是 Windows Server 2016 的問題,因為這是我在 Windows Server 2016 上完成的第一個 SQL Server 2016 安裝。
在裝有 SQL Server 2016 的 Windows Server 2012 R2(標準)機器上,這適用於 SQL 代理 CmdExec 作業步驟:
sqlcmd -E -S $(ESCAPE_SQUOTE(SRVR)) -d master -Q "EXECUTE MyStoredProc etc..."
但是在我的帶有 SQL Server 2016 的新 Windows Server 2016(標準)上,上述方法不起作用。我必須這樣做:
C:\Windows\System32\cmd.exe -c sqlcmd -E -S $(ESCAPE_SQUOTE(SRVR)) -d master -Q "EXECUTE MyStoredProc etc..."
或者這也有效:
sqlcmd -E -S $(ESCAPE_SQUOTE(SRVR)) -d master -Q "EXECUTE MyStoredProc etc..." GO
這個
cmd.exe -c
論點(我不熟悉)是一個批處理終止器;來自微軟文件:指定批處理終止符。預設情況下,通過在一行中單獨鍵入單詞“GO”來終止命令並將其發送到 SQL Server。重置批處理終止符時,請勿使用 Transact-SQL 保留關鍵字或對作業系統具有特殊意義的字元,即使它們前面有反斜杠。
我不知道為什麼在這種情況下需要批處理終止器…
GO 命令和分號終止符
GO 命令
“GO”是批處理終止符。從技術上講,GO 命令甚至不是 Transact-SQL 語言的一部分。它實際上是 SQLCMD、OSQL 和 ISQL 實用程序使用的命令,也可以在查詢分析器和查詢編輯器視窗中使用。
**注意:**批處理不應與腳本混淆。批處理是一組送出以作為一個組執行的 T-SQL 語句。腳本只是一個包含一組 T-SQL 語句的文件。一個腳本可以包含多個批次。
如果您在 SSMS 中打開一個新選項卡並切換到 sqlcmd,則該命令是正常的
print $(ESCAPE_SQUOTE(SRVR))
不起作用,因為 $(variable) 是在 sqlcmd 中使用變數的語法,因此會出現錯誤消息。
請注意,令牌只能在 SQL 代理範圍內使用。
https://docs.microsoft.com/en-us/sql/ssms/agent/use-tokens-in-job-steps?view=sql-server-2017
我試圖在我方便的 2 個實例(SQL2014 和 SQL2016)中重現您的錯誤,並創建了以下作業,在兩個版本上都可以正常工作
USE [msdb] GO /****** Object: Job [token test] Script Date: 14/06/2018 21:14:35 ******/ BEGIN TRANSACTION DECLARE @ReturnCode INT SELECT @ReturnCode = 0 /****** Object: JobCategory [[Uncategorized (Local)]] Script Date: 14/06/2018 21:14:35 ******/ IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1) BEGIN EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]' IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback END DECLARE @jobId BINARY(16) EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name=N'token test', @enabled=1, @notify_level_eventlog=0, @notify_level_email=0, @notify_level_netsend=0, @notify_level_page=0, @delete_level=0, @description=N'No description available.', @category_name=N'[Uncategorized (Local)]', @owner_login_name=N'sa', @job_id = @jobId OUTPUT IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /****** Object: Step [step1] Script Date: 14/06/2018 21:14:35 ******/ EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'step1', @step_id=1, @cmdexec_success_code=0, @on_success_action=1, @on_success_step_id=0, @on_fail_action=2, @on_fail_step_id=0, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'CmdExec', @command=N'sqlcmd -E -S $(ESCAPE_SQUOTE(SRVR)) -d master -Q "SELECT @@servername" ', @flags=0 IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1 IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)' IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback COMMIT TRANSACTION GOTO EndSave QuitWithRollback: IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION EndSave: GO
所以它必須是別的東西,因為 SQL2016 在這個特定問題上的行為就像以前的版本一樣。
/******** 編輯 ****************/
我已經在執行 Win Server 2016 - SQL Server 2017 標準版的機器上創建了上述 SQL 代理作業,並且執行良好,正如我之前指出的那樣,也許值得嘗試一些簡單的事情,例如
SELECT @@SERVERNAME
嘗試縮小問題範圍