SQL Server游標生成工具
- Declare @Age int
- Declare @Name varchar(20)
- Declare Cur Cursor For Select Age,Name From T_User
- Open Cur
- Fetch next From Cur Into @Age,@Name
- While @@fetch_status=0
- Begin
- Update T_User Set [Name]=@Name,Age=@Age
- Fetch Next From Cur Into @Age,@Name
- End
- Close Cur
- Deallocate Cur
在實際應(yīng)用時,經(jīng)常需要找到這個模板,然后再根據(jù)實際的表結(jié)果,重寫一遍。經(jīng)常遇到以下二個問題
1 上面的例子腳本不知道放在哪里了,或是有很多例子腳本,不方便很快找出來
2 重寫游標的例子,經(jīng)常重復(fù),又沒有技術(shù)難度可言。比如讀取工作單生產(chǎn)計劃,讀取用戶。
經(jīng)過思考,于是寫個游標生成工具,把上面的模板代碼,應(yīng)用到代碼生成器中。
注意上圖中的Script Cursor,這是用來生成游標模板的。選擇一個數(shù)據(jù)庫,樹左邊選擇表名,勾選字段值,點擊執(zhí)行
- DECLARE @UserID NVARCHAR(10)
- DECLARE @UserName NVARCHAR(50)
- DECLARE Cur CURSOR FOR SELECT [UserID],[UserName] FROM [USER]
- OPEN Cur
- FETCH next FROM Cur INTO @UserID,@UserName
- WHILE @@fetch_status=0
- BEGIN
- FETCH next FROM Cur INTO @UserID,@UserName
- END
- CLOSE Cur
- DEALLOCATE Cur
源代碼不到50行,全文如下
- List<ColumnInfo> fieldlist = this.GetFieldlist();
- StringBuilder builder=new StringBuilder();
- string typeName = string.Empty;
- foreach (ColumnInfo columnInfo in fieldlist)
- {
- switch (columnInfo.TypeName)
- {
- case "datetime":
- case "int":
- case "image":
- case "bit":
- typeName = columnInfo.TypeName;
- break;
- case "nvarchar":
- case "nchar":
- case "varchar":
- case "char":
- typeName =string.Format("{0}({1})", columnInfo.TypeName,columnInfo.Length);
- break;
- }
- builder.AppendLine(string.Format("Declare @{0} {1}", columnInfo.ColumnName, typeName));
- }
- var columns = string.Join(",", (from column in fieldlist
- select "["+column.ColumnName+"]").ToArray());
- string fetchNex= string.Join(",", (from column in fieldlist
- select "@"+column.ColumnName).ToArray());
- string update= string.Join(",", (from column in fieldlist
- select "@"+column.ColumnName+"=["+ column.ColumnName+"]").ToArray());
- builder.AppendLine(string.Format("Declare Cur Cursor For Select {0} From [{1}] ", columns, this.tablename));
- builder.AppendLine("Open Cur");
- builder.AppendLine(string.Format("Fetch next From Cur Into {0} ", fetchNex));
- builder.AppendLine("While @@fetch_status=0 ");
- builder.AppendLine("Begin");
- //builder.AppendLine(string.Format(" Update [{0}] Set {1} ",this.tablename,update));
- builder.AppendLine(string.Format(" Fetch next From Cur Into {0} ", fetchNex));
- builder.AppendLine("End ");
- builder.AppendLine("Close Cur ");
- builder.AppendLine("Deallocate Cur");
有以下幾點需要注意
1 生成的腳本中,字段名稱,表名稱,均要加上方括號,以避免名稱重突。
2 最后生成的SQL源代碼,還需要應(yīng)用下面的方法,將SQL關(guān)鍵字大寫。
將SQL查詢語句的關(guān)鍵字大寫的方法來自CSDN下載區(qū),全文如下
- private static Regex RegexSQLCapitalize = new Regex("\\badd\\b|\\baggregate\\b|\\baction\\b|\\balter\\b|\\bas\\b|\\basc\\b|\\basymmetric\\b|\\bauthorization\\b|\\bbegin\\b|\\bbinary\\b|\\bbit\\b|\\bby\\b|\\bcascade\\b|\\bcase\\b|\\bcatalog\\b|\\bcharacter\\b|\\bchar\\b|\\bcheck\\b|\\bcheckpoint\\b|\\bclose\\b|\\bclustered\\b|\\bconstraint\\b|\\bcollate\\b|\\bcolumn\\b|\\bcommit\\b|\\bcontains\\b|\\bcontinue\\b|\\bcreate\\b|\\bcross\\b|\\bcursor\\b|\\bdatabase\\b|\\bdeallocate\\b|\\bdesc\\b|\\bdecimal\\b|\\bdeclare\\b|\\bdefault\\b|\\bdelete\\b|\\bdesc\\b|\\bdistinct\\b|\\bdouble\\b|\\bdrop\\b|\\belse\\b|\\bend\\b|\\bescape\\b|\\bexcept\\b|\\bexec\\b|\\bexecute\\b|\\bexternal\\b|\\bfetch\\b|\\bfloat\\b|\\bforeign\\b|\\bfor\\b|\\bfrom\\b|\\bfunction\\b|\\bget\\b|\\bgroup\\b|\\bgoto\\b|\\bgrant\\b|\\bhaving\\b|\\bidentity\\b|\\binto\\b|\\bindex\\b|\\binsert\\b|\\binstead\\b|\\bint\\b|\\bkey\\b|\\bname\\b|\\bof\\b|\\bon\\b|\\bopen\\b|\\boption\\b|\\border\\b|\\boutput\\b|\\bprimary\\b|\\breturn\\b|\\brollback\\b|\\bschema\\b|\\bselect\\b|\\bsize\\b|\\bsymmetric\\b|\\bset\\b|\\bserver\\b|(\\btable\\b)|\\bthen\\b|\\btop\\b|\\btime\\b|\\btimestamp\\b|\\bto\\b|\\btrigger\\b|\\bprocedure\\b|\\btype\\b|\\bunion\\b|\\bunique\\b|\\bupdate\\b|\\buse\\b|\\bvalues\\b|\\bvalue\\b|\\bvarchar\\b|\\bview\\b|\\bwhen\\b|\\bwhile\\b|\\bwhere\\b|\\bwith\\b|\\bnvarchar\\b|\\bnchar\\b|\\bdatetime\\b|\\bfloat\\b|\\bdate\\b|\\bdatediff\\b|\\bdateadd\\b|\\bdatename\\b|\\bdatepart\\b|getdate|\\breferences\\b|\\babs\\b|\\bavg\\b|\\bcast\\b|\\bconvert\\b|\\bcount\\b|\\bday\\b|\\bisnull\\b|\\blen\\b|\\bmax\\b|\\bmin\\b|\\bmonth\\b|\\byear\\b|\\breplace\\b|\\bsubstring\\b|\\bsum\\b|\\bupper\\b|\\buser\\b|\\ball\\b|\\bany\\b|\\band\\b|\\bbetween\\b|\\bexists\\b|\\bin\\b|\\binner\\b|\\bis\\b|\\bjoin\\b|\\bleft\\b|\\blike\\b|\\bnot\\b|\\bnull\\b|\\bor\\b|\\bright\\b|\\btry\\b|\\bcatch\\b", RegexOptions.IgnoreCase);
- public static string CapitalizeSQLClause(string source)
- {
- //先按行劃分
- Regex rowReg = new Regex("\r\n");
- string[] strRows = rowReg.Split(source);
- StringBuilder strBuilder = new StringBuilder();
- int rowsCount = strRows.Length;
- for (int i = 0; i < rowsCount; i++)
- {
- //去掉一行中的一個或多個空白
- //strRows[i] = Regex.Replace(strRows[i], @"\s+", " ");
- //按空格劃分
- string[] strWords = strRows[i].Split(new char['\0']);
- int wordsCount = strWords.Length;
- for (int j = 0; j < wordsCount; j++)
- {
- strBuilder.Append(" ");
- if (RegexSQLCapitalize.IsMatch(strWords[j]))
- {
- MatchCollection mc = RegexSQLCapitalize.Matches(strWords[j]);
- int mcmcCount = mc.Count;
- for (int k = 0; k < mcCount; k++)
- {
- strWords[j] = strWords[j].Replace(mc[k].Value, mc[k].Value.ToUpper());
- }
- strBuilder.Append(strWords[j]);
- }
- else
- {
- strBuilder.Append(strWords[j]);
- }
- strBuilder.Append(" ");
- }
- strBuilder.Append("\r\n");
- }
- return strBuilder.ToString().Replace("\r\n\r\n", "\r\n");
- }
正則表達式替換字符串中的關(guān)鍵字,這個方法沒有任何依賴,可拷貝到您的項目或類庫中,為SQL 腳本增加關(guān)鍵字大寫功能。
3 SQL 腳本格式化功能 如果能把生成的SQL腳本格式化一下,生成美觀的SQL腳本,增加可讀性。SQL Pretty Printer可以做到,但是沒有找到API可以調(diào)用這個功能。
4 多表關(guān)聯(lián)的游標模板沒有做到。應(yīng)該嘗試從多個關(guān)聯(lián)表中生成游標。不過表與表之間的關(guān)系難以自動生成,比如像下面的母子表游標詢語句
- Declare Cur Cursor For Select r.Description,r.WorkCenter FROM JobOrder j, JobOrderRouting r
- WHERE j.JobNo=r.JobNo
- Open Cur
游標要從2個關(guān)聯(lián)的表中讀取數(shù)據(jù),如果2個表之間有外鍵關(guān)聯(lián),可以生成2個表的外鍵關(guān)聯(lián)字段的關(guān)系,也就是上面的SQL游標可以自動生成,但是有的2個表之間沒有外鍵關(guān)聯(lián)的,還是要手工指定,相當于是個半成品的游標生成器,于是只好把這個功能點拿掉,只做最簡單的一種情況,生成一個表的若干個字段的游標查詢,沒有設(shè)計多表查詢的游標。
原文鏈接:http://www.cnblogs.com/JamesLi2015/archive/2013/05/20/3088024.html
【編輯推薦】