如标题所示,我需要比较两个表来检查差异,这两个表具有相同的结构,但行数不同,列的数据差异。
也有类似的问题。
写了这个存储过程:
/*
**Author: Martin Bartscher
**Find & give out differences between two, 'same' Tables with old and new data.
*/
create or replace proc mb_diff_old_new_table(
@table_old varchar(255) /*table with the old data*/
,@table_new varchar(255) /*table with the new data*/
,@identifier_columns varchar(16384) /*names of the columns, that identify a data set; have to be separated by a single comma*/
,@columns_to_compare varchar(16384) /*names of the columns, that shall be compared; have to be separated by a single comma*/
,@debug bit =0
)
as begin
/*
**declare variables
*/
declare @sql varchar(16384)
,@sql_ident_cols_on varchar(16384)
,@sql_comp_cols_where varchar(16384)
,@sql_select_out_both varchar(16384)
,@id_cols varchar(16384)
,@comp_cols varchar(16384)
,@cur_col varchar(255)
,@crlf char(2)
,@rows_diff_old int
,@rows_diff_new int
,@com_pos int
/*
**initialize variables
*/
set @sql=null
set @sql_ident_cols_on='on ('
set @sql_comp_cols_where='where '
set @sql_select_out_both='select '
set @id_cols=@identifier_columns
set @comp_cols=@columns_to_compare
set @cur_col=null
set @crlf=char(13)+char(10)
set @rows_diff_old=0
set @rows_diff_new=0
set @com_pos=0
/*
**clean up old res-tables if proc ran before
*/
if exists(select name from sysobjects where name='mb_diff_old') begin
drop table mb_diff_old
end
if exists(select name from sysobjects where name='mb_diff_new') begin
drop table mb_diff_new
end
/*
**build 'on' clause with data set identifying columns
*/
while len(@id_cols)>0 begin
set @com_pos=charindex(',',@id_cols)
if @com_pos!=0 begin
set @cur_col=left(@id_cols,@com_pos-1)
set @id_cols=substring(@id_cols,@com_pos+1,len(@id_cols)-@com_pos)
end
else begin
set @cur_col=@id_cols
set @id_cols=null
end
set @sql_ident_cols_on=@sql_ident_cols_on+'ot.'+@cur_col+'=nt.'+@cur_col+@crlf
set @sql_select_out_both=@sql_select_out_both+'ot.'+@cur_col
if @id_cols!=null begin
set @sql_ident_cols_on=@sql_ident_cols_on+' and '
set @sql_select_out_both=@sql_select_out_both+','
end
else begin
set @sql_ident_cols_on=@sql_ident_cols_on+')'
set @sql_select_out_both=@sql_select_out_both+' /*identificational columns*/'+@crlf
end
end
if @debug=1 begin
print 'on-clause: '
print @sql_ident_cols_on
print 'select_out_both: '
print @sql_select_out_both
print '----------------------------------------------------------------'
end
/*
**build 'where' clause with the columns with the values to compare
*/
while len(@comp_cols)>0 begin
set @com_pos=charindex(',',@comp_cols)
if @com_pos!=0 begin
set @cur_col=left(@comp_cols,@com_pos-1)
set @comp_cols=substring(@comp_cols,@com_pos+1,len(@comp_cols)-@com_pos)
end
else begin
set @cur_col=@comp_cols
set @comp_cols=null
end
set @sql_comp_cols_where=@sql_comp_cols_where+'ot.'+@cur_col+'!=nt.'+@cur_col+@crlf
set @sql_select_out_both=@sql_select_out_both+
',ot.'+@cur_col+' as '+@cur_col+'_alt, nt.'+@cur_col+' as '+@cur_col+'_neu'
if @comp_cols!=null begin
set @sql_comp_cols_where=@sql_comp_cols_where+' or '
set @sql_select_out_both=@sql_select_out_both+@crlf
end
end
if @debug=1 begin
print 'where-clause: '
print @sql_comp_cols_where
print 'select_out_both: '
print @sql_select_out_both
print '----------------------------------------------------------------'
end
/*
**all data rows from old table, without equivalent data row in new table
*/
set @sql='select ot.*
into mb_diff_old
from '+@table_old+' ot
left join '+@table_new+' nt
'+@sql_ident_cols_on+'
where nt.QUARTAL=null'
if @debug=1 begin
print 'all data rows from old table, without equivalent data row in new table'
print @sql
print '----------------------------------------------------------------'
end
else begin
exec (@sql)
end
/*
**all data rows from new table, without equivalent data row in old table
*/
set @sql= 'select nt.*
into mb_diff_new
from '+@table_old+' ot
right join '+@table_new+' nt
'+@sql_ident_cols_on+'
where ot.QUARTAL=null'
if @debug=1 begin
print 'all data rows from new table, without equivalent data row in old table'
print @sql
print '----------------------------------------------------------------'
end
else begin
exec (@sql)
end
/*
**all data rows from old table, with difference to new table
*/
set @sql='insert into mb_diff_old
select ot.*
from '+@table_old+' ot
join '+@table_new+' nt
'+@sql_ident_cols_on+'
'+@sql_comp_cols_where
if @debug=1 begin
print 'all data rows from old table, with difference to new table'
print @sql
print '----------------------------------------------------------------'
end
else begin
exec (@sql)
end
/*
**all data rows from new table, with difference to old table
*/
set @sql='insert into mb_diff_new
select nt.*
from '+@table_old+' ot
join '+@table_new+' nt
'+@sql_ident_cols_on+'
'+@sql_comp_cols_where
if @debug=1 begin
print 'all data rows from new table, with difference to old table'
print @sql
print '----------------------------------------------------------------'
end
else begin
exec (@sql)
end
--------------------------------output--------------------------------
/*
**check if differences and put them out
*/
set @sql='select @rows_diff_old=count(*) from mb_diff_old'
if @debug=1 begin
print "Can't determine '@rows_diff_old', because 'mb_diff_old' won't be created in debug mode."
print '----------------------------------------------------------------'
end
else begin
exec (@sql)
end
/*
**If I write this (two) statement(s) directly, the parser thinks of it as a
**mistake, because 'mb_diff_(old/new)' isn't existing when I create the proc...
*/
set @sql='select @rows_diff_new=count(*) from mb_diff_new'
if @debug=1 begin
print "Can't determine '@rows_diff_new', because 'mb_diff_new' won't be created in debug mode."
print '----------------------------------------------------------------'
end
else begin
exec (@sql)
end
/*
**output only if there are differences
*/
if @rows_diff_old!=0 or @rows_diff_new!=0 or @debug=1 begin
/*
**All data sets, that are only in the old results.
*/
set @sql='select "All data sets, that are only in the old results." as "result description"
select ot.*
from mb_diff_old ot
left join mb_diff_new nt
'+@sql_ident_cols_on+'
where nt.QUARTAL=null'
if @debug=1 begin
print 'All data sets, that are only in the old results.'
print @sql
print '----------------------------------------------------------------'
end
else begin
exec (@sql)
end
/*
**All data sets, that are only in the new results.
*/
set @sql='select "All data sets, that are only in the new results." as "result description"
select nt.*
from mb_diff_old ot
right join mb_diff_new nt
'+@sql_ident_cols_on+'
where ot.QUARTAL=null'
if @debug=1 begin
print 'All data sets, that are only in the new results.'
print @sql
print '----------------------------------------------------------------'
end
else begin
exec (@sql)
end
/*
**All data sets, that are in both results, but differ.
*/
set @sql='select "All data sets, that are in both results, but differ." as "result description"
'+@sql_select_out_both+'
from mb_diff_old ot
join mb_diff_new nt
'+@sql_ident_cols_on
if @debug=1 begin
print 'All data sets, that are in both results, but differ.'
print @sql
print '----------------------------------------------------------------'
end
else begin
exec (@sql)
end
end
/*
**output that no differences were found
*/
else begin
select 'There are no differences.' as 'result description'
end
end