Как мне написать переносимый SQL, который ссылается на связанный сервер?

9

У меня есть хранимая процедура, которая ссылается на связанный сервер. В нескольких местах на протяжении всей процедуры у меня есть что-то вроде следующего:

INSERT INTO [TableName]
(...Columns...)
SELECT ...Columns...
FROM [ServerName\InstanceName].[Catalogue].[dbo].[TableName]
WHERE TableNameID = @TableNameID

Эта процедура существует в моей среде разработки, тестовой среде и среде Live.

Проблема в том, что каждая копия процедуры немного отличается, потому что имена серверов различны для каждой среды. Это делает управление развертыванием обновлений скрипта проблематичным.

Есть ли способ сделать процедуру переносимой, чтобы каждая среда могла запускать идентичные ее версии?

Если нет, могу ли я что-нибудь сделать, чтобы развертывание скриптов было менее подвержено ошибкам / ошибкам?

Доктор джонс
источник
3
Является ли создание представления, которое отличается на каждом сервере вариант? Вы можете определить представление как, SELECT <fields> FROM <linked server>но использовать одно и то же имя представления на всех серверах, чтобы сохранить код
JNK
@JNK, это неплохая идея, хотя есть довольно много таблиц, но, по крайней мере, представления проще поддерживать, чем хранимую процедуру со ссылками на связанные серверы.
Доктор Джонс
@jnk, ты должен сделать это ответ.
HLGEM 10.10.12

Ответы:

14

Имя вашего связанного сервера не обязательно должно быть именем сервера. Вы можете использовать общее имя.

EXEC master.dbo.sp_addlinkedserver
    @server = N'COMMONNAME',
    @srvproduct=N'MSDASQL',
    @provider=N'SQLNCLI',
    @provstr=N'DRIVER={SQL Server};SERVER=ACTUALSERVERNAME;UID=user1;PWD=rosebud567;', 
    @catalog=N'database1'

Настройте связанный сервер в каждой среде с тем же именем, но на самом деле укажите их на разных серверах.

Eli
источник
0

Мне нравится идея использовать общее имя связанного сервера. Однако во многих средах это может оказаться невозможным. В этом случае вы можете использовать динамический SQl в вашем sp.

declare @linkedservername nvarchar(200)
declare @sql nvarchar(4000)
SET @linkedservername =  CASE @@ServerName  
                            WHEN 'DevServer' THEN 'LinkedServerForDevEnvironment'
                            WHEN 'TestServer' THEN 'LinkedServerForTestEnvironment'
                            WHEN 'ProdServer' THEN 'LinkedServerForProdEnvironment'
                            ELSE Null
                        END   

set @sql = 'INSERT INTO [TableName] 
(...Columns...) 
SELECT ...Columns... 
FROM ' + @linkedservername + '.[Catalogue].[dbo].[TableName] 
WHERE TableNameID = @TableNameID'

Exec  @sql
HLGEM
источник
1
Я отмечу, что если бы я делал это в реальной жизни, я бы использовал блок try catch и выдавал ошибку, если @linkedservername был нулевым после оператора set, чтобы предупредить вас, что это было выполнено на неправильном сервере.
HLGEM
1
Если бы вы воспользовались этим подходом, я думаю, что я бы обернул оператор CASE в функцию, поэтому, если сервер изменился, мне нужно было только обновить функцию.
Илай
Хороший вопрос @Eli
HLGEM