Sql-Server

SQL Server 2016 SQL 代理令牌不工作

  • June 15, 2018

我在整個企業中的數十個 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論點(我不熟悉)是一個批處理終止器;來自微軟文件:

-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

嘗試縮小問題範圍

引用自:https://dba.stackexchange.com/questions/209689