SQL server学习——两表对照

自己闲来无事的时候就写了一个存储过程,用来对比两张表的相同性。
1、这个存储过程主要是用来查看数据量大的前提下,在不知道删除了什么数据,想要恢复.
2、这个存储过程不考虑表中的数据是否有唯一id,没有id一样行的通
3、表中的列一般情况下不能少于两列,少于两列的没有测试可用性
4、那个恢复数据功能有一个小问题,还没解决掉

/**
*对比两张表的不同
*
**/
alter proc sys_tableVsfit
	@tables_former varchar(1000),--原数据表
	@tables_Delete varchar(1000),--删除数据表
	@tables_Restore varchar(1000)='0' --默认不还原
as
begin
	--去两边的空格
	set @tables_former=ltrim(rtrim(@tables_former))
	set @tables_Delete=ltrim(rtrim(@tables_Delete))
	declare @table_nameFormer varchar(1000),
	--建立所用到的变量
	@table_nameDelete varchar(1000),@name varchar(1000),
	@num varchar(1000),@tb varchar(1000),@addtb varchar(1000),
	@tb_Formerid int,@table_Deleteid int,@tb_FormerCount int,@indexNo varchar(1000),
	@table_DeleteCount int,@Formerlie varchar(1000)='',@Deletelie varchar(1000)=''

	--过渡表
	create table #tb_Former(
	varid int primary key identity(1,1)
)	
	--真实数据表
	create table #tb_FormerReal(
	varid int primary key identity(1,1)
)	
	--删除表id
	create table #tb_Delete(
	varid int primary key identity(1,1)
)
	--删除的数据
	create table #tb_DeleteReal(
	varid int primary key
)
    --查询表中是否有传过来的表名
	select @table_nameFormer=name,@tb_Formerid=id from sysobjects where name=@tables_former
	select @table_nameDelete=name,@table_Deleteid=id from sysobjects where name=@tables_Delete
	--根据表名id查询列名,是否数目相同
	select @tb_FormerCount=count(name) from syscolumns where id=@tb_Formerid 
	select @table_DeleteCount=count(name) from syscolumns where id=@table_Deleteid
	if isnull(@table_nameFormer,null)=null
		begin
			print '输入的原数据表名为空'
			return
		end
	if isnull(@table_nameDelete,null)=null
		begin
			print '输入的删除数据表名为空'
			return
		end
	if @tb_FormerCount<>@table_DeleteCount
		begin
			print '两表不相同,请核对'
			return
		end
	---添加原数据据列,查询真正数据列名
	declare sys_name cursor
	for(
		select name from syscolumns  where  id=@tb_Formerid)
	open sys_name
	--循环下一行游标
	fetch next from sys_name into @name
	while @@FETCH_STATUS=0
		begin
		    --向临时表中添加真是数据库列名
			set @addtb='alter table #tb_Former add ' +@name+ ' varchar(1000)'
			--print @addtb
			exec(@addtb)
			set @addtb='alter table #tb_DeleteReal add ' +@name+ ' varchar(1000)'
			--print @addtb
			exec(@addtb)
			--获取列名为后面进行比较
			set @Formerlie += @name
			
			--print @name
			fetch next from sys_name into @name
		end
	--打印表1里面的列
	--print @formerlie
	close sys_name
	deallocate sys_name


	---查询删除数据列名
	declare sys_name2 cursor
	for(
		select name from syscolumns  where  id=@table_Deleteid)
	open sys_name2
	--循环下一行游标
	fetch next from sys_name2 into @name
	while @@FETCH_STATUS=0
		begin
			--删除表数据、真实数据表 用作varid比较
			set @addtb='alter table #tb_Delete add ' +@name+ ' varchar(1000)'
			exec(@addtb)
			set @addtb='alter table #tb_FormerReal add ' +@name+ ' varchar(1000)'
			exec(@addtb)
			--同理获取列名用作比较
			set @Deletelie += @name

			--print @name
			fetch next from sys_name2 into @name
		end
	--打印表2里面的列
	--print @Deletelie
	close sys_name2
	deallocate sys_name2
	--把真实数据放到临时表里面
	set @addtb='insert #tb_FormerReal select * from '+ @table_nameFormer
	exec(@addtb)
	--判断列名是否相同,(不区分大小写,需求可以改),判断的是列名
	set @indexNo = isnull(nullif(@Formerlie,@Deletelie),'NO')
	if @indexNo<>'NO'
		begin
			print '两表不相同,请核对'
			return
		end
	
	--添加过度列,作用是为了左连接判断删除数据的空值null
	declare @l1 varchar(1000),@l2 varchar(1000),@l3 varchar(1000),@l4 varchar(1000),
	@v1 nvarchar(1000)='',@v2 nvarchar(1000)='',@v3 nvarchar(1000)='',@v4 nvarchar(1000)='',
	@numl int,@numn varchar(1000)='1',@insersql nvarchar(1000)
	--设置一个计时器初始值为零
	set @numl=0
	declare sys_name1 cursor
	for(
		select name from syscolumns  where  id=@tb_Formerid)
	open sys_name1
	--循环下一行游标
	fetch next from sys_name1 into @name
	while @@FETCH_STATUS=0
		begin
			set @addtb='alter table #tb_Former add ' +@name+ '1 varchar(1000)'
			--print @addtb
			exec(@addtb)
			--把列名提取出来
			if @numl=1
				begin
					if isnull(@name,'1')<>'1'
					begin
					set @l1 = @name+@numn
					set @v1 = @name
					end
					else set @l1='*'
				end
			else if @numl=2
				begin
					if isnull(@name,'1')<>'1'
					begin
					set @l2 = @name+'1'
					set @v2 = @name
					end
					else set @l2='*'
				end
			else if @numl=3
				begin
					if isnull(@name,'1')<>'1'
					begin
					set @l3 = @name+@numn
					set @v3 = @name
					end
					else set @l3='*'
				end
			--第一列一般都是id,但是考虑到没有id的情况,添加多个列名
			else if @numl=0
				begin
					if isnull(@name,'1')<>'1'
					begin
					set @l4 = @name+@numn
					set @v4 = @name
					end
					else set @l4='*'
				end
			--把计时器相加
			set @numl+=1
			fetch next from sys_name1 into @name
		end
	close sys_name1
	deallocate sys_name1
	

	--把两个表的值添加进去
	--insert into #tb_Former select * from staff st left join staff1 sf on st.id=sf.id
	--列名只有大于3列才有意义,小于3列一般都是id加值,所以直接确定id就可以了
	set @insersql=
	'insert into #tb_Former select * from '+@table_nameFormer+' st left join '+@table_nameDelete+' sf
	on '+case when @tb_FormerCount>=3 then' st.'+@v4+'=sf.'+@v4+' and st.'+@v1 +'=sf.'+@v1+' and st.'+@v2+'=sf.'+@v2
	else ' st.'+@v4+'=sf.'+@v4 end
	exec(@insersql)
	--循环查询里面的数据
	declare @tb_count int, @n1 Nvarchar(1000),@n2 Nvarchar(1000),@n3 Nvarchar(1000),@n4 Nvarchar(1000),
			--设置默认没有被删除数据
			@sql Nvarchar(1000),@varid int,@index1 varchar(10)='false'
	--获取里面值的总数
	select @tb_count=count(varid) from #tb_Former
	--往删除表里添加删除的id,主要是为了把删除的那些值的varid存进去为以后连表查询做准备
	alter table #tb_Delete add Delete_id int

	while @tb_count >0
		begin
			--查询删除表的数据,为空赋值为'false'
			set @sql='select @varid=varid,'+case when @tb_FormerCount>=3 then '@n1=isnull(cast('+@l1+' as varchar),''false''),@n2=isnull(cast('+@l2+' as varchar),''false''),
			@n3=isnull(cast('+@l3+' as varchar),''false'')' 
			else '@n1=isnull(cast('+@l4+' as varchar),''false''),@n2=isnull(cast('+@l1+' as varchar),''false'')' end +' from #tb_Former where varid=@tb_count'
			--这个执行过程是为了把变量里面的值拿出来
			exec sp_executesql @sql,N'@n1 varchar(1000) out,@n2 varchar(1000) out,@n3 varchar(1000) out,@varid int out,@tb_count int',@n1 out,@n2 out,@n3 out,@varid out,@tb_count
			--都等于false说明是删除的数据,前面的三个空值就可以判定它是删除数据了,
			--前面的三个值是空的,有几率 但是基本不可能,前面的数据一般都是有值的
			if (@n1='false'and @n2='false' and @n3='false')
				begin
					--把查出来删除的varid放到事先准备好的Delete_id里面
					insert into #tb_Delete(Delete_id)
					select varid from #tb_Former where varid=@varid
					--进来就说明里面有删除的数据
					set @index1='true'
				end
			set @tb_count -= 1
		end
	--查询被删除的值
	if @index1<>'true'
		begin
			print '抱歉,你没有删除任何数据'
		end
	if @index1='true'
		begin
			--把删除的varid和真是数据varid关联查询出被删的数据,添加到删除数据的临时表中
			insert into #tb_DeleteReal
			select * from #tb_FormerReal st where st.varid in(
				select sf.Delete_id from #tb_Delete sf
			)
			--查询被删的数据
			set @sql='select * from #tb_DeleteReal'
			exec(@sql)
		end
	--还原数据(bug)暂时不可用
	/*if @tables_Restore='1' or @tables_Restore like'%还原%'
		begin
			--打开标识列
			set @sql='SET IDENTITY_INSERT '+@table_nameDelete+' ON'
			exec(@sql)
			set @sql ='insert into '+ @table_nameDelete+' select * from #tb_FormerReal st where st.varid in(select sf.Delete_id from #tb_Delete sf)'
			exec(@sql)
			--关闭标识列
			set @sql='SET IDENTITY_INSERT '+@table_nameDelete+' OFF'
			exec(@sql)
		end*/
