在做项目的过程中,经常会遇到一种情况,开发和测试过程中,会往业务表中添加很多测试数据,等到项目重新发布时需要删除数据并且让主键重新从1开始,若是表比较少还好办,多起来就不好玩了。昨天就碰到这么个事儿,总共50多张表,弄了个将近半个小时,弄完之后想想有没有更好的办法呢,就去网上搜了一下思路,结合实际情况写了如下的存储过程。
需要说明的几点:
1、数据库比较特殊,系统表和业务表取名不同,系统表如实取名,业务表统一为table...,且在一个为S_ENTITY(实体表)中有注明,所以我只需要从S_ENTITY表中获取以table打开的表进行初始化即可。
2、测试数据库用的SQL Server 2005。
3、存储过程思路:先将业务表的结构复制到临时表,再删除业务表,再将临时表中的结构复制到业务表,最后删除临时表。
4、缺点是:因为复制的临时表,所以原来的业务表中的特殊应用如触发器,索引等都会没有,也就是此操作之后新的业务表什么触发器啊、索引啊等特殊应该都会木有,只有一个基本结构。
以下为实现过程:
1、实体表创建:
SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO SET ANSI_PADDING ON GO CREATE TABLE [dbo].[S_ENTITY]( [S_ID] [int] IDENTITY(1,1) NOT NULL, [ENTITYNAME] [varchar](100) COLLATE Chinese_PRC_CI_AS NULL, [ENTITYDESCRIPT] [varchar](200) COLLATE Chinese_PRC_CI_AS NULL CONSTRAINT [PK_S_ENTITY] PRIMARY KEY CLUSTERED ( [S_ID] ASC )WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO SET ANSI_PADDING OFF GO
2、insert测试数据:
insert into S_ENTITY(ENTITYNAME,ENTITYDESCRIPT) values('table1','测试表1') insert into S_ENTITY(ENTITYNAME,ENTITYDESCRIPT) values('table2','测试表2') insert into S_ENTITY(ENTITYNAME,ENTITYDESCRIPT) values('table3','测试表3')
3、创建存储过程:
-- ============================================= -- Author: <wjl> -- Create date: <2015-5-13> -- Description: <初始化业务表中的数据,包括删除业务表数据并复位主键> -- ============================================= CREATE PROCEDURE [dbo].[initData] AS BEGIN SET NOCOUNT ON; --1、从实体表中获取业务数据表:以table开头 declare @count int;--记录符合条件的表的数量 select @count = count(S_ID) from S_ENTITY where ENTITYNAME like '%table%' print @count; if(@count>0)--说明有符合条件的table begin declare @c int; declare @tableName varchar(100);--表名 declare @tempTableName varchar(100);--临时表名称 declare @PKColumn varchar(50);--主键所在列名称 declare @sql varchar(200);--拼接的SQL语句 set @c = 1; while(@c<=@count)--依次循环各个表 begin --获取表名称 select @tableName = ENTITYNAME from ( select ENTITYNAME,row_number() over(order by S_ID) as fn from S_ENTITY where ENTITYNAME like '%table%') as a where fn=@c; print @tableName; --2、将表结构复制到临时表中 set @tempTableName = '##TEMP_TAB_'+@tableName;--使用全局临时表,使用本地临时表会报“找不到临时表”的错误。 print @tempTableName; --判断临时表是否存在 if exists(select * from tempdb..sysobjects where id=object_id('tempdb..'+@tempTableName+'')) begin print '临时表存在'; set @sql = 'drop table '+@tempTableName+';'--若存在则删除 exec(@sql); end --判断物理表是否存在 if object_id(N''+@tableName+'',N'U') is not null print '物理表存在' else begin print @tableName; print '物理表不存在' set @c=@c+1;--循环数加1,否则会死循环 continue;--不存在跳出当前循环,进行下一个循环 end set @sql = 'SELECT * INTO '+@tempTableName+' FROM '+@tableName+ ' where 1=2';--只复制结构,不复制数据 print @sql; exec(@sql); --3、获取主键所在列: --因为复制结构到临时表时除了主键信息之外,其重要的自增信息也会复制过去,所以只需要设置自增信息即可 --(前提条件是当前表上没有其他的特殊应用,若有其他特殊应用如触发器/索引什么的,都会丢失) SELECT @PKColumn=COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME=@tableName; print @PKColumn; --4、删除原有表 set @sql = 'drop table '+@tableName+';' print @sql; exec(@sql); --5、通过临时表新建原有表 set @sql = 'SELECT * INTO '+@tableName+' FROM '+@tempTableName+' where 1=2;';--新建结构,没有数据 print @sql; exec(@sql); --6、为新表添加主键:因为新建的表有临时表的自增属性,所以不需要添加 set @sql ='alter table '+@tableName+' Add Constraint PK_'+@tableName+' Primary Key ('+@PKColumn+')' print @sql; exec(@sql);--执行SQL --7、删除临时表 set @sql = 'drop table '+@tempTableName+';' print @sql; exec(@sql); set @c=@c+1; end end END
个人观点:
上面这个存储过程用来初始化没有特殊应用的表倒是不错,有特殊应用就不行了。最好的办法还是删除标识列,然后再添加标识列,这样原有特殊应用就都保存下来了。有问题的是:每次添加的列都会在表的最后,若是没有特殊不要求倒是也无所谓,要是有特殊要求标识列必须放在第一列,这个位置问题就是个大难题了,MySql中有before和after用来调节这个,SQL Server图形化界面本身也有插入列的操作,SQL Server脚本的实现方法是:新建临时表用来存储原表结构及数据信息,然后删除原表,再将临时表更名为原表名称,最后为新表添加特殊应用,如触发器。