Wie schreibe ich portables SQL, das sich auf einen Verbindungsserver bezieht?

9

Ich habe eine gespeicherte Prozedur, die auf einen Verbindungsserver verweist. An mehreren Stellen während des Verfahrens habe ich ungefähr Folgendes:

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

Dieses Verfahren ist in meiner Entwicklungsumgebung, Testumgebung und Live-Umgebung vorhanden.

Das Problem ist, dass jede Kopie der Prozedur geringfügig unterschiedlich ist, da die Servernamen für jede Umgebung unterschiedlich sind. Dies erschwert die Verwaltung der Bereitstellung von Skriptaktualisierungen.

Gibt es eine Möglichkeit, das Verfahren portabel zu machen, sodass in jeder Umgebung identische Versionen davon ausgeführt werden können?

Wenn nicht, kann ich etwas tun, um die Skriptbereitstellung weniger fehleranfällig zu machen?

Doktor Jones
quelle
3
Ist das Erstellen einer Ansicht, die auf jedem Server unterschiedlich ist, eine Option? Sie können die Ansicht als definieren, SELECT <fields> FROM <linked server>aber auf allen Servern denselben Ansichtsnamen verwenden, um den Code beizubehalten
JNK
@JNK das ist keine schlechte Idee, es gibt zwar einige Tabellen, aber zumindest wären Ansichten einfacher zu pflegen als eine gespeicherte Prozedur mit durchgehend gespickten verknüpften Serverreferenzen.
Doktor Jones
@jnk, du solltest das zu einer Antwort machen.
HLGEM

Antworten:

14

Der Name Ihres Verbindungsservers muss nicht der Name des Servers sein. Sie können einen generischen Namen verwenden.

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'

Richten Sie den Verbindungsserver in jeder Umgebung mit demselben Namen ein, zeigen Sie ihn jedoch tatsächlich auf verschiedene Server.

Eli
quelle
0

Ich mag die Idee, einen generischen Verbindungsservernamen zu verwenden. In vielen Umgebungen ist dies jedoch möglicherweise nicht möglich. In diesem Fall können Sie dynamisches SQl in Ihrem SP verwenden.

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
quelle
1
Ich werde bemerken, dass ich, wenn ich dies im wirklichen Leben tun würde, einen try catch-Block verwenden und einen Fehler auslösen würde, wenn @linkedservername nach der set-Anweisung null wäre, um Sie zu warnen, dass dies auf dem falschen Server ausgeführt wurde.
HLGEM
1
Wenn Sie diesen Ansatz wählen würden, würde ich die CASE-Anweisung wahrscheinlich in eine Funktion einschließen. Wenn sich also ein Server ändert, muss ich nur die Funktion aktualisieren.
Eli
Guter Punkt @Eli
HLGEM