Sql 比较两行的通用解决方案
TL;博士Sql 比较两行的通用解决方案,sql,sql-server,tsql,database-schema,Sql,Sql Server,Tsql,Database Schema,TL;博士 是否有一种方法可以在不考虑表架构的情况下比较同一表的两行,但忽略特定列 长 我在一次系统维护中不知从何而来,被要求在几个表中实施审计。。。准确地说是72张桌子。。。我决定在更新和删除时使用触发器。它工作正常,性能符合预期。 我的问题是,系统非常愚蠢,在不做任何更改的情况下更新表上的行,有点像“将X更改为X”,只是行有一个“rowversion”列,因此,最后更新了“rowversion”。我的问题是:是否有一种方法可以比较行的“插入”版本和“删除”版本,而不考虑表架构并忽略特定列(因
是否有一种方法可以在不考虑表架构的情况下比较同一表的两行,但忽略特定列 长
我在一次系统维护中不知从何而来,被要求在几个表中实施审计。。。准确地说是72张桌子。。。我决定在更新和删除时使用触发器。它工作正常,性能符合预期。
我的问题是,系统非常愚蠢,在不做任何更改的情况下更新表上的行,有点像“将X更改为X”,只是行有一个“rowversion”列,因此,最后更新了“rowversion”。我的问题是:是否有一种方法可以比较行的“插入”版本和“删除”版本,而不考虑表架构并忽略特定列(因为如果在操作中获得rowversion,则行将不相同……)。这里的主要目标是一个脚本,我只是在其中更改表名…这里是我刚刚编写的一个脚本,它将创建一个函数,您可以从触发器内部调用该函数以获得比较查询。然后,您可以运行该查询并将结果插入临时表,然后根据行是否更改来执行任何需要执行的操作
create function GetChangedRowsQuery(
@TableName varchar(50),
@PrimaryKeyColumnName varchar(50),
@RowVersionColumnName varchar(50) = ''
)
returns varchar(max)
as
begin
declare
@ColumnName varchar(50),
@GetChangedRowsQuery varchar(max)
select @GetChangedRowsQuery =
'select isnull(a.' + @PrimaryKeyColumnName + ', b.' + + @PrimaryKeyColumnName + ')
from #inserted a
full join #deleted b on a.' + @PrimaryKeyColumnName + ' = b.' + @PrimaryKeyColumnName + '
where '
declare ColumnCursor cursor Read_Only
for select Name
from Sys.columns
where object_id = Object_Id('Member')
open ColumnCursor
fetch next from ColumnCursor into @ColumnName
while @@FETCH_STATUS = 0
begin
if (@ColumnName != @PrimaryKeyColumnName and @ColumnName != @RowVersionColumnName)
begin
select @GetChangedRowsQuery = @GetChangedRowsQuery + '((a.' + @ColumnName + ' != b.' + @ColumnName + ' or a.' + @ColumnName + ' is null or b.' + @ColumnName + ' is null) and (a.' + @ColumnName + ' is not null or b.' + @ColumnName + ' is not null))' + char(13) + ' or '
end
fetch next from ColumnCursor into @ColumnName
end
close ColumnCursor
deallocate ColumnCursor
select @GetChangedRowsQuery = substring(@GetChangedRowsQuery, 0, len(@GetChangedRowsQuery) -7)
return @GetChangedRowsQuery
end
然后你可以创建一个如下所示的触发器
create trigger TestTrigger on Member for Insert, Update, Delete
as
begin
//We can't access the inserted or deleted tables from inside the exec statement
//Dump that data into temp tables so you we can
select *
into #Inserted
from Inserted
select *
into #Deleted
from Deleted
declare @GetChangedRowsQuery varchar(max)
select @GetChangedRowsQuery = dbo.GetChangedRowsQuery('Member', 'MemberId', '')
select @GetChangedRowsQuery
create table #Temp (PrimaryKey int)
insert into #Temp (PrimaryKey)
exec (@GetChangedRowsQuery)
//Do what you need to do with the rows that have or haven't been updated
drop table #Temp
end
go
我已经更新了这个答案十几次了,我想我已经解决了错误,但我不能保证
像这样的查询可能会对性能造成严重影响,我不确定我是否真的建议实现它,但创建它很有趣。我认为最好的选择是编写一个sql脚本,它将为您提取一个表和脚本进行比较。然后可以将该比较粘贴到表的触发器中。是的,您可以
按
字段分组并使用计数
;将having
子句设置为count(unique_field)>=2将显示重复项。不过,表模式很重要,因为您将无法接受相同的查询并在不同的表上使用它。您要求的是一种selectall,除了FROM…
语法,多年来我一直要求ISO-SQL采用这种语法。