链接服务器查询/动态SQL

时间:2012-04-16 08:23:58

标签: sql tsql stored-procedures sql-server-2008-r2 dynamic-sql

我目前有一个链接服务器,我在存储过程中查询。我现在的查询工作得很好但是这个查询需要为我拥有的每个代码分支进行更改。我想知道什么是最好的方法来驱动我在跨服务器查询中调用的数据库名称。

例: 服务器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 

而主干分支上的存储过程将是

SELECT foo FROM [SRV_B].[DB2_Trunk].[foo_table] WHERE bar = 1

由于我希望有一个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);

我不得不想象有一个更好的解决方案,如果有人可以帮助我,我会非常感激。如果通过一些外线拍摄这是最好的方式让我知道。

谢谢, 詹姆斯

2 个答案:

答案 0 :(得分:5)

解决此问题的一种方法可能是通过将链接的服务器名称包装在synonym中来抽象它: 注意目标表名称中的额外部分 - 跨服务器查询需要一个由四部分组成的名称 - 我假设这是问题中的拼写错误,而foo_table位于dbo中模式

CREATE SYNONYM dbo.syn_foo_table
FOR [SRV_B].[DB1_DEV].[dbo].[foo_table]

然后可以在代码中引用

SELECT foo FROM dbo.syn_foo_table WHERE bar = 1 

然后,您需要自定义部署脚本以创建指向环境的正确服务器/数据库的同义词。这可以使用与上面概述的类似的动态SQL进程,但只需要在部署时执行一次(而不是每次执行)。

另一种可能的解决方案是在存储过程脚本中使用SQLCMD参数,因为(AFAIK)VS项目使用SQLCMD来部署数据库对象。
此功能允许您使用$(variablename)形式的变量参数化SQL脚本 - 在您的情况下:

SELECT foo FROM [SRV_B].[$(dbname)].[foo_table] WHERE bar = 1 

变量的值可以使用环境变量设置,也可以使用-v开关作为参数传递给命令。有关详细信息,请参阅上面的SQLCMD MSDN链接。

答案 1 :(得分:0)

我能够使用上面提到的db-name环境变量的组合,并且还使用以下查询动态生成SRV名称:

DECLARE @ServerName NVARCHAR(100);
SET @ServerName = (SELECT name FROM sys.servers WHERE server_id = 1)