通過SqlClr制作Sql自動化批量執行腳本
在與同事一起做項目時,看到同事用sqlclr做批量執行腳本,感覺挺新奇的就上網搜集資料自己模仿跟做了個案例,
感覺挺不錯的,現在想和大家分享一下,可能存在些錯誤的地方,大家就做個小參考吧....
1.我們在做數據遷移或是數據庫結構修改時,通常會寫一些腳本文件之后逐個運行。但是如果有數十或數百個腳本文件,
那么就可以通過SqlClr制作Sql自動化執
2.比如現在ImportDataScript文件夾內有些腳本文件:

3.我們想讓這9個腳本文件自動的依次執行,並且輸出最終的執行情況並且生成一個日志寫到ImportDataScript文件夾內的
LogFile文件夾內的Logg.txt中。
4.我們預期結果:
執行結果:(執行每個文件的開始時間、結束時間、執行總時間)

輸出日志:(名稱、執行時間)

5.思路:首先我們通過sqlclr創建一個表值函數來獲取腳本文件的本地路徑的集合,然后遍歷這個集合並通過sql exec xp_cmdshell命令
來執行指定路徑下的腳本文件,並通過sqlclr創建一個記錄日志的的標量函數來逐條記錄執行日志。
5.1創建sqlclr項目
5.1.1創建實體類:
1 public class FilePathModel 2 { 3 public FilePathModel() 4 { 5 6 } 7 public FilePathModel(string fileName, string filePath) 8 { 9 this.FileName = fileName; 10 this.FilePath = FilePath; 11 } 12 private string _FileName; 13 14 public string FileName 15 { 16 get { return _FileName; } 17 set { _FileName = value; } 18 } 19 private string _FilePath; 20 21 public string FilePath 22 { 23 get { return _FilePath; } 24 set { _FilePath = value; } 25 } 26 }
5.1.2創建表值函數:
1 public partial class UserDefinedFunctions 2 { 3 [Microsoft.SqlServer.Server.SqlFunction 4 (DataAccess = DataAccessKind.Read, 5 TableDefinition = "FileName nvarchar(100),FilePath nvarchar(100)", 6 FillRowMethodName = "FillTable", IsDeterministic = true)] 7 public static IEnumerable GetScriptFilePath(SqlString fileRootPath) 8 { 9 10 IList<FilePathModel> list = new List<FilePathModel>(); 11 if (Directory.Exists(fileRootPath.Value)) 12 { 13 DirectoryInfo di = new DirectoryInfo(fileRootPath.Value); 14 foreach (FileInfo fi in di.GetFiles()) 15 { 16 list.Add(new FilePathModel { FileName=fi.Name,FilePath=fi.FullName}); 17 } 18 } 19 return list; 20 } 21 public static void FillTable(object obj, out SqlString fileName, out SqlString filePath) 22 { 23 fileName = ""; 24 filePath = ""; 25 FilePathModel fpModel = obj as FilePathModel; 26 if (fpModel != null) 27 { 28 fileName = fpModel.FileName; 29 filePath = fpModel.FilePath; 30 } 31 } 32 };
5.1.3創建寫入日志的標量函數:
1 public partial class UserDefinedFunctions 2 { 3 [Microsoft.SqlServer.Server.SqlFunction] 4 public static SqlString ImportLog(SqlString pathStr, SqlString strName, SqlString Time) 5 { 6 // 在此處放置代碼 7 8 if (Directory.Exists(pathStr.Value)) 9 { 10 string filePathNew = Path.Combine(pathStr.Value, "Logg.txt"); 11 FileInfo fi = new FileInfo(filePathNew); 12 if (!File.Exists(filePathNew)) 13 { 14 fi.Create(); 15 } 16 using (StreamWriter sw = fi.AppendText()) 17 { 18 sw.WriteLine(strName.Value + "||" + Time.Value); 19 } 20 return new SqlString("完成"); 21 } 22 else 23 { 24 return new SqlString("失敗"); 25 } 26 } 27 };
5.2寫執行腳本:
--開啟sqlclr sp_configure 'show advanced options', 1; GO RECONFIGURE; GO sp_configure 'clr enabled', 1; GO RECONFIGURE; GO --使用.net framework ALTER database Test SET TRUSTWORTHY ON ALTER assembly DataImprot with permission_set = external_access go -- --開啟【xp_cmdshell】權限 exec sp_configure 'xp_cmdshell', @configvalue = 1 reconfigure with override go --開啟【opendatasource】權限 exec sp_configure @configname = 'Ad Hoc Distributed Queries', @configvalue = 1 reconfigure with override --測試 DECLARE @fileRootPath nvarchar(100) DECLARE @logFilePath nvarchar(100) DECLARE @serverName nvarchar(100) DECLARE @dataBaseName nvarchar(100) DECLARE @loginName nvarchar(100) DECLARE @passWord nvarchar(100) --服務器名 SET @ServerName='PACTERA_GZF-PC' --數據庫名 SET @dataBaseName='Test' --用戶名 SET @loginName='sa' --密碼 SET @passWord='sa' --腳本根路徑 SET @fileRootPath='D:\ImportDataScript' --日志文件路徑.txt SET @logFilePath='D:\ImportDataScript\LogFile' DECLARE @FilePathTable table ( [FileName] nvarchar(100), FilePath nvarchar(100) ) create table #CurFilePathTable ( Id int identity(1,1) primary key, [FileName] nvarchar(100), FilePath nvarchar(100), BeginTime datetime, EndTime datetime, ExcuteDate float ) insert into @FilePathTable select [FileName], [FilePath] from dbo.GetScriptFilePath(@fileRootPath) declare @FileName nvarchar(100) declare @FilePath nvarchar(100) declare @BeginTime datetime declare @EndTime datetime declare @sqlStr nvarchar(200) declare cur_FilePath cursor for select [FileName], [FilePath] from @FilePathTable open cur_FilePath fetch next from cur_FilePath into @FileName, @FilePath while (@@fetch_status = 0) begin set @BeginTime = getdate() set @sqlStr = 'exec xp_cmdshell ''osql -S '+@ServerName+' -U '+@loginName+' -P '+@passWord+' -i ' + @FilePath + '''' exec master..sp_executesql @sqlStr set @EndTime = getdate() print @FileName insert into #CurFilePathTable ([FileName], FilePath, BeginTime,EndTime,ExcuteDate) values (@FileName, @FilePath, @BeginTime,@EndTime,datediff(second, @BeginTime, @EndTime)) select dbo.ImportLog(@logFilePath,@FileName,convert(varchar(10),datediff(second, @BeginTime, @EndTime))) fetch next from cur_FilePath into @FileName, @FilePath end close cur_FilePath deallocate cur_FilePath select * FROM #CurFilePathTable DROP TABLE #CurFilePathTable
5.3總結:
感覺SqlClr就像是插件模型,通過嵌入.dll來實現更多的功能。
利用SqlClr我們可以做許事情比如我們也可以在sqlserver端實現數據的加密解密等。
