Sql server 计算不同服务器上两个数据库中所有表中的所有行

Sql server 计算不同服务器上两个数据库中所有表中的所有行,sql-server,tsql,ssms,ssms-2016,Sql Server,Tsql,Ssms,Ssms 2016,我希望查询返回两台报表服务器上所有表的表名和行数。他们都有相同的桌子。另外,前几天我已经在这两者之间添加了链接服务器 到目前为止,查询一台服务器,但不确定如何添加与另一台服务器连接的第三列: SELECT t.NAME AS TableName, p.[Rows] FROM sys.tables t INNER JOIN sys.indexes i ON t.OBJECT_ID = i.object_id INNER JOIN sys.p

我希望查询返回两台报表服务器上所有表的表名和行数。他们都有相同的桌子。另外,前几天我已经在这两者之间添加了链接服务器

到目前为止,查询一台服务器,但不确定如何添加与另一台服务器连接的第三列:

SELECT 
    t.NAME AS TableName,
    p.[Rows]
FROM 
    sys.tables t
INNER JOIN      
    sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN 
    sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN 
    sys.allocation_units a ON p.partition_id = a.container_id
WHERE 
    t.NAME NOT LIKE 'dt%' AND
    i.OBJECT_ID > 255 AND   
    i.index_id <= 1
GROUP BY 
    t.NAME, i.object_id, i.index_id, i.name, p.[Rows]
ORDER BY 
    object_name(i.object_id) 

如果您能够从一台服务器获得结果,那么如果已设置链接服务器,则可以从其他服务器获得相同的结果

您可以使用由4部分组成的名称来完成此操作。例如:

Select ...
From ServerName.DBName.schema.TableName
...
只需将“SET@SQL”语句第二行的LIVE和TEST以及“dbo”模式名称更改为这两个数据库的名称


编辑:您还可以将一个数据库名称.schema名称添加到顶部的“从sys.tables中选择名称”语句中,以及您想要执行的任何表名称筛选。

这对于常见的表表达式CTE非常有用,因为您可以运行多个查询,然后将这些查询结果连接在一起,并以不同的方式对其进行分析/操作:

/* Use the WITH keyword to start your first expression */
WITH SERVER_A AS (
  SELECT 
      t.NAME AS TableName,
      p.[Rows] AS NumRows
  FROM 
      sys.tables t
  INNER JOIN      
      sys.indexes i ON t.OBJECT_ID = i.object_id
  INNER JOIN 
      sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
  INNER JOIN 
      sys.allocation_units a ON p.partition_id = a.container_id
  WHERE 
      t.NAME NOT LIKE 'dt%' AND
      i.OBJECT_ID > 255 AND   
      i.index_id <= 1
  GROUP BY 
      t.NAME, i.object_id, i.index_id, i.name, p.[Rows]
),

/* Then chain additional expressions (this time adding the linked server into the table name) */
SERVER_B AS (
  SELECT 
      t.NAME AS TableName,
      p.[Rows] AS NumRows
  FROM 
      LINKED_SERVER_NAME.sys.tables t
  INNER JOIN      
      LINKED_SERVER_NAME.sys.indexes i ON t.OBJECT_ID = i.object_id
  INNER JOIN 
      LINKED_SERVER_NAME.sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
  INNER JOIN 
      LINKED_SERVER_NAME.sys.allocation_units a ON p.partition_id = a.container_id
  WHERE 
      t.NAME NOT LIKE 'dt%' AND
      i.OBJECT_ID > 255 AND   
      i.index_id <= 1
  GROUP BY 
      t.NAME, i.object_id, i.index_id, i.name, p.[Rows]
)

/* Then join the two together on a common column */
SELECT
  A.TableName,
  A.NumRows AS DB1_Rows,
  B.NumRows AS DB2_Rows

FROM SERVER_A A
  LEFT JOIN SERVER_B B ON
    A.TableName = B.TableName

ORDER BY
  A.TableName ASC
您也可以使用APPLY语句或相关子查询来实现这一点,但使用CTE的优点是,您不会为父查询返回的每一行运行子查询。使用CTE,您可以运行一个查询,然后简单地将该查询结果视为另一个表


显然,你会想测试这个。我目前没有访问SQL Server的权限,因此这里或那里可能有输入错误。

