如何扫描两个查询之间的差异?

时间:2012-04-11 13:54:03

标签: sql database sql-server-2005 hash checksum

我有一个表每天加载新数据,另一个表包含该表的更改历史记录。检查自上次加载数据以来是否有任何数据发生变化的最佳方法是什么?

例如,我有一些表@a,其中有一些针对不同国家的策略,而表@b跟踪对表@a所做的更改。我可以使用checksum()来散列可以更改的字段,如果现有散列与新散列不同,则将它们添加到表中。但是,MSDN认为这不是一个好主意,因为可能会发生“冲突”,例如两个不同的值映射到相同的校验和。

校验和的MSDN链接 http://msdn.microsoft.com/en-us/library/aa258245(v=SQL.80).aspx

示例代码:

declare @a table
(
    ownerid bigint
    ,Strategy varchar(50)
    ,country char(3)
)
insert into @a
select 1,'Long','USA'

insert into @a
select 2,'Short','CAN'

insert into @a
select 3,'Neutral','AUS'

declare @b table
(
    Lastupdated datetime
    ,ownerid bigint
    ,Strategy varchar(50)
    ,country char(3)

)

insert into @b
(
    Lastupdated
    ,ownerid
    ,strategy
    ,country
)
select 
    getdate()
    ,a.ownerid
    ,a.strategy
    ,a.country
from @a a left join @b b
    on a.ownerid=b.ownerid
where
    b.ownerid is null

select * from @b

--get a different timestamp
waitfor delay '00:00:00.1'

--change source data
update @a 
set strategy='Short'
where ownerid=1

--add newly changed data into 
insert into @b
select 
    getdate()
    ,a.ownerid
    ,a.strategy
    ,a.country
from 
    (select *,checksum(strategy,country) as hashval from @a) a 
    left join 
    (select *,checksum(strategy,country) as hashval from @b) b
    on a.ownerid=b.ownerid
where 
    a.hashval<>b.hashval

select * from @b

3 个答案:

答案 0 :(得分:1)

如果您使用不同的方法解决问题,则无需检查更改。

在主表上为INSERTUPDATEDELETE创建一个触发器,通过写入表@b来跟踪您的更改。

如果您在互联网上搜索“ SQL审核表”,您会发现许多描述该过程的页面,例如:Adding simple trigger-based auditing to your SQL Server database

答案 1 :(得分:1)

如何使用EXCEPT编写查询?只需为两个表编写查询,然后在它们之间添加EXCEPT

(SELECT * FROM table_new) EXCEPT (SELECT * FROM table_old) 

结果将是table_new中不在table_old中的条目(即已更新或插入的条目)。

注意:要获取最近从table_old删除的行,您可以撤消查询的顺序。

答案 2 :(得分:1)

感谢@newenglander我能够使用EXCEPT来查找更改的行。正如@Tony所说,我不确定多个更改是如何工作的,但是这里使用的是相同的示例代码而不是使用Except而不是CHECKSUM

declare @a table
(
    ownerid bigint
    ,Strategy varchar(50)
    ,country char(3)
)
insert into @a
select 1,'Long','USA'

insert into @a
select 2,'Short','CAN'

insert into @a
select 3,'Neutral','AUS'

declare @b table
(
    Lastupdated datetime
    ,ownerid bigint
    ,Strategy varchar(50)
    ,country char(3)

)

insert into @b
(
    Lastupdated
    ,ownerid
    ,strategy
    ,country
)
select 
    getdate()
    ,a.ownerid
    ,a.strategy
    ,a.country
from @a a left join @b b
    on a.ownerid=b.ownerid
where
    b.ownerid is null

select * from @b

--get a different timestamp
waitfor delay '00:00:00.1'

--change source data
update @a 
set strategy='Short'
where ownerid=1



--add newly changed data using EXCEPT
insert into @b 
select getdate(),
    ownerid,
    strategy,
    country
from 
(
    (
    select 
        ownerid
        ,strategy
        ,country 
    from @a changedtable
    ) 
    EXCEPT 
    (
    select 
        ownerid
        ,strategy
        ,country 
    from @b historicaltable
    )
) x

select * from @b