打包程序时,往往需要把测试数据清除掉,最直接的方法是,导出SQL脚本时,只导出结构。但如果使用备份还原的模式,清除数据记录就会有点麻烦,尤其使用自增字段为主键,delete之后数据清空,但增长的初始值还是基于原有数据。
如果表不多的话,可以使用逐个TRUNCATE TABLE命令。如果表比较多的时候,写个for循环也就OK了,但还需注意一个细节,即表中可能存在外键,如果不处理,是无法清除数据的,因此在循环之前先使用系统存储过程sp_MSforeachtable禁用外键检测,清除完成后,再打开就可以了。
use dbname;
--禁用表中所有的外键
EXEC sp_MSforeachtable @command1='alter table? NOCHECK constraint all';
--查询数据到临时表 生成有序index列 用于后面遍历
select row_number() over(order by name desc) as 'rowindex',* into #test_temp from ( SELECT name FROM SysObjects Where XType='U') as A;
--遍历数据表test中的数据
declare @i int,@flag int
select @flag=count(rowindex)+1 from #test_temp
set @i=1
declare @v1 varchar(500)
while(@i<@flag)
begin
select @v1=name from #test_temp where rowindex=@i ;
exec('TRUNCATE TABLE '+ @v1);
--清除数据表
set @i=@i+1;
end
--启用数据表中的外键
EXEC sp_MSforeachtable @command1='alter table? CHECK constraint all';
--删除临时表
drop table #test_temp
在我本机测试过之后,移到服务器执行出现外键的问题,报错如下。
查询资料之后,发现以上代码可以有更简单的写法。
--关闭约束
EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
--关闭触发器
EXEC sp_MSForEachTable 'ALTER TABLE ? DISABLE TRIGGER ALL'
--清空表
EXEC sp_MSForEachTable 'TRUNCATE TABLE ?'
--启用约束
EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
--启用触发器
EXEC sp_MSForEachTable 'ALTER TABLE ? ENABLE TRIGGER ALL'
但简单归简单,却不能从根本上解决问题。继续查询,最后找到一个折中的方案,即遍历库中所有的表,然后把表中的自增字段重设种子,之后清除DB的的日志信息。
if( object_id('pr_DataClear') is not null )
drop procedure pr_DataClear
go
create procedure pr_DataClear
as
begin transaction
declare @cTblName varchar(128)
declare cur_Clear cursor for select rtrim(name) from sysobjects where type = 'U' order by crdate desc
open cur_Clear
declare @cSQL varchar(255)
fetch next from cur_Clear into @cTblName
while( @@fetch_status = 0)
begin
set @cSQL = 'delete from ' + @cTblName
print @cSQL
exec( @cSQL )
if( ident_seed(@cTblName) is not null )
begin
dbcc checkident( @cTblName, reseed, 0 )
print '有种子且成功重置为1'
end
fetch next from cur_Clear into @cTblName
end
close cur_Clear
deallocate cur_Clear
commit
go
-- 清空所有表数据
exec pr_DataClear
-- 截断日志
ALTER DATABASE DBName SET RECOVERY SIMPLE
dbcc shrinkdatabase( DBName )
dbcc updateusage( DBName )
问题解决,使用时,替换脚本中的DBName为你的数据库名。谨慎操作,数据丢失不可恢复。如有更好方案,还请共享。