【问题标题】:How to compare data between two table in different databases using Sql Server 2008?如何使用 Sql Server 2008 比较不同数据库中两个表之间的数据?
【发布时间】:2011-11-28 04:51:40
【问题描述】:

我有两个数据库,在 Sql server 2008 中命名为 DB1 和 DB2。这两个数据库有相同的表和相同的表数据。但是,我想检查这些表中的数据之间是否存在任何差异。

谁能帮我写一个脚本?

【问题讨论】:

标签: sql sql-server sql-server-2008


【解决方案1】:

我已经使用 Checksum(*) 函数完成了类似的操作

本质上,它会在所有列数据上创建一个行级校验和,然后您可以将每个表的每一行的校验和相互比较,使用左连接来查找不同的行。

希望这是有道理的......

举个例子更好....

select *
from 
( select checksum(*) as chk, userid as k from UserAccounts) as t1
left join 
( select checksum(*) as chk, userid as k from UserAccounts) as t2 on t1.k = t2.k
where t1.chk <> t2.chk 

【讨论】:

  • 这不起作用,因为没有定义UserAccounts
【解决方案2】:
select * from DB1.dbo.Table a inner join DB2.dbo.Table b on b.PrimKey = a.PrimKey 
where a.FirstColumn <> b.FirstColumn ...

Matt 推荐的校验和可能是比较列而不是比较每一列的更好方法

【讨论】:

  • 您可以编写一个 t-sql 脚本,以编程方式创建所有这些查询。所有元数据都在系统表和视图中
  • 查看此问题以获取主键stackoverflow.com/questions/222217/…
【解决方案3】:

如果数据库位于同一服务器中,则在访问位于不同数据库中的表时使用[DatabaseName].[Owner].[TableName] 格式。

例如:[DB1].[dbo].[TableName]

如果不同服务器中的数据库查看Creating Linked Servers (SQL Server Database Engine)