end

/**
*对比两张表的不同
*
**/
alter proc sys_tableVsfit
	@tables_former varchar(1000),--原数据表
	@tables_Delete varchar(1000),--删除数据表
	@tables_Restore varchar(1000)='0' --默认不还原
as
begin
	--去两边的空格
	set @tables_former=ltrim(rtrim(@tables_former))
	set @tables_Delete=ltrim(rtrim(@tables_Delete))
	declare @table_nameFormer varchar(1000),
	--建立所用到的变量
	@table_nameDelete varchar(1000),@name varchar(1000),
	@num varchar(1000),@tb varchar(1000),@addtb varchar(1000),
	@tb_Formerid int,@table_Deleteid int,@tb_FormerCount int,@indexNo varchar(1000),
	@table_DeleteCount int,@Formerlie varchar(1000)='',@Deletelie varchar(1000)=''

	--过渡表
	create table #tb_Former(
	varid int primary key identity(1,1)
)	
	--真实数据表
	create table #tb_FormerReal(
	varid int primary key identity(1,1)
)	
	--删除表id
	create table #tb_Delete(
	varid int primary key identity(1,1)
)
	--删除的数据
	create table #tb_DeleteReal(
	varid int primary key
)
    --查询表中是否有传过来的表名
	select @table_nameFormer=name,@tb_Formerid=id from sysobjects where name=@tables_former
	select @table_nameDelete=name,@table_Deleteid=id from sysobjects where name=@tables_Delete
	--根据表名id查询列名,是否数目相同
	select @tb_FormerCount=count(name) from syscolumns where id=@tb_Formerid 
	select @table_DeleteCount=count(name) from syscolumns where id=@table_Deleteid
	if isnull(@table_nameFormer,null)=null
		begin
			print '输入的原数据表名为空'
			return
		end
	if isnull(@table_nameDelete,null)=null
		begin
			print '输入的删除数据表名为空'
			return
		end
	if @tb_FormerCount<>@table_DeleteCount
		begin
			print '两表不相同,请核对'
			return
		end
	---添加原数据据列,查询真正数据列名
	declare sys_name cursor
	for(
		select name from syscolumns  where  id=@tb_Formerid)
	open sys_name
	--循环下一行游标
	fetch next from sys_name into @name
	while @@FETCH_STATUS=0
		begin
		    --向临时表中添加真是数据库列名
			set @addtb='alter table #tb_Former add ' +@name+ ' varchar(1000)'
			--print @addtb
			exec(@addtb)
			set @addtb='alter table #tb_DeleteReal add ' +@name+ ' varchar(1000)'
			--print @addtb
			exec(@addtb)
			--获取列名为后面进行比较
			set @Formerlie += @name
			
			--print @name
			fetch next from sys_name into @name
		end
	--打印表1里面的列
	--print @formerlie
	close sys_name
	deallocate sys_name


	---查询删除数据列名
	declare sys_name2 cursor
	for(
		select name from syscolumns  where  id=@table_Deleteid)
	open sys_name2
	--循环下一行游标
	fetch next from sys_name2 into @name
	while @@FETCH_STATUS=0
		begin
			--删除表数据、真实数据表 用作varid比较
			set @addtb='alter table #tb_Delete add ' +@name+ ' varchar(1000)'
			exec(@addtb)
			set @addtb='alter table #tb_FormerReal add ' +@name+ ' varchar(1000)'
			exec(@addtb)
			--同理获取列名用作比较
			set @Deletelie += @name

			--print @name
			fetch next from sys_name2 into @name
		end
	--打印表2里面的列
	--print @Deletelie
	close sys_name2
	deallocate sys_name2
	--把真实数据放到临时表里面
	set @addtb='insert #tb_FormerReal select * from '+ @table_nameFormer
	exec(@addtb)
	--判断列名是否相同,(不区分大小写,需求可以改),判断的是列名
	set @indexNo = isnull(nullif(@Formerlie,@Deletelie),'NO')
	if @indexNo<>'NO'
		begin
			print '两表不相同,请核对'
			return
		end
	
	--添加过度列,作用是为了左连接判断删除数据的空值null
	declare @l1 varchar(1000),@l2 varchar(1000),@l3 varchar(1000),@l4 varchar(1000),
	@v1 nvarchar(1000)='',@v2 nvarchar(1000)='',@v3 nvarchar(1000)='',@v4 nvarchar(1000)='',
	@numl int,@numn varchar(1000)='1',@insersql nvarchar(1000)
	--设置一个计时器初始值为零
	set @numl=0
	declare sys_name1 cursor
	for(
		select name from syscolumns  where  id=@tb_Formerid)
	open sys_name1
	--循环下一行游标
	fetch next from sys_name1 into @name
	while @@FETCH_STATUS=0
		begin
			set @addtb='alter table #tb_Former add ' +@name+ '1 varchar(1000)'
			--print @addtb
			exec(@addtb)
			--把列名提取出来
			if @numl=1
				begin
					if isnull(@name,'1')<>'1'
					begin
					set @l1 = @name+@numn
					set @v1 = @name
					end
					else set @l1='*'
				end
			else if @numl=2
				begin
					if isnull(@name,'1')<>'1'
					begin
					set @l2 = @name+'1'
					set @v2 = @name
					end
					else set @l2='*'
				end
			else if @numl=3
				begin
					if isnull(@name,'1')<>'1'
					begin
					set @l3 = @name+@numn
					set @v3 = @name
					end
					else set @l3='*'
				end
			--第一列一般都是id,但是考虑到没有id的情况,添加多个列名
			else if @numl=0
				begin
					if isnull(@name,'1')<>'1'
					begin
					set @l4 = @name+@numn
					set @v4 = @name
					end
					else set @l4='*'
				end
			--把计时器相加
			set @numl+=1
			fetch next from sys_name1 into @name
		end
	close sys_name1
	deallocate sys_name1
	

	--把两个表的值添加进去
	--insert into #tb_Former select * from staff st left join staff1 sf on st.id=sf.id
	--列名只有大于3列才有意义,小于3列一般都是id加值,所以直接确定id就可以了
	set @insersql=
	'insert into #tb_Former select * from '+@table_nameFormer+' st left join '+@table_nameDelete+' sf
	on '+case when @tb_FormerCount>=3 then' st.'+@v4+'=sf.'+@v4+' and st.'+@v1 +'=sf.'+@v1+' and st.'+@v2+'=sf.'+@v2
	else ' st.'+@v4+'=sf.'+@v4 end
	exec(@insersql)
	--循环查询里面的数据
	declare @tb_count int, @n1 Nvarchar(1000),@n2 Nvarchar(1000),@n3 Nvarchar(1000),@n4 Nvarchar(1000),
			--设置默认没有被删除数据
			@sql Nvarchar(1000),@varid int,@index1 varchar(10)='false'
	--获取里面值的总数
	select @tb_count=count(varid) from #tb_Former
	--往删除表里添加删除的id,主要是为了把删除的那些值的varid存进去为以后连表查询做准备
	alter table #tb_Delete add Delete_id int

	while @tb_count >0
		begin
			--查询删除表的数据,为空赋值为'false'
			set @sql='select @varid=varid,'+case when @tb_FormerCount>=3 then '@n1=isnull(cast('+@l1+' as varchar),''false''),@n2=isnull(cast('+@l2+' as varchar),''false''),
			@n3=isnull(cast('+@l3+' as varchar),''false'')' 
			else '@n1=isnull(cast('+@l4+' as varchar),''false''),@n2=isnull(cast('+@l1+' as varchar),''false'')' end +' from #tb_Former where varid=@tb_count'
			--这个执行过程是为了把变量里面的值拿出来
			exec sp_executesql @sql,N'@n1 varchar(1000) out,@n2 varchar(1000) out,@n3 varchar(1000) out,@varid int out,@tb_count int',@n1 out,@n2 out,@n3 out,@varid out,@tb_count
			--都等于false说明是删除的数据,前面的三个空值就可以判定它是删除数据了,
			--前面的三个值是空的,有几率 但是基本不可能,前面的数据一般都是有值的
			if (@n1='false'and @n2='false' and @n3='false')
				begin
					--把查出来删除的varid放到事先准备好的Delete_id里面
					insert into #tb_Delete(Delete_id)
					select varid from #tb_Former where varid=@varid
					--进来就说明里面有删除的数据
					set @index1='true'
				end
			set @tb_count -= 1
		end
	--查询被删除的值
	if @index1<>'true'
		begin
			print '抱歉,你没有删除任何数据'
		end
	if @index1='true'
		begin
			--把删除的varid和真是数据varid关联查询出被删的数据,添加到删除数据的临时表中
			insert into #tb_DeleteReal
			select * from #tb_FormerReal st where st.varid in(
				select sf.Delete_id from #tb_Delete sf
			)
			--查询被删的数据
			set @sql='select * from #tb_DeleteReal'
			exec(@sql)
		end
	--还原数据(bug)暂时不可用
	/*if @tables_Restore='1' or @tables_Restore like'%还原%'
		begin
			--打开标识列
			set @sql='SET IDENTITY_INSERT '+@table_nameDelete+' ON'
			exec(@sql)
			set @sql ='insert into '+ @table_nameDelete+' select * from #tb_FormerReal st where st.varid in(select sf.Delete_id from #tb_Delete sf)'
			exec(@sql)
			--关闭标识列
			set @sql='SET IDENTITY_INSERT '+@table_nameDelete+' OFF'
			exec(@sql)
		end*/
end

在这里注释就不写了,写的可能有点乱