2012-05-01 56 views
3

如何讓單條SQL有條件地更改目標服務器?針對不同服務器的條件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並將其設置爲任何devservertestserver與SQL FROM [@TGT].[cases].[dbo].[sp_class]試過,但我得到一個錯誤Could not find server '@TGT' in sys.servers.

+0

Yeap這些是兩臺服務器的名稱 – SteveC

回答

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的版本總是有用的!

+0

感謝您的優秀和全面的迴應 – SteveC

2

我通常使用這種情況的同義詞。既然你從兩個不同的地方運行這個,你只需要在每個地方適當地定義你的同義詞。

在您的本地dev的機器:

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用於它自己的系統過程的前綴,它可能會變得非常混亂。
+0

很顯然,我需要打字速度更快,您在我打字時輸入幷包含一個很好的示例。 ;-) – TimothyAWiseman

+0

Tim!好久不見!那麼,在我拿到這個時候,Aaron實際上輸入了三個不同的答案(包括這個)。猜猜這就是他爲什麼是MVP的原因......-) – RBarryYoung

+1

謝謝,但我刪除了一個,因爲我意識到OP可能在這兩種環境中都沒有設置兩個鏈接的服務器名稱,所以我的UNION想法(以及Timothy的IF想法)在這種情況下不會解析。 –

1

亞倫伯特蘭指出,動態SQL是一個選項,並有動態SQL在The Curse and Blessings of Dynamic 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 

最後,特別是如果這個問題的條件是基於什麼像什麼的機器,這是運行,你可以使用一個代名詞,但改變什麼別名是在需要的基礎上指指點點。這可能是最複雜的選擇,但它具有使存儲過程更簡單和更簡單的優點。

+2

不幸的是,即使使用延遲名稱解析,IF條件也不會正確解析,除非兩個環境都設置了兩個鏈接服務器(這不太可能)。 –

+0

感謝您的補充。我輕易地認爲所有適當的鏈接服務器都存在。 – TimothyAWiseman

+0

感謝這篇文章的鏈接,在動態SQL和其他方法方面有很多有趣的指針 – SteveC