最简单的方法是创建一个临时表,并用每个数据库的查询填充它,但添加数据库/服务器名称。然后,您可以简单地对表名进行自连接,并进行一些条件聚合以交叉标记结果。对于这一点,游标是错误的工具。它们效率极低。这可以通过基于集合的查询很容易地解决。结果正是Jonathan想要的。这可以通过其他方式完成,如果您有解决方案,请随意发布itI。我尝试用命名约定替换LIVE和TEST:Server.DatabaseName,返回的不包含表DatabaseName.dbo.spt\u fallback\u dbo您是否将选择名称从system.tables更改为其中一个数据库?我相信这就是我的想法寻找,但我得到的两个服务器的行数相同,我知道它们是不同的。我尝试对两个查询使用完整的4部分名称,但仍然得到相同的结果。@JonathanPorter您可以突出显示每个CTE的内部部分,然后运行该查询并查看结果,以确保它们返回正确的数据。如果您使用的是MS SSDT或类似的应用程序,您应该能够隔离每个查询,确认数据集,然后再次运行整个查询以确认您获得了正确的输出。在ssms中,当我独立运行每个查询时,它们返回的结果相同,但是,当我更改服务器连接时,结果会发生变化,即使我使用server.Database.sys.tables作为命名示例。那么,我是否使用了错误的约定,或者由于它们是sys架构的一部分,所以它的工作方式是否有所不同?[LinkedServer].master.sys.tables应该可以工作-只要链接服务器设置为允许使用系统表。在链接服务器上,您需要运行:将视图服务器状态授予;将视图数据库状态授予;授予数据库权限:授予服务器权限:
DECLARE @RESULT TABLE (TableName VARCHAR(MAX),   DB1_rows  INT,   DB2_Rows INT)
DECLARE @TABLENAME VARCHAR(MAX), @SQL VARCHAR(MAX)

DECLARE cCursor CURSOR FOR 
SELECT name FROM sys.tables

OPEN cCursor 
FETCH NEXT FROM cCursor INTO @TABLENAME 

WHILE @@FETCH_STATUS = 0
    BEGIN 
        SET @SQL = 'SELECT  ''' + @TABLENAME + ''' , COUNT(*) FROM ' + @TABLENAME

        DECLARE @FirstColumn VARCHAR(MAX) = (SELECT TOP 1 c.name FROM sys.columns c JOIN sys.tables t ON t.object_id = c.object_id WHERE t.name = @TABLENAME ORDER BY column_id)

        SET @SQL = 'SELECT  ''' + @TABLENAME + ''' , SUM(CASE WHEN A.' + @FirstColumn + ' IS NOT NULL THEN 1 ELSE 0 END), SUM(CASE WHEN B.' + @FirstColumn + ' IS NOT NULL THEN 1 ELSE 0 END) '
                   +'FROM LIVE.dbo.' + @TABLENAME + ' AS A FULL JOIN TEST.dbo.' + @TABLENAME + ' AS B on 1=0'

        INSERT INTO @RESULT EXEC (@SQL) 

        FETCH NEXT FROM cCursor INTO @TABLENAME 
    END

CLOSE cCURSOR 
DEALLOCATE cCURSOR

SELECT * FROM @RESULT
/* Use the WITH keyword to start your first expression */
WITH SERVER_A AS (
  SELECT 
      t.NAME AS TableName,
      p.[Rows] AS NumRows
  FROM 
      sys.tables t
  INNER JOIN      
      sys.indexes i ON t.OBJECT_ID = i.object_id
  INNER JOIN 
      sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
  INNER JOIN 
      sys.allocation_units a ON p.partition_id = a.container_id
  WHERE 
      t.NAME NOT LIKE 'dt%' AND
      i.OBJECT_ID > 255 AND   
      i.index_id <= 1
  GROUP BY 
      t.NAME, i.object_id, i.index_id, i.name, p.[Rows]
),

/* Then chain additional expressions (this time adding the linked server into the table name) */
SERVER_B AS (
  SELECT 
      t.NAME AS TableName,
      p.[Rows] AS NumRows
  FROM 
      LINKED_SERVER_NAME.sys.tables t
  INNER JOIN      
      LINKED_SERVER_NAME.sys.indexes i ON t.OBJECT_ID = i.object_id
  INNER JOIN 
      LINKED_SERVER_NAME.sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
  INNER JOIN 
      LINKED_SERVER_NAME.sys.allocation_units a ON p.partition_id = a.container_id
  WHERE 
      t.NAME NOT LIKE 'dt%' AND
      i.OBJECT_ID > 255 AND   
      i.index_id <= 1
  GROUP BY 
      t.NAME, i.object_id, i.index_id, i.name, p.[Rows]
)

/* Then join the two together on a common column */
SELECT
  A.TableName,
  A.NumRows AS DB1_Rows,
  B.NumRows AS DB2_Rows

FROM SERVER_A A
  LEFT JOIN SERVER_B B ON
    A.TableName = B.TableName

ORDER BY
  A.TableName ASC