我有一个实时数据表,其中放置旧值,在新表中我将数据从该实时表移动到此表如何查找在新表中插入或更新的更新或新记录,而不使用,校验和(binary_checksum)和join,我正在寻找使用系统定义函数的解决方案。
这个要求很有意思,因为最好的解决方案是使用EXCEPT
或FULL JOIN
。你想要做的是所谓的left anti semi join
。这是一个good article about the topic。
请注意此示例数据和解决方案(请注意,我的解决方案不使用EXCEPT或连接是最后一个解决方案):
-- sample data
if object_id('tempdb.dbo.orig') is not null drop table dbo.orig;
if object_id('tempdb.dbo.new') is not null drop table dbo.new;
create table dbo.orig (someid int, col1 int, constraint uq_cl_orig unique (someid, col1));
create table dbo.new (someid int, col1 int, constraint uq_cl_new unique (someid, col1));
insert dbo.orig values (1,100),(2,110),(3,120),(4,2000)
insert dbo.new values (1,100),(2,110),(3,122),(5,999);
这是EXCEPT版本
select someid
from
(
select * from dbo.new except
select * from dbo.orig
) n
union -- union "distict"
select someid
from
(
select * from dbo.orig except
select * from dbo.new
) o;
这是一个全连接解决方案,它还会告诉您记录是否被删除,更改或添加:
select
someid = isnull(n.someid, o.someid),
[status] =
case
when count(isnull(n.someid, o.someid)) > 1 then 'changed'
when max(n.col1) is null then 'removed' else 'added'
end
from dbo.new n
full join dbo.orig o
on n.col1=o.col1 and n.someid = o.someid
where n.col1 is null or o.col1 is null
group by isnull(n.someid, o.someid);
但是,因为那些有效的解决方案不是一个选项 - 你需要使用NOT IN或NOT EXISTS子查询....并且因为它必须是一个函数,我将逻辑封装到一个函数中。
create function dbo.newOrChangedOrRemoved()
returns table as return
-- get the new records
select someid, [status] = 'new'
from dbo.new n
where n.someid not in (select someid from dbo.orig)
union all
-- get the removed records
select someid, 'removed'
from dbo.orig o
where o.someid not in (select someid from dbo.new)
union all
-- get the changed records
select someid, 'changed'
from dbo.orig o
where exists
(
select *
from dbo.new n
where o.someid = n.someid and o.col1 <> n.col1
);
结果:
someid status
----------- -------
5 new
4 removed
3 changed