SQL Server管理員不易養成的好習慣(附小工具)
一、開發初衷
相信大家在平時寫SQL語句的時候,為了節省時間,都不太喜歡把小指放到Shift鍵上打出關鍵字的大寫形式,比如建數據庫,直接就create database...了,而不是CREATE DATABASE,反正SQL SERVER都可以執行語句,所以也就無所謂代碼的效果了。
的確如此,但是編程都有規范一說,在SQL的編寫中,將關鍵字大寫就是一個規范,所以如果有這樣的工具能夠方便象我也是這樣的懶人,批量將關鍵字替換成大寫那就好了,不過飯來張口、衣來伸手可不是什么好習慣,所以還是DIY吧。。。
二、開發思路
建立Winform應用程序,依據需求此工具需要實現三個方面:
1、打開對話框——選擇要處理的SQL文件路徑;
2、保存對話框——選擇處理完成后輸出文件的路徑;
3、核心功能——用正則表達式查找SQL文件中的關鍵字,如有匹配則將其轉換為大寫。
三、開發過程
俗話說:計劃趕不上變化。本來計劃一兩個小時就能夠搞定,但是還是足足折騰了一個下午,實在有些汗顏,下面就詳細敘述一下過程吧:
1、搜集SQL關鍵字
要說SQL關鍵字,除了大家常見的CRUD相關的語句,還有FUNCTION、CURSOR、PROCEDURE、系統內置VARIABLE、VIEW、SCHEMA等等等等,總之一大堆,而且貌似也超出關鍵字的范疇了,要想完全搞定這么多東西,俺實在只能說無能為力了,所以我只搜集了大家平時經常用到的一些關鍵字,在下面的代碼中會看到。
PS:當然如果園子里哪位能夠做出一個覆蓋所有SQL那樣強大的來,小弟一定前往拜讀。
2、SQL文件語句的遍歷
不像ORACLE里的SQL PLUS那樣難用的東西(主要是俺太菜了,經常出紕漏,很難一下就寫對SQL),在SQL SERVER中SQL語句可以上下鍵隨意更改內容或格式,而且語句也不用強制分號作為結尾,所以復雜的時候幾行甚至十幾行才是一個完整的SQL語句,所以一開始我就嘗試從頭到尾遍歷整個文件貌似有些不太現實,最后的方案是采用了按行劃分,以一行為一個數組進行處理,代碼如下:
- //先以行作為劃分,得到一個數組
- Regex rowReg = new Regex("\r\n");
- string[] strRow = rowReg.Split("轉換的SQL源文件內容");
3、現在依然不能急著處理strRow數組中的每一個元素,因為元素中有可能會出現" create database "這樣的情況,即關鍵字兩側有一個或多個空格字符,如果不進行統一處理,會給后面的替換帶來很大的麻煩,所以這里再用一個正則表達式,使空格通通變成一個,隨后再以空格作為分割符,這樣才算得到了我們真正需要進行匹配替換操作的數組:
- for (int i = 0; i < strRow.Length; i++)
- {
- strRow[i] = Regex.Replace(strRow[i], @"\s+", " ");
- string[] strRowDetail = strRow[i].Split(new char['\0']);
- }
4、下面循環遍歷strRowDetail數組中的每一項:
- for (int j = 0; j < strRowDetail.Length; j++)
- {
- if (regex.regRow.IsMatch(strRowDetail[j]))
- {
- Match match = regex.Match(strRowDetail[j]);
- ...
- }
- }
為什么暫時省略了后面的代碼呢,因為這樣寫考慮是不周全的,試想如果一個SQL語句如:
- create table student
- (
- cno varchar(50),
- ...
- )
這樣關鍵字一個是一個的話,那匹配起來自然沒有問題,但很多時候事情并沒有那么簡單,有些SQL語句包含了很多關鍵字。
最典型的就是日期類型的操作,比如:
- --求本月天數:select day(dateadd(mm,1,getdate())-day(getdate()));
這樣的一個SQL語句我們以空格劃分后,那么數組的第二個元素會是day(dateadd(mm,1,getdate())-day(getdate())),如果進行上述的Match匹配就只會將第一個day變為大寫,而其他則沒有得到處理。
進行了一定的測試后,我轉用了MatchCollection類,代碼如下(注:tbSource指的是顯示SQL代碼的文本框):
- for (int j = 0; j < strRowDetail.Length; j++)
- {
- //regex.regRow指的是尋找匹配關鍵字的正則表達式,在代碼下載中會看到
- //首先查看strRowDetail[j]是否能夠匹配
- if (regex.regRow.IsMatch(strRowDetail[j]))
- {
- //若能匹配則記錄其匹配的內容
- MatchCollection mc = regex.regRow.Matches(strRowDetail[j]);
- //遍歷匹配的集合
- for (int k = 0; k < mc.Count; k++)
- {
- //循環替換匹配的項
- strRowDetail[j] = strRowDetail[j].Replace(
- mc[k].Value, mc[k].Value.ToUpper());
- }
- //附加替換完成后的內容
- this.tbSource.Text += strRowDetail[j] + " ";
- }
- //不匹配則直接附加原來的內容
- else
- {
- this.tbSource.Text += strRowDetail[j] + " ";
- }
- }
- //因為最初是以行分割的,所以這里要附加\r\n,從而保持其原來的格式
- this.tbSource.Text += "\r\n";
5、最后用StreamWriter將得到的內容寫入文件,這里除了編碼問題貌似也沒啥好說的了:
- StreamWriter writer = new StreamWriter(this.tbExportPath.Text, false,
- Encoding.Default);
- writer.WriteLine(this.tbSource.Text);
- writer.Flush();
四、效率測試
細心的你在閱讀代碼的過程中可能已經發現我在大量的字符串處理操作時一直在使用普通的字符串"+="這樣的方法,其實這也是我為我的效率小測驗準備的,這下可以再切實的體會一下StringBuilder對效率的提升。
要測試那還是要請出我們的Stopwatch了,相信大家都會的了,下面的代碼直接無視:
- StreamWriter writer = new StreamWriter(this.tbExportPath.Text, false, Encoding.Default);
- writer.WriteLine(this.tbSource.Text);
- writer.Flush();
如果使用原來普通字符串連接的方法,足足等了我5347毫秒!
而如果使用StringBuilder對象作字符串操作,并且為提高for循環效率,避免每次重復計算數組長度,先將數組的長度存儲在變量中,優化代碼如下:
- int strRowDetailLength = strRowDetail.Length;
- for (int j = 0; j < strRowDetailLength; j++)
- {
- if (regex.regRow.IsMatch(strRowDetail[j]))
- {
- MatchCollection mc = regex.regRow.Matches(strRowDetail[j]);
- int mcCount = mc.Count;
- for (int k = 0; k < mcCount; k++)
- {
- strRowDetail[j] = strRowDetail[j]
- .Replace(mc[k].Value, mc[k].Value.ToUpper());
- }
- strBuilder.Append(strRowDetail[j] + " ");
- }
- else15 {
- strBuilder.Append(strRowDetail[j] + " ");
- }
- }
- strBuilder.Append("\r\n");
測試的結果是34毫秒,hoho,StringBuilder的威力果然很強大。。。
五、項目說明
1、介于正則表達式實在是礙眼,所以就沒有貼出來,說實話我自己都不忍心看了。。。
2、麻雀雖小也要五臟俱全嘛,這個小工具在界面上使用了錢李峰同學的 美化版Winform,沒經作者同意就亂打廣告,忘作者不要介意啊 ^_^
六、后續問題
1、希望大家在看完后能夠指出我在解決的思路上有沒有什么問題,有沒有什么簡單的方法,因為雖然實現了,但個人感覺方法上有點齪。。。
2、期待哪位能夠開發出更完善更優雅的SQL關鍵字替換工具。。。
3、如有使用問題請及時留言。。。
七、項目下載
http://files.cnblogs.com/RockyMyx/Solution.rar
原文標題:DIY小工具開發---SQL關鍵字批量轉換
鏈接:http://www.cnblogs.com/RockyMyx/archive/2010/04/21/Convert-Sql-Keyword.html
【編輯推薦】
- SQL Server使用索引實現數據訪問優化
- SQL Server數據庫優化經驗總結
- 如何使用SQLServer數據庫查詢累計值
- 淺析Oracle和SqlServer存儲過程的調試、出錯處理
- 幾段SQLServer語句和存儲過程
- 50種方法優化SQL Server數據庫查詢