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

时间:2017-01-06 15:31:58

标签: sql-server tsql ssms ssms-2016

我希望我的查询返回两个报告服务器上所有表的表名和rowcount。他们都有相同的表格。此外,我已经在这两天之间添加了链接服务器。

目前为一台服务器查询,不知道如何添加与我们其他服务器连接的第三列:

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) 

期望的输出:

TableName   DB1_rows     DB2_Rows
----------+-----------+-----------
Account   |  20,000   |  19,388
Contacts  |   1,234   |   1,390
Bla       |   2,330   |   2,430

3 个答案:

答案 0 :(得分:2)

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

attr_accessor :title, release_date

您也可以使用/* 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 语句或相关子查询来完成此操作,但使用CTE的优点是您不会为父查询返回的每一行运行子查询。使用CTE,您可以运行查询,然后将该查询结果视为另一个表。

显然你会想要测试一下。我目前无法访问SQL Server,因此可能存在拼写错误。

答案 1 :(得分:1)

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

只需将'SET @SQL'语句第二行的LIVE和TEST以及'dbo'模式名称更改为2个数据库的名称。

编辑:您还可以将其中一个数据库names.schema名称添加到顶部的“SELECT name FROM sys.tables”语句,以及您想要执行的任何表名过滤。

答案 2 :(得分:0)

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

您可以使用4部分名称来完成。例如:

Select ...
From ServerName.DBName.schema.TableName
...