SQL Server游标 - 循环遍历多个服务器并执行查询

ana*_*ist 1 t-sql sql-server cursor sql-server-2008

我有以下代码(光标):

DECLARE @SN VARCHAR(20);
DECLARE @sql NVARCHAR(MAX); 
DECLARE C CURSOR LOCAL FAST_FORWARD
  FOR SELECT DISTINCT(SERVERNAME) FROM INSTALLATION 
    where DATABASETYPE = 'MsSql' AND SERVERNAME IN ('x');

OPEN C;

FETCH NEXT FROM C INTO @SN;
WHILE (@@FETCH_STATUS = 0)
BEGIN 
    PRINT @SN;
    -- you could loop here for each database, if you'd define what that is
   SELECT name 
FROM master.dbo.sysdatabases 
WHERE name not in ('master','model','msdb','tempdb');
    SET @sql = N'SELECT TOP 1 NAME FROM TABLE ';

    EXEC sp_executesql @sql;
    FETCH NEXT FROM C INTO @SN;
END 
CLOSE C;
DEALLOCATE C;
Run Code Online (Sandbox Code Playgroud)

我希望能够遍历每个服务器并在某些(不是全部)数据库上执行select语句.

查询类似于:

SELECT TOP 1 NAME FROM TABLE 
Run Code Online (Sandbox Code Playgroud)

我运行游标的服务器将所有其他服务器作为链接服务器.

Aar*_*and 7

DECLARE @SN VARCHAR(20);

DECLARE C CURSOR LOCAL FAST_FORWARD
  FOR SELECT DISTINCT(SERVERNAME) FROM TABLE 
  where SERVERNAME NOT IN ('SRV1','SRV2','SRV3');

OPEN C;

FETCH NEXT FROM C INTO @SN;
WHILE (@@FETCH_STATUS = 0)
BEGIN 
    PRINT @SN;
    -- you could loop here for each database, if you'd define what that is
    SET @sql = N'SELECT * FROM ' + @SN + '.master.dbo.TABLE;';
    EXEC sys.sp_executesql @sql;
    FETCH NEXT FROM C INTO @SN;
END 
CLOSE C;
DEALLOCATE C;
Run Code Online (Sandbox Code Playgroud)

变化:

  1. 没有理由在这里使用默认光标选项 - 全局,可更新,动态,可滚动等.背景.

  2. 作为习惯/最佳实践,使用sp_executesql与否EXEC().虽然在这种情况下它并不重要,但在其他情况下它可能很重要,所以我更喜欢始终以相同的方式编码.背景.

  3. 另外,请养成用分号终止你的陈述的习惯.你最终必须这样做.背景.

编辑

现在我们有关于您实际需求的更多信息,我建议这段代码.哦,看,没有游标(好吧,没有明确的游标声明和它们附带的所有脚手架)!

SET NOCOUNT ON;

DECLARE @dbs TABLE(SERVERNAME SYSNAME, DBNAME SYSNAME);

DECLARE @sql NVARCHAR(MAX) = N'';

-- first, let's get the databases on each server:

SELECT @sql += N'SELECT ''' + SERVERNAME + ''', name FROM '
 + QUOTENAME(SERVERNAME) + '.master.sys.databases
   WHERE database_id > 4 
   AND name NOT IN (N''somedb'',N''someotherdb'');' 
 FROM dbo.INSTALLATION 
   WHERE DATABASETYPE = 'MsSql' 
   AND SERVERNAME IN ('x');

INSERT @dbs EXEC sys.sp_executesql @sql;

SELECT @sql = N'';

-- now, build a command to run in each database context:

SELECT @sql += N'
  EXEC ' + QUOTENAME(SERVERNAME) + '.'
  + QUOTENAME(DBNAME) + '.sys.sp_executesql @sql;'
  FROM @dbs;

-- feel free to change the 3rd parameter here:

EXEC sys.sp_executesql @sql, N'@sql NVARCHAR(MAX)', 
  N'SELECT @@SERVERNAME, DB_NAME(), actual_columns FROM dbo.table_name;';
Run Code Online (Sandbox Code Playgroud)

如果table_name不存在,这将失败,因此如果您希望促进错误处理,您可能仍有一些工作要做.但这应该让你开始.

另外,请注意并始终使用模式前缀.背景.

  • @Muhammed每个版本都有越来越多的地方.但不要担心今天的需求.只是到处使用它; 然后,当它在任何地方都需要时,你将需要更少的代码来更新. (2认同)