如何更新已创建Linked Server的Catalog列适配动态SQL需求?
我有一台主Staging服务器,配置了多个Linked Server,每个Linked Server在主Staging服务器上都有对应的数据库。我编写了一个存储过程(SP),从这些Linked Server提取数据,并按每个Linked Server对应的数据库导入到主Staging服务器中。
现在遇到的问题是,部分Linked Server存在多个可用的有效数据库。此前我默认该数据库名为"OriginalDB",但实际并非如此,导致动态SQL中的以下语句无法始终生效:
SELECT [Store ID] FROM [' + @LinkedServerName + '].OriginalDB.dbo.[Branch Details] WHERE [Branch Number] = 1) AS StoreCode
因此我需要像处理LinkedServerName一样,动态替换正确的数据库名。该脚本仅需执行一次,但涉及大量数据库,手动操作效率低下,也为后续操作提供便利。
要实现上述需求,我需要更新sys.servers中的Catalog列,为每个Linked Server设置正确的数据库名。我已在存储过程中创建了@catalog变量,用于获取每个Linked Server的Catalog名称。
我尝试使用sp_serveroption编写了如下脚本更新Catalog:
DECLARE @DBName NVARCHAR(255); DECLARE @LinkedServerName NVARCHAR(255); DECLARE @SQL NVARCHAR(MAX); DECLARE @Count INT = 0; -- Counter for the number of matching databases DECLARE @Result NVARCHAR(255); -- Variable to store the result for DB name or "Multiple DBs" -- Set Linked Server name based on current DB SET @LinkedServerName = RIGHT(DB_NAME(), LEN(DB_NAME()) - PATINDEX('%[0-9]%', DB_NAME()) + 1); SET @Result = ''; SET @SQL = ' DECLARE db_cursor CURSOR FOR SELECT name FROM [' + @LinkedServerName + '].master.sys.databases WHERE state_desc = ''ONLINE'' AND name != ''NotOriginalDB'';' EXEC sp_executesql @SQL; OPEN db_cursor; FETCH NEXT FROM db_cursor INTO @DBName; WHILE @@FETCH_STATUS = 0 BEGIN -- Define the dynamic SQL for checking tables SET @SQL = ' IF EXISTS (SELECT 1 FROM [' + @LinkedServerName + '].[' + @DBName + '].sys.tables WHERE name IN (''Table One'', ''Table Two'')) BEGIN -- Increment the counter if a match is found SET @Count = @Count + 1; -- If more than 1 match, set the result to "Multiple DBs" and exit early IF @Count > 1 BEGIN -- Output "Multiple DBs" SET @Result = ''Multiple DBs''; CLOSE db_cursor; DEALLOCATE db_cursor; RETURN; END; END'; -- Execute the dynamic SQL for checking tables EXEC sp_executesql @SQL, N'@Count INT OUTPUT, @Result NVARCHAR(255) OUTPUT', @Count OUTPUT, @Result OUTPUT; FETCH NEXT FROM db_cursor INTO @DBName; END; -- If only 1 match, set the result to the database name IF @Count = 1 BEGIN SET @Result = @DBName; END; CLOSE db_cursor; DEALLOCATE db_cursor; IF @Result != '' BEGIN EXEC sp_serveroption @server = @LinkedServerName, @optname = 'catalog', @optvalue = @Result; END; -- Select the result for verification SELECT @Result AS DatabaseResult;
此外,我还尝试直接使用UPDATE语句更新系统目录,但收到错误:
Ad hoc updates to system catalogs are not allowed
尝试通过EXEC sp_configure 'allow updates', 1; RECONFIGURE;绕过限制,又收到:
Ad hoc update to system catalogs is not supported
据了解微软已禁用该功能以避免数据损坏。
回到使用sp_serveroption的脚本,执行时出现错误:
Msg 15600, Level 15, State 1, Procedure sp_serveroption, Line 203 [Batch Start Line 0]
An invalid parameter or option was specified for procedure 'sys.sp_serveroption'.
经确认,该错误是由于无法通过此存储过程修改Catalog属性导致的,但脚本的结果输出是正确的。
该脚本通过bat文件在对应数据库上执行,bat文件用于运行保存为.sql的脚本。Linked Server的命名规则为:名称等于当前数据库名称末尾的数字部分(即LinkedServerName)。
内容的提问来源于stack exchange,提问作者Enzo

