设为首页 收藏本站
查看: 961|回复: 0

[经验分享] SQL Server 游标生成工具 技术原理和源代码分享

[复制链接]

尚未签到

发表于 2015-6-28 15:44:45 | 显示全部楼层 |阅读模式
  经常做ERP报表,涉及存储过程中读取数据,多个表之间关联的数据读取,用到游标。经典的读取用户表的游标例子
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
  在实际应用时,经常需要找到这个模板,然后再根据实际的表结果,重写一遍。经常遇到以下二个问题
  1  上面的例子脚本不知道放在哪里了,或是有很多例子脚本,不方便很快找出来
  2  重写游标的例子,经常重复,又没有技术难度可言。比如读取工作单生产计划,读取用户。
  经过思考,于是写个游标生成工具,把上面的模板代码,应用到代码生成器中。
DSC0000.png
  注意上图中的Script Cursor,这是用来生成游标模板的。选择一个数据库,树左边选择表名,勾选字段值,点击执行

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  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源代码,还需要应用下面的方法,将SQL关键字大写。
  将SQL查询语句的关键字大写的方法来自CSDN下载区,全文如下

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 = Regex.Replace(strRows, @&quot;\s+&quot;, &quot; &quot;);
//按空格划分
string[] strWords = strRows.Split(new char['\0']);
int wordsCount = strWords.Length;
for (int j = 0; j < wordsCount; j++)
{
strBuilder.Append(&quot; &quot;);
if (RegexSQLCapitalize.IsMatch(strWords[j]))
{
MatchCollection mc = RegexSQLCapitalize.Matches(strWords[j]);
int mcCount = 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(&quot; &quot;);
}
strBuilder.Append(&quot;\r\n&quot;);
}
return strBuilder.ToString().Replace(&quot;\r\n\r\n&quot;, &quot;\r\n&quot;);
}


  正则表达式替换字符串中的关键字,这个方法没有任何依赖,可拷贝到您的项目或类库中,为SQL 脚本增加关键字大写功能。
  
  3  SQL 脚本格式化功能  如果能把生成的SQL脚本格式化一下,生成美观的SQL脚本,增加可读性。SQL Pretty Printer可以做到,但是没有找到API可以调用这个功能。
  4 多表关联的游标模板没有做到。应该尝试从多个关联表中生成游标。不过表与表之间的关系难以自动生成,比如像下面的母子表游标询语句

Declare Cur Cursor For Select r.Description,r.WorkCenter  FROM JobOrder  j, JobOrderRouting r
WHERE j.JobNo=r.JobNo
Open Cur
  游标要从2个关联的表中读取数据,如果2个表之间有外键关联,可以生成2个表的外键关联字段的关系,也就是上面的SQL游标可以自动生成,但是有的2个表之间没有外键关联的,还是要手工指定,相当于是个半成品的游标生成器,于是只好把这个功能点拿掉,只做最简单的一种情况,生成一个表的若干个字段的游标查询,没有设计多表查询的游标。
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-81238-1-1.html 上篇帖子: 《Microsoft Sql server 2008 Internals》读书笔记--第五章Table(1) 下篇帖子: 《Microsoft Sql server 2008 Internals》读书笔记--第六章Indexes:Internals and Management(4
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表