2012-04-11 89 views
1

我有一个每天加载新数据的表以及另一个包含该表更改历史记录的表。自上次加载数据以来,检查是否有任何数据发生了更改的最佳方法是什么?如何扫描两个查询之间的差异?

例如,我对表@a有一些适用于不同国家的策略,表@b跟踪对表@a所做的更改。如果现有散列不同于新散列,我可以使用校验和()来散列可以更改的字段,并将它们添加到表中。但是,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 
+1

你有没有在源数据的控制?你最好的选择是有一个日期时间字段来跟踪记录何时被创建和/或修改。然后只提取时间戳比您当前拥有的数据更新的数据。否则,您需要比较每行中的每个字段以查看是否有任何更改。 – MatBailie 2012-04-11 13:59:42

+0

如果“导入”非常简单,那么经常会发现检查成本不仅仅是覆盖,因为您将新数据作为福音。 – 2012-04-11 14:00:38

+1

请让我知道Table @b是否允许同一个ownerid的多条记录。是ownerid是主要关键。 – 2012-05-03 15:00:31

回答

1

如何编写使用EXCEPT查询?只要写两个表的查询,然后将它们之间添加EXCEPT

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

结果将在table_new项不在table_old(即已经被更新或插入)。

注意:要获取最近从table_old中删除的行,可以颠倒查询的顺序。

+0

您假设'table_new'中的每行只有一行'table_old';这意味着第二个表格只是第一个表格的精确副本。如果有多行,那么使用'EXCEPT'将不起作用。 – Tony 2012-05-04 11:00:15

+0

最近从'table_old'中删除的行不会被看到,那是什么意思?我会做笔记。 – newenglander 2012-05-04 11:11:10

+0

这可能是我一直在寻找的!我不得不重新做一点,但会很快发布代码。 – FistOfFury 2012-05-15 19:18:35

1

有没有需要检查的变化,如果你使用不同的方法解决问题。

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

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

+0

这是一个很好的解决方案,但不是我正在尝试解决的问题。具有历史记录的表不仅仅是审计表。我想将新的/更改的结果添加到历史记录表中,以便我可以在给定的时间点引用其状态。例如。如果我有一个日期参数,我希望得到截至该日期的所有最新记录。审计表适用于跟踪历史记录,但不适用于在特定日期获取表的状态。 – FistOfFury 2012-05-15 19:12:56

+0

@FistOfFury - 看起来不错。我始终使用审计表进行时间点报告。特别是什么使它不适合你? (有几种SQL模式使得这一点很简单,尤其是SQL Server的窗口函数和CTE。) – MatBailie 2012-05-16 06:55:07

+0

@Dems为了在给定的时间点获得表的状态,我必须重新创建所有的使用审计表对表进行更改。例如,如果我想知道某个领域的价值是一年前的价值,那么我将不得不使用当前状态和以前的所有状态退出该值。使用历史记录表,我可以通过一个简单的select * from表获取相关行,其中max(timestamp) FistOfFury 2012-05-31 21:35:01

1

感谢@newenglander我能够使用EXCEPT来查找已更改的行。作为@Tony说,我不知道变化会如何影响多个工作,但这里的改造,以使用相同的代码示例除了没有校验

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 
+1

对不起,这些更改被版主拒绝。也许只是尝试发布SQL查询本身,没有添加SQL Server特色? – newenglander 2012-07-17 16:30:34