您好,欢迎访问一九零五行业门户网

使用SQLCMD在SQLServer执行多个脚本

概述: 作为 dba ,经常要用开发人员提供的 sql 脚本来更新正式数据库,但是一个比较合理的开发流程,当提交脚本给 dba 执行的时候,可能已经有几百个 sql 文件,并且有执行顺序,如我现在工作的公司,十几个客户,每个客户一个库,但是数据库结构、存储过程
概述: 
       作为dba,经常要用开发人员提供的sql脚本来更新正式数据库,但是一个比较合理的开发流程,当提交脚本给dba执行的时候,可能已经有几百个sql文件,并且有执行顺序,如我现在工作的公司,十几个客户,每个客户一个库,但是数据库结构、存储过程、视图等都是一模一样,每次执行脚本(以下称为升级),如果有一百个脚本,那么就要按顺序执行过千次,这种工作量可不是一个人能承受得了的。
解决方法: 
应对这种情况有以下几种方法: 
1、  购买第三方软件(一般估计很少人买) 
2、  自己编程一个小软件来执行,但是这个逻辑性要求比较高,而且编程的能力要有一定层次,这个我暂时没有。 
3、  使用本文介绍的方法,至于是啥,接着看: 
使用sqlcmd在sqlserver上执行多个脚本: 
             sqlcmd:使用 sqlcmd 实用工具,可以在命令提示符处、在 sqlcmd 模式下的“查询编辑器”中、在 windows脚本文件中或者在 sql server代理作业的操作系统 (cmd.exe)作业步骤中输入 transact-sql语句、系统过程和脚本文件。 此实用工具使用 odbc执行 transact-sql批处理。(来源于msdn)详细语法可以到网上查找,这里就不贴出来。
sqlcmd有一个很重要的命令::r,记住,sqlcmd是大小写敏感的。当:r发现正在运行sql脚本,它会告诉sqlcmd把这个文件所引用的文件一并放入调用脚本中。这将告诉你,停止目前的单个查询。并重新调整查询,把应该关联的查询放到适当的位置。另外,使用:r命令在一个批处理中执行多个脚本,使得你可以定义一个单独的变量集,用于包含所有脚本,但是不包含go终结符。从2005以后引入sqlcmd,可以用于将来替代osql工具。如果你不熟悉sqlcmd,可以认为它是一个能从操作系统执行t-sql命令和脚本的命令行工具。
下面例子中,创建5个作用在testdb数据库上有关联的sql文件。第一个脚本叫做create_db.sql,用于创建一个叫做testdb的数据库。这个脚本包含了4个其他的脚本(使用了:r命令。),用于生成其他表、表插入、索引创建和存储过程的创建。一个.bat文件用于创建用来执行sqlcmd命令。
第一步:先创建一个在c盘下的文件夹:c:\scripts。然后把脚本存放到这个文件夹中:脚本1:create_db.sql
/* script: create_db.sql *//* 创建testdb数据库 */-- this is the main caller for each scriptset nocount ongoprint '开始创建testdb数据库'if exists (select 1 from sys.databases where name = 'testdb')drop database testdbgocreate database testdbgo:on error exit:r c:\scripts\create_tables.sql:r c:\scripts\table_inserts.sql:r c:\scripts\create_indexes.sql:r c:\scripts\create_procedures.sqlprint '创建完毕'go
脚本2:create_indexes.sql
/* 创建索引 */print '开始创建索引'gouse testdbgoif not exists ( select 1 from sys.indexes where name = 'ix_employee_lastname' ) create index ix_employee_lastname on dbo.employee(lastname, firstname)goif not exists ( select 1 from sys.indexes where name = 'ix_timecard_employeeid' ) create index ix_timecard_employeeid on dbo.timecard(employeeid)go
脚本3:create_procedures.sql
/* 创建存储过程 */print '正在创建存储过程'gouse testdbgoif object_id('get_employee_timecards') is not null drop procedure dbo.get_employee_timecardsgocreate procedure dbo.get_employee_timecards @employeeid intas set nocount on select * from dbo.employee e join dbo.timecard t on e.employeeid = t.employeeid where e.employeeid = @employeeid order by dateworkedgo
脚本4:create_tables.sql
/* 创建数据表 */print '正在创建数据表 'gouse testdbgoif object_id('employee') is not null drop table dbo.employeegocreate table dbo.employee ( employeeid int identity(1, 1) not null primary key , firstname varchar(50) , lastname varchar(50) )goif object_id('timecard') is not null drop table dbo.timecardgocreate table dbo.timecard ( timecardid int identity(1, 1) not null primary key , employeeid int not null , hoursworked tinyint not null , hourlyrate money not null , dateworked datetime not null )godeclare @total_tables intset @total_tables = 2
脚本5:table_inserts.sql
/* 插入表数据 */print 'total tables created = ' + cast(@total_tables as varchar)goprint '正在插入数据到表 employee'gouse testdbgoinsert into dbo.employee ( firstname, lastname ) select 'john' , 'doe'goinsert into dbo.employee ( firstname, lastname ) select 'jane' , 'doe'goinsert into dbo.employee ( firstname, lastname ) select 'jeff' , 'doe'go
第二步:在c盘根目录下创建一个bat文件create_db.bat,用于执行sqlcmd: 
sqlcmd -e -dmaster -ic:\scripts\create_db.sqlpause
第三步:在c盘下直接执行bat文件: 
双击文件可以看到:
在执行前,是没有testdb:
执行中:
执行后,该创建的东西都创建出来了:
由于执行的顺序已经在脚本1中定义好,所以直接执行即可,并且执行成功。
总结:             根据个人经验,还是开发一个批量执行工具会比较好,这个方法在少量脚本的时候可以选用。
其它类似信息

推荐信息