【讨论】:

    【解决方案4】:
    select * 
    from (
          select 'T1' T, *
          from DB1.dbo.Table
          except
          select 'T2' T, *
          from DB2.dbo.Table
         ) as T
    union all
    select * 
    from (
          select 'T2' T, *
          from DB2.dbo.Table
          except
          select 'T1' T, *
          from DB1.dbo.Table
         ) as T
    ORDER BY 2,3,4, ..., 1  -- make T1 and T2 to be close in output 2,3,4 are UNIQUE KEY SEGMENTS
    

    测试代码:

    declare @T1 table (ID int)
    declare @T2 table (ID int)
    
    insert into @T1 values(1),(2)
    insert into @T2 values(2),(3)
    
    select * 
    from (
          select *
          from @T1
          except
          select *
          from @T2
         ) as T
    union all
    select * 
    from (
          select *
          from @T2
          except
          select *
          from @T1
         ) as T
    

    结果:

    ID
    -----------
    1
    3
    

    注意:在开发“调整”解决方案或重构时,比较大表可能需要很长时间,这将给出与 REFERERCE 相同的结果 - 首先检查简单参数可能是明智的:like

    select count(t.*) from (
       select count(*) c0, SUM(BINARY_CHECKSUM(*)%1000000) c1 FROM T_REF_TABLE 
       -- select 12345 c0, -214365454 c1 -- constant values FROM T_REF_TABLE 
       except 
       select count(*) , SUM(BINARY_CHECKSUM(*)%1000000) FROM T_WORK_COPY 
    ) t
    

    当它为空时,您可能已经控制了一些事情,并且可能您可以在失败时进行修改,您会看到“从 T_REF 开始的常量值”到 isert 以节省更多时间进行下一次检查!!!

    【讨论】:

    • 请让我明白,什么是“except”关键字和“union all”?
    • @JagadisSahu “除了返回左侧查询中未在右侧查询中找到的任何不同值。” msdn.microsoft.com/en-us/library/ms188055.aspx
    • @JagadisSahu "UNION 指定要组合多个结果集并作为单个结果集返回。"。 msdn.microsoft.com/en-us/library/ms180026.aspx
    • 当您处于无法安装 redgate 但您可以访问两个数据库的环境中时,这种模式非常棒!非常感谢!
    【解决方案5】:

    另一种解决方案(非T-SQL):您可以使用tablediff 实用程序。 例如,如果您想比较来自两个不同服务器(ROBUH01 和 ROBUH02)的两个表(Localitate),您可以使用以下 shell 命令:

    C:\Program Files\Microsoft SQL Server\100\COM>tablediff -sourceserver ROBUH01 -s
    ourcedatabase SIM01 -sourceschema dbo -sourcetable Localitate -destinationserver
     ROBUH02 -destinationschema dbo -destinationdatabase SIM02 -destinationtable Lo
    calitate
    

    结果:

    Microsoft (R) SQL Server Replication Diff Tool Copyright (c) 2008 Microsoft Corporation User-specified agent parameter values: 
    -sourceserver ROBUH01 
    -sourcedatabase SIM01 
    -sourceschema dbo 
    -sourcetable Localitate 
    -destinationserver ROBUH02 
    -destinationschema dbo 
    -destinationdatabase SIM02 
    -destinationtable Localitate 
    
    Table [SIM01].[dbo].[Localitate] on ROBUH01 and Table [SIM02].[dbo].[Localitate ] on ROBUH02 have 10 differences. 
    
    Err Id Dest. 
    Only 21433 Dest. 
    Only 21434 Dest. 
    Only 21435 Dest. 
    Only 21436 Dest. 
    Only 21437 Dest. 
    Only 21438 Dest. 
    Only 21439 Dest. 
    Only 21441 Dest. 
    Only 21442 Dest. 
    Only 21443 
    The requested operation took 9,9472657 seconds.
    ------------------------------------------------------------------------
    

    【讨论】:

      【解决方案6】:

      我真的建议遇到这个问题的人去寻找第三方数据库比较工具。

      原因 - 这些工具节省了大量时间,并使流程不易出错。

      我使用过 ApexSQL 的 comparison tools(Diff 和 Data Diff),但使用 marc_s 和 Marina Nastenko 已经指出的其他工具不会出错。

      如果您绝对确定您只会比较表一次,那么 SQL 就可以了,但如果您不时需要它,您最好使用一些 3rd 方工具。

      如果您没有预算购买它,那么只需在试用模式下使用它即可完成工作。

      我希望新读者会发现这很有用,即使它是一个迟到的答案......

      【讨论】:

      • 您的评论不相关。有时您需要以编程方式运行比较。
      【解决方案7】:

      比较 SQL 数据库中的两个数据库。试试这个查询它可能会有所帮助。

      SELECT T.[name] AS [table_name], AC.[name] AS [column_name],  TY.[name] AS 
         system_data_type FROM    [***Database Name 1***].sys.[tables] AS T  
         INNER JOIN [***Database Name 1***].sys.[all_columns] AC ON T.[object_id] = AC.[object_id]      
         INNER JOIN [***Database Name 1***].sys.[types] TY ON AC.[system_type_id] = TY.[system_type_id] 
         EXCEPT SELECT T.[name] AS [table_name], AC.[name] AS [column_name], TY.[name] AS system_data_type FROM    ***Database Name 2***.sys.[tables] AS T  
         INNER JOIN ***Database Name 2***.sys.[all_columns] AC ON T.[object_id] = AC.[object_id]  
         INNER JOIN ***Database Name 2***.sys.[types] TY ON AC.[system_type_id] = TY.[system_type_id]
      

      【讨论】:

        【解决方案8】:

        如果两个数据库在同一台服务器上。您可以使用以下查询检查类似的表:

        select 
              fdb.name, sdb.name 
        from 
              FIRSTDBNAME.sys.tables fdb 
              join SECONDDBNAME.sys.tables sdb
              on fdb.name = sdb.name -- compare same name tables
        order by 
              1     
        

        通过列出相似的表,您可以使用sys.columns 视图比较列架构。

        希望对你有所帮助。

        【讨论】:

          【解决方案9】:

          为了比较两个数据库,我编写了以下程序。 如果要比较两个表,可以使用过程“CompareTables”。示例:

          EXEC master.dbo.CompareTables 'DB1', 'dbo', 'table1', 'DB2', 'dbo', 'table2'
          

          如果要比较两个数据库,请使用过程“CompareDatabases”。示例:

          EXEC master.dbo.CompareDatabases 'DB1', 'DB2'
          

          注意: - 我试图使程序安全,但无论如何,这些程序仅用于测试和调试。 - 如果您想要一个完整的比较解决方案,请使用第三方(Visual Studio,...)

          USE [master]
          GO
          
          create proc [dbo].[CompareDatabases]
              @FirstDatabaseName nvarchar(50),
              @SecondDatabaseName nvarchar(50)
              as
          begin
              -- Check that databases exist
              if not exists(SELECT name FROM sys.databases WHERE name=@FirstDatabaseName)
                  return 0
              if not exists(SELECT name FROM sys.databases WHERE name=@SecondDatabaseName)
                  return 0
          
              declare @result table (TABLE_NAME nvarchar(256))
              SET NOCOUNT ON
              insert into @result EXEC('(Select distinct TABLE_NAME from ' + @FirstDatabaseName  + '.INFORMATION_SCHEMA.COLUMNS '
                                              +'Where TABLE_SCHEMA=''dbo'')'
                                      + 'intersect'
                                      + '(Select distinct TABLE_NAME from ' + @SecondDatabaseName  + '.INFORMATION_SCHEMA.COLUMNS '
                                              +'Where TABLE_SCHEMA=''dbo'')')
          
              DECLARE @TABLE_NAME nvarchar(256)
              DECLARE curseur CURSOR FOR
                  SELECT TABLE_NAME FROM @result
              OPEN curseur
              FETCH curseur INTO @TABLE_NAME
                  WHILE @@FETCH_STATUS = 0
                      BEGIN
                          print 'TABLE : ' + @TABLE_NAME
                          EXEC master.dbo.CompareTables @FirstDatabaseName, 'dbo', @TABLE_NAME, @SecondDatabaseName, 'dbo', @TABLE_NAME
                          FETCH curseur INTO @TABLE_NAME
                      END
                  CLOSE curseur
              DEALLOCATE curseur
              SET NOCOUNT OFF
          end
          GO
          

          .

          USE [master]
          GO
          
          CREATE PROC [dbo].[CompareTables]
              @FirstTABLE_CATALOG nvarchar(256),
              @FirstTABLE_SCHEMA nvarchar(256),
              @FirstTABLE_NAME nvarchar(256),
              @SecondTABLE_CATALOG nvarchar(256),
              @SecondTABLE_SCHEMA nvarchar(256),
              @SecondTABLE_NAME nvarchar(256)
              AS
          BEGIN
              -- Verify if first table exist
              DECLARE @table1 nvarchar(256) = @FirstTABLE_CATALOG + '.' + @FirstTABLE_SCHEMA + '.' + @FirstTABLE_NAME
              DECLARE @return_status int
              EXEC @return_status = master.dbo.TableExist @FirstTABLE_CATALOG, @FirstTABLE_SCHEMA, @FirstTABLE_NAME
              IF @return_status = 0
                  BEGIN
                      PRINT @table1 + ' : Table Not FOUND'
                      RETURN 0
                  END
          
          
          
              -- Verify if second table exist
              DECLARE @table2 nvarchar(256) = @SecondTABLE_CATALOG + '.' + @SecondTABLE_SCHEMA + '.' + @SecondTABLE_NAME
              EXEC @return_status = master.dbo.TableExist @SecondTABLE_CATALOG, @SecondTABLE_SCHEMA, @SecondTABLE_NAME
              IF @return_status = 0
                  BEGIN
                      PRINT @table2 + ' : Table Not FOUND'
                      RETURN 0
                  END
          
              -- Compare the two tables
              DECLARE @sql AS NVARCHAR(MAX)
              SELECT @sql = '('
                          + '(SELECT ''' + @table1 + ''' as _Table, * FROM ' + @FirstTABLE_CATALOG + '.' + @FirstTABLE_SCHEMA + '.' + @FirstTABLE_NAME + ')'
                          + 'EXCEPT'
                          + '(SELECT ''' + @table1 + ''' as _Table, * FROM ' + @SecondTABLE_CATALOG + '.' + @SecondTABLE_SCHEMA + '.' + @SecondTABLE_NAME + ')'
                          + ')'
                          + 'UNION'
                          + '('
                          + '(SELECT ''' + @table2 + ''' as _Table, * FROM ' + @SecondTABLE_CATALOG + '.' + @SecondTABLE_SCHEMA + '.' + @SecondTABLE_NAME + ')'
                          + 'EXCEPT'
                          + '(SELECT ''' + @table2 + ''' as _Table, * FROM ' + @FirstTABLE_CATALOG + '.' + @FirstTABLE_SCHEMA + '.' + @FirstTABLE_NAME + ')'
                          + ')'
              DECLARE @wrapper AS NVARCHAR(MAX) = 'if exists (' + @sql + ')' + char(10) + '    (' + @sql + ')ORDER BY 2'
              Exec(@wrapper)
          END
          GO
          

          .

          USE [master]
          GO
          
          CREATE PROC [dbo].[TableExist]
              @TABLE_CATALOG nvarchar(256),
              @TABLE_SCHEMA nvarchar(256),
              @TABLE_NAME nvarchar(256)
              AS
          BEGIN
              IF NOT EXISTS(SELECT name FROM sys.databases WHERE name=@TABLE_CATALOG)
                  RETURN 0
          
              declare @result table (TABLE_SCHEMA nvarchar(256), TABLE_NAME nvarchar(256))
              SET NOCOUNT ON
              insert into @result EXEC('Select TABLE_SCHEMA, TABLE_NAME from ' + @TABLE_CATALOG  + '.INFORMATION_SCHEMA.COLUMNS')
              SET NOCOUNT OFF
          
              IF EXISTS(SELECT TABLE_SCHEMA, TABLE_NAME FROM @result
                          WHERE TABLE_SCHEMA=@TABLE_SCHEMA AND TABLE_NAME=@TABLE_NAME)
                  RETURN 1
          
              RETURN 0
          END
          
          GO
          

          【讨论】:

          • 这与@Mikael Eriksson 接受的答案有何不同?看起来您重复使用了已接受的答案并将其放入 CREATE PROC 语句中。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-07-18
          • 1970-01-01
          • 2022-01-23
          • 2013-12-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多