Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/79.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 比较两行的通用解决方案_Sql_Sql Server_Tsql_Database Schema - Fatal编程技术网

Sql 比较两行的通用解决方案

Sql 比较两行的通用解决方案,sql,sql-server,tsql,database-schema,Sql,Sql Server,Tsql,Database Schema,TL;博士 是否有一种方法可以在不考虑表架构的情况下比较同一表的两行,但忽略特定列 长 我在一次系统维护中不知从何而来,被要求在几个表中实施审计。。。准确地说是72张桌子。。。我决定在更新和删除时使用触发器。它工作正常,性能符合预期。 我的问题是,系统非常愚蠢,在不做任何更改的情况下更新表上的行,有点像“将X更改为X”,只是行有一个“rowversion”列,因此,最后更新了“rowversion”。我的问题是:是否有一种方法可以比较行的“插入”版本和“删除”版本,而不考虑表架构并忽略特定列(因

TL;博士
是否有一种方法可以在不考虑表架构的情况下比较同一表的两行,但忽略特定列


我在一次系统维护中不知从何而来,被要求在几个表中实施审计。。。准确地说是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采用这种语法。