SSI*_*Off 3 sql t-sql stored-procedures dynamic-sql sql-server-2008-r2
我目前有一个链接服务器,我在存储过程中查询.我现在的查询工作得很好但是这个查询需要为我拥有的每个代码分支进行更改.我想知道什么是最好的方法来驱动我在跨服务器查询中调用的数据库名称.
例如:服务器A有一个到服务器B的链接.服务器A包含3个数据库.SRV_A.DB1_DEV,SRV_A.DB2_Trunk,SRV_A.DB3_Prod每个都链接到它们的服务器B对应... SRV_B.DB1_DEV,SRV_B.DB2_Trunk,SRV_B.DB3_Prod
服务器A上的每个数据库都具有相同的存储过程.在sproc中唯一改变的是跨服务器选择.所以SRV_A.DB1_Dev在sproc中有一个select:
SELECT foo FROM [SRV_B].[DB1_DEV].[foo_table] WHERE bar = 1
Run Code Online (Sandbox Code Playgroud)
而主干分支上的存储过程将是
SELECT foo FROM [SRV_B].[DB2_Trunk].[foo_table] WHERE bar = 1
Run Code Online (Sandbox Code Playgroud)
由于我希望有一个VS项目将数据库部署到所提到的每个分支,我希望能够动态填写数据库名称.我提出的解决方案是使用CHARINDEX函数进行一系列IF检查,然后使用动态SQL创建查询,如下所示:
DECLARE @dSql NVARCHAR(4000);
DECLARE @databaseName NVARCHAR(100) = DB_NAME();
DECLARE @tableName NVARCHAR(100);
IF SELECT CHARINDEX('Dev', @databaseName, 0)
SET @tableName = '[SRV_B].[DB1_DEV].[foo_table]
...Same if & set for Trunk
...Same if & set for Prod
SET @dSql = 'DECLARE @retID INT;SELECT foo FROM ' + @tableName
+ ' WHERE bar = 1';SET @retID = SELECT SCOPE_IDENTITY()'
EXEC(@dSQL);
Run Code Online (Sandbox Code Playgroud)
我不得不想象有一个更好的解决方案,如果有人可以帮助我,我会非常感激.如果通过一些外线拍摄这是最好的方式让我知道.
谢谢,詹姆斯
解决此问题的一种方法可能是通过将链接服务器名称包装在同义词中来抽象它:
注意目标表名称中的额外部分 - 跨服务器查询需要一个由四部分组成的名称 - 我假设这是一个错字在问题中,这foo_table是在dbo架构中
CREATE SYNONYM dbo.syn_foo_table
FOR [SRV_B].[DB1_DEV].[dbo].[foo_table]
Run Code Online (Sandbox Code Playgroud)
然后可以在代码中称为
SELECT foo FROM dbo.syn_foo_table WHERE bar = 1
Run Code Online (Sandbox Code Playgroud)
然后,您需要自定义部署脚本以创建指向环境的正确服务器/数据库的同义词.这可以使用与上面概述的类似的动态SQL进程,但只需要在部署时执行一次(而不是每次执行).
另一种可能的解决方案是SQLCMD在存储过程脚本中使用参数,因为(AFAIK)VS项目用于SQLCMD部署数据库对象.
此功能允许您使用表单$(variablename)中的变量来参数化SQL脚本- 在您的情况下:
SELECT foo FROM [SRV_B].[$(dbname)].[foo_table] WHERE bar = 1
Run Code Online (Sandbox Code Playgroud)
可以使用环境变量设置变量的值,也可以使用-v开关将其作为参数传递给命令.有关SQLCMD完整详细信息,请参阅上面的MSDN链接.