Aus*_*tin 5 sql-server dynamic-sql t-sql
我遇到了一个奇怪的动态 sql 问题,我认为这是某种格式问题,在过去的几个小时里我一直在为此抓狂。我非常感谢我能得到的任何帮助。
对于一些背景信息,此存储过程的目的是清理我们的集中式 (hq) 数据库中的数据,该数据库应该拥有我们所有商店的所有记录的完整副本。如果重要的话,我们正在运行 Microsoft Dynamics RMS (2.0.2022) 和 SQL 2014 Standard(对于总部,商店使用 Express)。
最初我打算将 sql 语句放在参数中并使用 exec 命令,但是虽然我不经常使用它,但我认为 sp_executesql 看起来更干净,并且更容易将查询重用为模板并进行更改他们。现在我只有一些选择的脚本,但是一旦它们完成,我将创建一个额外的存储过程来插入、删除和更新记录。
执行 sql 语句有效,但出于某种原因,我无法让 sp_executesql 使用存储过程中的参数。无论我将参数更改为什么,包括在存储过程中使用静态值,它都只会输出参数名称。所以无论:
@LS = @LinkedServer
Run Code Online (Sandbox Code Playgroud)
或者
@LS = 'StaticLinkedServerName'
Run Code Online (Sandbox Code Playgroud)
它返回的错误信息是:
在 sys.servers 中找不到服务器“@LS”。验证是否指定了正确的服务器名称。如有必要,执行存储过程 sp_addlinkedserver 将服务器添加到 sys.servers。
无效的解决方案
CREATE PROCEDURE [dbo].[usp_bn_ShowStoreHQSync]
(
@StoreCode NVARCHAR(10)
,@LinkedServer NVARCHAR(50)
,@StoreDB NVARCHAR(40)
)
AS
BEGIN
BEGIN TRANSACTION
BEGIN TRY
IF @StoreCode IS NULL
RAISERROR('@StoreCode Cannot Be NULL',15,1)
ELSE IF @StoreCode NOT IN (SELECT StoreCode FROM [HQDB].[dbo].[Store])
RAISERROR('@StoreCode Not In DB',15,1)
ELSE IF @LinkedServer IS NULL
RAISERROR('@LinkedServer Cannot Be NULL',15,1)
ELSE IF @LinkedServer NOT IN (SELECT name FROM sys.servers)
RAISERROR('@LinkedServer Does Not Exist or Cannot Connect',15,1)
ELSE
DECLARE @LinkedServerCatalog AS TABLE
(
DBName NVARCHAR(MAX)
, Description NVARCHAR(MAX)
)
INSERT INTO @LinkedServerCatalog
EXEC sp_catalogs @server_name = @LinkedServer
IF @StoreDB NOT IN (SELECT DBName FROM @LinkedServerCatalog)
RAISERROR('@Database Does Not Exist or Cannot Connect',15,1)
ELSE
DECLARE @StoreID INT;
DECLARE @Last401 DATETIME;
SET @StoreID = (SELECT ID FROM Store WHERE StoreCode = @StoreCode)
SET @Last401 = dbo.Last401(@StoreID)
EXECUTE sp_executesql
N'SELECT SOPO.ID
, SOPO.ID
, SOPO.PONumber
, SOPO.POTitle
, SOPO.Status
, SOPO.LastUpdated
, SOPO.DateCreated
, SOPO.DatePlaced
, SOPO.IsPlaced
, SOPO.Remarks
, SOPO.StoreID
, SOPO.OtherStoreID
, SOPO.[To]
, SOPO.ShipTo
, SOPO.WorksheetID
FROM [@LS].[@DB].[dbo].[PurchaseOrder] SOPO
WHERE SOPO.ID NOT IN (SELECT HQPO.ID FROM HQDB.dbo.PurchaseOrder HQPO WHERE HQPO.StoreID = @SID)'
, N'@LS NVARCHAR(50), @DB NVARCHAR(40), @SID NVARCHAR(10)'
, @LS = @LinkedServer
, @DB = @StoreDB
, @SID = @StoreID;
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber
, ERROR_STATE() AS ErrorState
, ERROR_SEVERITY() AS ErrorSeverity
, ERROR_PROCEDURE() AS ErrorProcedure
, ERROR_LINE() AS ErrorLine
, ERROR_MESSAGE() AS ErrorMessage;
ROLLBACK TRANSACTION;
END CATCH
END
Run Code Online (Sandbox Code Playgroud)
工作方案
CREATE PROCEDURE [dbo].[usp_bn_ShowStoreHQSync]
(
@StoreCode NVARCHAR(10)
,@LinkedServer NVARCHAR(50)
,@StoreDB NVARCHAR(40)
)
AS
BEGIN
BEGIN TRANSACTION
BEGIN TRY
IF @StoreCode IS NULL
RAISERROR('@StoreCode Cannot Be NULL',15,1)
ELSE IF @StoreCode NOT IN (SELECT StoreCode FROM [HQDB].[dbo].[Store])
RAISERROR('@StoreCode Not In DB',15,1)
ELSE IF @LinkedServer IS NULL
RAISERROR('@LinkedServer Cannot Be NULL',15,1)
ELSE IF @LinkedServer NOT IN (SELECT name FROM sys.servers)
RAISERROR('@LinkedServer Does Not Exist or Cannot Connect',15,1)
ELSE
DECLARE @LinkedServerCatalog AS TABLE
(
DBName NVARCHAR(MAX)
, Description NVARCHAR(MAX)
)
INSERT INTO @LinkedServerCatalog
EXEC sp_catalogs @server_name = @LinkedServer
IF @StoreDB NOT IN (SELECT DBName FROM @LinkedServerCatalog)
RAISERROR('@Database Does Not Exist or Cannot Connect',15,1)
ELSE
DECLARE @StoreID INT;
DECLARE @Last401 DATETIME;
DECLARE @SQL_MissingPO NVARCHAR(MAX);
SET @StoreID = (SELECT ID FROM Store WHERE StoreCode = @StoreCode)
SET @Last401 = dbo.Last401(@StoreID)
SET @SQL_MissingPO = ' SELECT ''@SQL_MissingPO'' AS ''Script''
, SOPO.ID
, SOPO.PONumber
, SOPO.POTitle
, SOPO.Status
, SOPO.LastUpdated
, SOPO.DateCreated
, SOPO.DatePlaced
, SOPO.IsPlaced
, SOPO.Remarks
, SOPO.StoreID
, SOPO.OtherStoreID
, SOPO.[To]
, SOPO.ShipTo
, SOPO.WorksheetID
FROM [' + @LinkedServer + '].[' + @StoreDB + '].[dbo].[PurchaseOrder] SOPO
WHERE SOPO.ID NOT IN (SELECT HQPO.ID FROM HQDB.dbo.PurchaseOrder HQPO WHERE HQPO.StoreID = ' + CAST(@StoreID AS NVARCHAR(20)) + ')'
EXEC (@SQL_MissingPO)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber
, ERROR_STATE() AS ErrorState
, ERROR_SEVERITY() AS ErrorSeverity
, ERROR_PROCEDURE() AS ErrorProcedure
, ERROR_LINE() AS ErrorLine
, ERROR_MESSAGE() AS ErrorMessage;
ROLLBACK TRANSACTION;
END CATCH
END;
Run Code Online (Sandbox Code Playgroud)
执行命令(对于两种解决方案)
EXEC usp_bn_ShowStoreHQSync '01', 'Store_001', 'bnstr01'
Run Code Online (Sandbox Code Playgroud)
Eri*_*ing 11
您不能使用对象名称作为动态 SQL 中的参数。这就是为什么你的第一次尝试不起作用
如果将第一次和第二次尝试结合起来,至少可以对@StoreId
参数进行参数化。
另外,请记住,仅使用方括号并不完全安全。您需要使用QUOTENAME。
DECLARE
@sql nvarchar(MAX) = N'';
SELECT
@sql += N'
SELECT
SOPO.ID
SOPO.ID,
SOPO.PONumber,
SOPO.POTitle,
SOPO.Status,
SOPO.LastUpdated,
SOPO.DateCreated,
SOPO.DatePlaced,
SOPO.IsPlaced,
SOPO.Remarks,
SOPO.StoreID,
SOPO.OtherStoreID,
SOPO.[To],
SOPO.ShipTo,
SOPO.WorksheetID
FROM ' +
QUOTENAME(@LS) +
N'.' +
QUOTENAME(@DB) +
N'.dbo.PurchaseOrder SOPO
WHERE SOPO.ID NOT IN (SELECT HQPO.ID FROM HQDB.dbo.PurchaseOrder HQPO WHERE HQPO.StoreID = @SID);';
EXECUTE sys.sp_executesql
@sql,
N'@SID NVARCHAR(10)',
@SID = @StoreID;
Run Code Online (Sandbox Code Playgroud)