以SQL Server存储过程中的本地数据库引用以编程方式替换链接服务器引用?

时间:2009-07-09 15:46:47

标签: sql sql-server metadata

作为脚本程序的一部分,我正在尝试以编程方式更新对存储过程中链接服务器的引用。我们有几个像这样的引用: -

SELECT foo, bar
FROM [Server].[Database].dbo.[Table]

我想将其翻译成: -

SELECT foo, bar
FROM [Database].dbo.[Table]

我想在几个数据库的“fire and forget”脚本中完全以编程方式完成此操作。

我现在的想法是使用元数据来查找对链接表的引用,再次从元数据中读取每个sp的文本,调整每个sp的文本,然后将每个更新文本块推送到exec语句中以重建它们一个接一个。

我确实怀疑这是否会是一种巨大的痛苦,所以有没有更好的想法?如果可以提供更好的解决方案,我愿意使用PowerShell。

提前致谢!

4 个答案:

答案 0 :(得分:1)

希望我理解这些问题,但不是删除或替换[Server],我建议采用以下两种方法之一:

  • 选项1:不要改变任何一个 的SP。而是,更新链接 服务器配置指向a 不同的数据库,甚至是本地的 框。

  • 选项2:不要改变任何一个 的SP。相反,开始使用SQL Server 别名。 SQL Server别名是 通过CliConfig实用程序进行管理 最终存储在 注册表中。因此,它们可以应用 手动或通过.reg脚本。 基本上,SQL Server别名 解密服务器(以及 正在引用的端口)。如果 您更新链接服务器 配置引用SQL 服务器别名而不是特定的 服务器,你可以指出你的程序 每当你到不同的服务器(甚至本地服务器) 想。

我希望它有所帮助。

答案 1 :(得分:1)

坦白说,你的方法最简单。我今年早些时候遇到了类似的问题

  • 读取sys.sql_modules
  • 更换链接的服务器文本和CREATE - > ALTER
  • EXEC(@Result)

答案 2 :(得分:1)

这是一个脚本,用于查找在SQL 2005实例上引用链接服务器的所有proc / functions /视图 - 也可能有用:

USE master
GO
SET NOCOUNT ON;

--------------------------------------------------------------------
-- Test linked server connections
--------------------------------------------------------------------
BEGIN TRY   DROP TABLE #Svrs;   END TRY BEGIN CATCH END CATCH;

CREATE TABLE #Svrs
(
    [Server]                nvarchar(max),
    [CanConnectAsDefault]   bit
);

DECLARE @ServerName nvarchar(max), @RetVal int;

DECLARE Svrs CURSOR FAST_FORWARD READ_ONLY
FOR
    SELECT  ServerName = S.name
    FROM    sys.servers S;

OPEN Svrs;
FETCH NEXT FROM Svrs INTO @ServerName;
WHILE @@FETCH_STATUS = 0
BEGIN
    BEGIN TRY
        EXEC @RetVal = sys.sp_testlinkedserver @ServerName;
    END TRY
    BEGIN CATCH
        SET @RetVal = sign(@@error);
    END CATCH;

    INSERT INTO #Svrs 
    SELECT  @ServerName 
        ,   CASE WHEN @RetVal = 0 THEN 1 ELSE 0 END;

    FETCH NEXT FROM Svrs INTO @ServerName;
END;
CLOSE Svrs;
DEALLOCATE Svrs;

SELECT * FROM #Svrs
DROP TABLE #Svrs;
GO

--------------------------------------------------------------------
-- Report linked server references
--------------------------------------------------------------------
BEGIN TRY   DROP TABLE #Refs;   END TRY BEGIN CATCH END CATCH;

CREATE TABLE #Refs
(
    [Server]    nvarchar(max),
    [Database]  nvarchar(max),
    [Schema]    nvarchar(max),
    [Object]    nvarchar(max),
    [Type]      nvarchar(max)
);

DECLARE @DatabaseName nvarchar(max), @ServerName nvarchar(max), @SQL nvarchar(max);
DECLARE Refs CURSOR FAST_FORWARD READ_ONLY
FOR
    SELECT  DatabaseName = D.name 
        ,   ServerName = S.name
    --  ,   ServerProvider = S.provider
    --  ,   ServerSource = S.data_source
    FROM    sys.databases D 
            CROSS JOIN sys.servers S
    WHERE D.name NOT IN ('master', 'tempdb', 'model', 'msdb', 'ReportServer', 'ReportServerTempDB');

OPEN Refs;
FETCH NEXT FROM Refs INTO @DatabaseName, @ServerName;
WHILE @@FETCH_STATUS = 0
BEGIN
    SET @SQL = 'USE [' + @DatabaseName + '];                
                INSERT INTO #Refs 
                SELECT DISTINCT ''' + @ServerName + ''', ''' + @DatabaseName + ''', S.[name], O.[name], O.type_desc 
                FROM    syscomments C
                        INNER JOIN sys.objects O ON C.id = O.[object_id]
                        LEFT JOIN sys.schemas S ON S.[schema_id] = O.[schema_id]
                WHERE   C.[TEXT] LIKE ''%[ ,~[( '''']' + @ServerName + '[ .,~])'''' ]%'' ESCAPE ''~'';'

    PRINT 'Looking for ' + @ServerName + ' refs in ' + @DatabaseName -- + ': ' + @SQL;

    EXEC sp_executesql @SQL;

    FETCH NEXT FROM Refs INTO @DatabaseName, @ServerName;
END
CLOSE Refs;
DEALLOCATE Refs;

SELECT * FROM #Refs
DROP TABLE #Refs;
GO

--------------------------------------------------------------------
SET NOCOUNT OFF;
GO

答案 3 :(得分:1)

这对于生产环境来说不是一个好主意,但如果您需要一个用于开发目的的环回链接服务器this为我工作:

EXEC sp_addlinkedserver @server = N'name_for_linked_server',
    @srvproduct = N' ',
    @provider = N'SQLNCLI', 
    @datasrc = N'name_of_my_sqlserver_instance', 
    @catalog = N'name_of_database'