合并SQL腳本文件的方法分享
--------------------------------------------------------------------------------
在平時(shí)的工作中,我會(huì)經(jīng)常的碰到這樣需要合并SQL腳本的問題。如,有很多的SQL腳本文件,需要按照一定的先后順序,再生成一個(gè)合并SQL腳本文件,然后再發(fā)布到用戶SQL Server服務(wù)器上。
合并SQL腳本文件,最直接的方法就是新建1個(gè)空白的SQL腳本文件,再把需要合并的SQL腳本文件內(nèi)容復(fù)制到新建的SQL文件中。當(dāng)初,我合并腳本的操作方法與剛說(shuō)的有類似。我在Microsoft SQL Server Management Studio(MSSMS)新建一個(gè)查詢,再把要合并的SQL腳本文件,一個(gè)一個(gè)的打開,并復(fù)制內(nèi)容到新建查詢中,然后生成合并腳本文件。
上面的方法,對(duì)于幾個(gè)SQL腳本文件合并來(lái)說(shuō),似乎沒什么問題。但是,當(dāng)我們要合并的腳本很多,一文件一個(gè)文件的內(nèi)容復(fù)制,是比較繁瑣的事情,要是能有1個(gè)簡(jiǎn)單合并腳本工具就最好不過(guò)了。下面介紹我寫的兩個(gè)合并SQL腳本文件的存儲(chǔ)過(guò)程.
第1個(gè)存儲(chǔ)過(guò)程,只要調(diào)用sp_OACreate實(shí)現(xiàn)合并SQL腳本文件。
use master
Go
if object_id('sp_ScriptMerge') Is Not Null
Drop proc sp_ScriptMerge
Go
Create Proc sp_ScriptMerge
(
@Path nvarchar(1024),
@FilesList nvarchar(max)= null,
@NewFileName nvarchar(1024)=null
)
As
/*合并SQL腳本文件(SQL)V1.0 Andy 2011-9-1*/
Declare
@ScriptNr nchar(21),
@subdirectoryStr nvarchar(512),
@Dir nvarchar(1024),
@ScriptCount int
Declare @subdirectoryTB Table (subdirectory nvarchar(512),depth smallint,[file] smallint)
Declare @tmp table(row smallint identity primary key,fileName nvarchar(512))
Set Nocount on
if right(@Path,1)<>'\' Set @Path=@Path+'\'
If Isnull(@NewFileName,'')='' Set @NewFileName=N'合并腳本-'+Convert(nvarchar(8),getdate(),112)
if lower(right(@NewFileName,4))<>'.sql' Set @NewFileName=@NewFileName+'.sql'
Set @NewFileName=@Path+@NewFileName
Set @ScriptNr='Nr: '+Replace(replace(Replace(replace(convert(nvarchar(23),getdate(),121),'-',''),':',''),' ',''),'.','')
Set @ScriptCount=0
/*讀取腳本文件內(nèi)容*/
if @FilesList >''
Begin
Set @FilesList='Select N'''+replace(@FilesList,',',''' Union All Select N''')+''''
Insert into @tmp([fileName]) Exec(@FilesList)
End
if object_id('Tempdb..#') Is Not Null Drop Table #
Create table #(row int identity(1,1) Primary key,text nvarchar(max))
Insert into @subdirectoryTB Exec xp_dirtree @Path,1,1
Declare cur_file cursor for
Select a.subdirectory
From @subdirectoryTB As a
left Join @tmp As b ON b.fileName=a.subdirectory
Where a.[file]=1 And a.subdirectory like '%.sql'
And (b.fileName=a.subdirectory Or Not Exists(Select 1 From @tmp))
Order By isnull(b.row,0),a.subdirectory
Open cur_file
fetch next From cur_file into @subdirectoryStr
While @@FETCH_STATUS = 0
Begin
Set @ScriptCount=@ScriptCount+1
Insert into #(text) Select +Char(13)+Char(10)+ N'Go'+Char(13)+Char(10)+ N'/* '+@ScriptNr+' ('+rtrim(@ScriptCount)+'): '+@subdirectoryStr+' */'+Char(13)+Char(10)+ N'Go'+Char(13)+Char(10)
Set @Dir='Type '+@Path+'"'+@subdirectoryStr+'"'
Insert into #(text)
Exec sys.xp_cmdshell @Dir
fetch next From cur_file into @subdirectoryStr
End
Close cur_file
Deallocate cur_file
if @ScriptCount >0 Insert into #(text) Select +Char(13)+Char(10)+ N'Go'+Char(13)+Char(10)+ N'/* '+@ScriptNr+' 合并完成(合計(jì) '+rtrim(@ScriptCount)+' 各腳本文件). */'+Char(13)+Char(10)+ N'Go'+Char(13)+Char(10)
/*寫入合并腳本文件*/
if @ScriptCount>0
Begin
Declare @object int,
@FileID int,
@hr int,
@src varchar(255),
@desc varchar(255),
@row int,
@text nvarchar(max)
Exec @hr=sp_OACreate 'Scripting.FileSystemObject',@object output
If @hr <> 0 Goto File_ErrorHandler
Exec @hr = sp_OAMethod @object,'CreateTextFile',@FileID OUTPUT, @NewFileName
If @hr <> 0 Goto File_ErrorHandler
Set @row=1
While Exists(Select 1 From # Where row=@row)
Begin
Set @text=(Select text From # Where row=@row)
Exec @hr = sp_OAMethod @FileID, 'WriteLine', NULL, @text
Set @row=@row +1
End
Goto File_Done
File_ErrorHandler:
Print N'*********** 讀寫文件的時(shí)候發(fā)生錯(cuò)誤 ***********'
Exec @hr=sp_OAGetErrorInfo @object, @src OUT, @desc OUT
Select convert(varbinary(4),@hr) As hr, @src As Source, @desc As Description
File_Done:
Exec @hr = sp_OADestroy @FileID
Exec @hr = sp_OADestroy @object
Print N'*********** 合并腳本完成 ***********'
Print N'合并后腳本文件: '+@NewFileName
End
Go
調(diào)用上面存儲(chǔ)過(guò)程前,需要確認(rèn)啟用 OLE Automation Procedures和xp_cmdshell 選項(xiàng):
Exec sys.sp_configure @configname = 'show advanced options',@configvalue = 1
reconfigure
go
Exec sys.sp_configure @configname = 'xp_cmdshell',@configvalue = 1
reconfigure
Go
Exec sys.sp_configure @configname = 'Ole Automation Procedures',@configvalue = 1
reconfigure
Go
測(cè)試:
use master
GO
Exec master.dbo.sp_ScriptMerge
@Path = 'C:\Users\Administrator\Desktop\temp', -- nvarchar(1024)
@FilesList = '', -- nvarchar(max)
@NewFileName = '合并腳本20110905.sql' -- nvarchar(1024)
*********** 合并腳本完成 ***********合并后腳本文件: C:\Users\Administrator\Desktop\temp\合并腳本20110905.sql第2個(gè)是CLR存儲(chǔ)過(guò)程,使用C#代碼實(shí)現(xiàn)合并SQL腳本文件。
--------------------------------------------------------------------------------
C#代碼:
using System;
using System.Data;
using System.Data.SqlClient;
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.IO;
using System.Text;
public class clScriptMerge
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void SQLScriptMerge(string Path, string FilesList, string NewFileName)
{
try
{
string[] strFiles ;
FileInfo[] myFileInfo = (new DirectoryInfo(Path)).GetFiles("*.sql");
string strScriptNr = @"Nr" + DateTime.Now.ToString("yyyyMMddHHmmssFFF");
int intCount=0;
if (NewFileName == null || NewFileName=="")
{
NewFileName = "合并腳本" + DateTime.Now.ToString("yyyyMMdd") + ".sql";
}
SqlContext.Pipe.Send(NewFileName.ToString()); //打印已合并的SQL文件名
// 1.獲得SQL腳本列表
if (FilesList != "")
{
strFiles = FilesList.Split(','); //篩分SQL腳本文件名列表,以","分隔
}
else
{
strFiles = new string[myFileInfo.Length];
for (int i = 0; i < myFileInfo.Length; i++)
{
strFiles[i] = myFileInfo[i].Name;
}
}
// 2.合并腳本
SqlContext.Pipe.Send("【SQL腳本文件列表】:\n--------------------------------------------");
StreamWriter SW = new StreamWriter(Path + @"\" + NewFileName, true, Encoding.Unicode); //使用Unicode編碼
SW.WriteLine(@"Go\n/*============ " + strScriptNr + "====Start===================================*/\nGo\n"); //記錄生成的合并腳本編號(hào)&合并動(dòng)作的開始位置
foreach (string strFile in strFiles)
{
if (strFile !=NewFileName)
{
intCount += 1;
SW.WriteLine(@"/* " + strScriptNr +@" ("+intCount+@"): " + strFile + "*/\nGo\n"); //記錄合并哪一個(gè)腳本文件
using (StreamReader SR = new StreamReader(Path + @"\" + strFile, Encoding.Default))
{
string line;
while ((line = SR.ReadLine()) != null)
{
SW.WriteLine(line);
}
SR.Close();
}
SqlContext.Pipe.Send(strFile.ToString()); //打印已合并的SQL文件名
}
}
SW.WriteLine(@"/*============ " + strScriptNr + "====End (一共 " + intCount + " 個(gè)文件)===================================*/\nGo\n"); //記錄生成的合并腳本文件個(gè)數(shù)&合并動(dòng)作的結(jié)束位置
SW.Close();
SqlContext.Pipe.Send("\n\n【合成后文件】:\n--------------------------------------------\n" + NewFileName);
}
catch (System.Exception e)
{
SqlContext.Pipe.Send("\n在方法SQLScriptMerge內(nèi)發(fā)生錯(cuò)誤: \n\n" + e.ToString());
}
}
}
存儲(chǔ)過(guò)程代碼:
Use master
GO
--啟動(dòng)CLR
Exec sp_configure 'clr enable',1
Go
Reconfigure
GO
--先設(shè)置數(shù)據(jù)庫(kù)選項(xiàng)
Alter Database Master Set TRUSTWORTHY On
Go
--存儲(chǔ)過(guò)程
If object_id('sp_ScriptMerge2') Is Not Null
Drop Proc sp_ScriptMerge2
Go
If Exists(Select 1 From sys.assemblies Where Name=N'ScriptMerge')
Drop Assembly ScriptMerge
Go
Create Assembly ScriptMerge
From 'E:\Test\Objects\ISTest\ScriptMerge\ScriptMerge\bin\Debug\ScriptMerge.dll'
create proc sp_ScriptMerge2
(
@Path nvarchar(1024),
@FilesList nvarchar(max),
@NewFileName nvarchar(1024)
)
As External Name ScriptMerge.clScriptMerge.SQLScriptMerge
Go
以上的CLR存儲(chǔ)過(guò)程代碼是在SQL Server 2005 & Microsoft Visual Studio 2005下運(yùn)行通過(guò)。
相關(guān)文章
sqlserver合并DataTable并排除重復(fù)數(shù)據(jù)的通用方法分享
網(wǎng)上合并DataTable通用方法的文章很多,結(jié)合項(xiàng)目開發(fā)中的常用需求,并借鑒網(wǎng)上的做法,寫了一個(gè)合并DataTable的通用方法,主要功能是合并兩個(gè)DataTable(結(jié)構(gòu)可以不同,如字段不完全一致),并可以根據(jù)某一列值進(jìn)行排重處理2011-12-12sqlserver substring函數(shù)使用方法小結(jié)
在操作sqlserver時(shí)候用到了substring函數(shù),特整理一些實(shí)例,需要的朋友可以參考下。2009-12-12SQL SERVER 2012新增函數(shù)之邏輯函數(shù)IIF
這篇文章主要介紹了關(guān)于SQL SERVER 2012新增函數(shù)之邏輯函數(shù)IIF的相關(guān)資料,網(wǎng)上關(guān)于邏輯函數(shù)IIF的資料比較少,本文中的介紹的還是相對(duì)詳細(xì)的,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-03-03查找sqlserver查詢死鎖源頭的方法 sqlserver死鎖監(jiān)控
如何查出SQL Server死鎖的原因,下面就教您SQL Server死鎖監(jiān)控的語(yǔ)句寫法,下面的SQL語(yǔ)句運(yùn)行之后,便可以查找出SQLServer死鎖和阻塞的源頭2014-01-01SQLServer只賦予創(chuàng)建表權(quán)限的全過(guò)程
在SQL Server中進(jìn)行各種操作是非常常見的操作,下面這篇文章主要給大家介紹了關(guān)于SQLServer只賦予創(chuàng)建表權(quán)限的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04SQL Server約束增強(qiáng)的兩點(diǎn)建議
我們可以在CHECK的約束條件中加入任何邏輯表達(dá)式,而目前所有外鍵只能用來(lái)驗(yàn)證一個(gè)或多個(gè)列的值是否相等。2009-05-05sql server通過(guò)腳本進(jìn)行數(shù)據(jù)庫(kù)壓縮全備份的方法【推薦】
這篇文章主要介紹了sql server通過(guò)腳本進(jìn)行數(shù)據(jù)庫(kù)壓縮全備份的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-06-06數(shù)據(jù)庫(kù)觸發(fā)器DB2和SqlServer有哪些區(qū)別
大部分?jǐn)?shù)據(jù)庫(kù)語(yǔ)句的基本語(yǔ)法是相同的,但具體到的每一種數(shù)據(jù)庫(kù),又有些不一樣,例如觸發(fā)器,DB2和SQL Server兩種很大的不同。對(duì)數(shù)據(jù)庫(kù)觸發(fā)器DB2和SqlServer有哪些區(qū)別感興趣的朋友一起看看本文吧2015-11-11SQLServer行列互轉(zhuǎn)實(shí)現(xiàn)思路(聚合函數(shù))
這篇文章主要為大家詳細(xì)介紹了SQLServer行列互轉(zhuǎn)實(shí)現(xiàn)思路,使用聚合函數(shù)pivot/unpivot實(shí)現(xiàn)行列互轉(zhuǎn),感興趣的小伙伴們可以參考一下2016-03-03