计算不同服务器上两个数据库中所有表中的所有行
Count all rows from all tables in two databases on different servers
我想查询 return table 名称,以及我们两个报告服务器上所有 table 的行数。他们都有相同的tables。另外,前几天我已经在这两者之间添加了链接服务器。
到目前为止查询了一台服务器,但不确定如何添加与我们的另一台服务器连接的第三列:
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
如果您能够从一台服务器获取结果,那么如果链接服务器已设置,您也可以从另一台服务器获取相同的结果。
您可以使用 4 部分名称来完成。例如:
Select ...
From ServerName.DBName.schema.TableName
...
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' 语句,加上您想要执行的任何 table 名称过滤。
这对通用 Table 表达式 (CTE) 非常有用,因为您可以 运行 多个查询,然后将这些查询结果连接在一起,并以不同的方式 analyze/manipulate 它们:
/* 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 的优点是您不必 运行 为每一行设置子查询父查询 returns。使用 CTE,您可以 运行 查询,然后简单地将查询结果视为另一个 table.
显然您需要对此进行测试。我目前无法访问 SQL 服务器,因此这里或那里可能有错字。
我想查询 return table 名称,以及我们两个报告服务器上所有 table 的行数。他们都有相同的tables。另外,前几天我已经在这两者之间添加了链接服务器。
到目前为止查询了一台服务器,但不确定如何添加与我们的另一台服务器连接的第三列:
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
如果您能够从一台服务器获取结果,那么如果链接服务器已设置,您也可以从另一台服务器获取相同的结果。
您可以使用 4 部分名称来完成。例如:
Select ...
From ServerName.DBName.schema.TableName
...
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' 语句,加上您想要执行的任何 table 名称过滤。
这对通用 Table 表达式 (CTE) 非常有用,因为您可以 运行 多个查询,然后将这些查询结果连接在一起,并以不同的方式 analyze/manipulate 它们:
/* 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 的优点是您不必 运行 为每一行设置子查询父查询 returns。使用 CTE,您可以 运行 查询,然后简单地将查询结果视为另一个 table.
显然您需要对此进行测试。我目前无法访问 SQL 服务器,因此这里或那里可能有错字。