3

如何让一条 SQL 有条件地更改目标服务器?

所以在我的本地开发机器上,我可以运行它并使用命令......

INSERT  INTO [sds].[dbo].[Team_Email_Addresses]
        SELECT  [class] AS 'Team number' ,
                [description] AS 'Team name' ,
                [DutyEmail] AS 'Team email address'
        FROM    [DEVSERVER].[cases].[dbo].[sp_class]
        WHERE   [status] = 1

但在测试机器上,我希望运行相同的 SQL 并拥有命令......

INSERT  INTO [sds].[dbo].[Team_Email_Addresses]
        SELECT  [class] AS 'Team number' ,
                [description] AS 'Team name' ,
                [DutyEmail] AS 'Team email address'
        FROM    [TESTSERVER].[cases].[dbo].[sp_class]
        WHERE   [status] = 1

我尝试使用变量@TGT并将其设置为SQLdevservertestserverSQL FROM [@TGT].[cases].[dbo].[sp_class],但出现错误Could not find server '@TGT' in sys.servers.

4

3 回答 3

6

您将需要使用动态 SQL。此外,您不应该使用'single quotes'来分隔列别名;此语法已被弃用。您应该使用[square brackets]"double quotes"(通常首选前者)。

DECLARE @sql NVARCHAR(MAX), @TGT SYSNAME;

SET @TGT = N'[TESTSERVER]';

SET @sql = N'INSERT  INTO [sds].[dbo].[Team_Email_Addresses]
        SELECT  [class] AS [Team number] ,
                [description] AS [Team name] ,
                [DutyEmail] AS [Team email address]
        FROM    ' + @TGT + '.[cases].[dbo].[sp_class]
        WHERE   [status] = 1;';

PRINT @sql;
EXEC sp_executesql @sql;

(事实上​​,您在这里并不需要别名,尽管您应该指定插入列列表。)

或者,您可以做些什么来使代码更稳定,即在您的两个环境中使用同义词。在开发中:

CREATE SYNONYM dbo.sp_class FOR DEVSERVER.cases.dbo.sp_class;

在测试中:

CREATE SYNONYM dbo.sp_class FOR TESTSERVER.cases.dbo.sp_class;

现在您的查询可以简单地是:

INSERT  INTO [sds].[dbo].[Team_Email_Addresses]
        SELECT  [class],
                [description],
                [DutyEmail]
        FROM    [dbo].[sp_class]
        WHERE   [status] = 1;

当然,同义词只有在您使用 SQL Server 2005 或更高版本时才有效。指定您使用的 SQL Server 版本总是很有用的!

于 2012-05-01T15:35:58.660 回答
2

对于这种情况,我通常使用同义词。由于您从两个不同的地方运行它,您只需要在每个地方适当地定义您的同义词。

在您的本地开发机器上:

CREATE SYNONYM dbo.Cases_sp_class FOR [DEVSERVER].[cases].[dbo].[sp_class]

在您的测试机器上:

CREATE SYNONYM dbo.Cases_sp_class FOR [TESTSERVER].[cases].[dbo].[sp_class]

然后,您只需要在所有环境中将您的 SQL 更改为此:

INSERT  INTO [sds].[dbo].[Team_Email_Addresses]
        SELECT  [class] AS 'Team number' ,
                [description] AS 'Team name' ,
                [DutyEmail] AS 'Team email address'
        FROM    [dbo].[Cases_sp_class]
        WHERE   [status] = 1

几点注意事项:

  1. TESTSERVER 和/或 DEVSERVER 需要定义为链接服务器
  2. 如果 [sp_class] 真的是一个存储过程,您将需要以稍微不同的方式来完成所有这些工作。如果不是,您可能不应该为它使用“sp_”前缀,因为这是 MS 用于它自己的系统过程的前缀,它可能会变得非常混乱。
于 2012-05-01T15:43:04.237 回答
1

正如 Aaron Bertrand 指出的那样,动态 SQL 是一种选择,在动态 SQL的诅咒和祝福中对动态 sql 进行了很好的讨论

除了动态 sql 选项之外,您还可以简单地将两者都包含在 if 语句中。

If <insert condition> then
INSERT  INTO [sds].[dbo].[Team_Email_Addresses]         SELECT  [class] AS 'Team number' ,                 [description] AS 'Team name' ,                 [DutyEmail] AS 'Team email address'         FROM    [DEVSERVER].[cases].[dbo].[sp_class]         WHERE   [status] = 1 
else
INSERT  INTO [sds].[dbo].[Team_Email_Addresses]         SELECT  [class] AS 'Team number' ,                 [description] AS 'Team name' ,                 [DutyEmail] AS 'Team email address'         FROM    [TESTSERVER].[cases].[dbo].[sp_class]         WHERE   [status] = 1 

最后,特别是如果问题条件基于运行的机器之类的东西,您可以使用同义词,但根据需要更改别名所指向的内容。这可能是最复杂的选项,但它的优点是使所讨论的存储过程更短更简单。

于 2012-05-01T15:44:53.383 回答