<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">企业信息化_博客园|网站分类</title><subtitle type="text">代码改变世界</subtitle><id>http://feed.cnblogs.com/blog/sitecateogry/cio/rss</id><updated>2012-02-23T09:28:27Z</updated><generator>CNBlogs BlogServer</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/cate/cio/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/sitecateogry/cio/rss"/><entry><id>http://www.cnblogs.com/yiyumeng/archive/2012/02/03/2337218.html</id><title type="text">MS SQL自定义字符串拆分函数的惨痛经历</title><summary type="text"/><published>2012-02-03T07:57:00Z</published><updated>2012-02-03T07:57:00Z</updated><author><name>谢堂文(Darren Xie)</name><uri>http://www.cnblogs.com/yiyumeng/</uri></author><link rel="alternate" href="http://www.cnblogs.com/yiyumeng/archive/2012/02/03/2337218.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/yiyumeng/archive/2012/02/03/2337218.html"/><content type="html">&lt;p&gt;我想大家都会有一个自己的函数来处理这样的需求，在SQL中按给定的分隔符来拆分字符串，产生一个表。&lt;/p&gt; &lt;p&gt;以下是我的经历，我以流水账式请有更高明的大侠指教。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;话说有这么一个需求谈话：&lt;/p&gt; &lt;p&gt;Jeff：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;“我们工厂生产的产品，有机会会从客户那里退回到工厂返工，返工后再发给客户，不过会更换新的条码。客户需要知道退回来的条码是什么，换成了新的条码是什么，返工过程中，有多少数量是更换了的。”&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Darren Xie：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;“你提供一个条码ID，系统找出这个条码在更换前后的信息以及过程中的信息，如旧条码和新条码、不良以及更换品信息，产生报表。这些信息都可以从我们的MES系统中得到，但是需要在后台经过计算，会需要一些时间。”&lt;/p&gt; &lt;p&gt;“有些问题需要您把答案补充到你的需求中。”&lt;/p&gt; &lt;p&gt;“你一次会提交多少个ID进行查询？”&lt;/p&gt; &lt;p&gt;“你以什么方式输入到系统中？比如一个条码一个条码进行扫描、手工一个一个输入、复制粘贴、上传固定格式的文件还是其它方式？”&lt;/p&gt; &lt;p&gt;“你想要的报表是什么样的？”&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Jeff：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;“需要一个功能，可以通过手工输入或复制粘贴的方式输入一些条码号（数据不确定），一次可以提交多个条码。系统需要产生这些条码的报表，报表的内容是MES中这些条码的反工信息：旧条码是什么，换成了新的条码是什么，返工过程中，有多少数量是更换了的。报表要可以在线查询和导出Excel文件。”&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Darren Xie：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;“我想复述一下，看我的理解是否正确，同时加上我的想法。”&lt;/p&gt; &lt;p&gt;“我将配合你的需求内容，做一个功能，用WEB的方式实现（因为你在美国，我在中国，中国和美国的同事都可能要用到这个功能），有一个网页提供给你输入要查询的条码，你输入条码（可以输入一个再输入一个的方式，也可以复制有格式的文本，如用逗号、空格、换行分隔的文本。），输入的条码系统会自动格式化系统认识的格式，你输入你的邮件地址后再提交，之后系统会发送报表的连接地址给你，你通过连接地址查看报表。因为你提交的条码可能会很多，系统处理的时间较长，你提交后，系统会在后台计算出你要的数据，完成后就发送一个连接地址给你，我不使用附件的方式，是因为不知道附件会有多大，同是你也要求在线查询，有了连接地址你就可以与同事分享你的报表。下面给你一些设计预想，你看看是否同意或有更好的主意！”&lt;/p&gt; &lt;p&gt;提供一个网页，接收你提供的条码信息：&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/yiyumeng/201202/201202031556288982.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/yiyumeng/201202/201202031556293508.png" width="572" height="312"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;你提交数据后，你会收到邮件告诉你，报表已产生以及报表的连接地址：&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/yiyumeng/201202/201202031556298001.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/yiyumeng/201202/201202031556303051.png" width="579" height="239"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;你打开连接地址就是你要的报表，可以导出包括Excel在内的多种格式文件：&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/yiyumeng/201202/201202031556304546.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/yiyumeng/201202/201202031556311231.png" width="583" height="303"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Jeff:&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;“这就是我想要的，这样我得到报表的同时，也可以分享给需要的同事。请帮我做出来吧！”&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;这就是背景，我的设计是这样来处理的，用户在网面上输入信息，保存到数据库中，在数据库中建立Job或Trigger等去开始计算，计算好的结果保存好，再由数据库通过DBMail发邮件给用户，邮件中包括一个报表的连接地址，是一个网页，地址中带参数就可以了。&lt;/p&gt; &lt;p&gt;这中间有数据库的设计和使用（表、存储过程、函数、Jobs）、C#的功能代码、ASP.NET等等内容，但是我只是想说说这里要用到的SQL函数，其它的不会在本文中。&lt;/p&gt; &lt;p&gt;正题吧！这里提交的多个条码都是用逗号分的一个字符串，我就需要有一个功能在SQL中完成拆分成一个一列表，用于关联其它的表取数据计算。我的初始版本如下：&lt;/p&gt; &lt;div &gt;&lt;pre &gt;&lt;span &gt;SET&lt;/span&gt; ANSI_NULLS &lt;span &gt;ON&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;GO&lt;/span&gt;&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;SET&lt;/span&gt; QUOTED_IDENTIFIER &lt;span &gt;ON&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;GO&lt;/span&gt;&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;-- =============================================&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;-- Author:        &amp;lt;Author,,Darren&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;-- Create date: &amp;lt;Create Date,,20110823&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;-- Description:    &amp;lt;Description,,傳入帶指定分隔符的字符串，返回分割後的單列表&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;-- =============================================&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;ALTER&lt;/span&gt; &lt;span &gt;FUNCTION&lt;/span&gt; [dbo].[f_String2Table]&lt;/pre&gt;&lt;pre &gt;(    &lt;/pre&gt;&lt;pre&gt;@S &lt;span &gt;varchar&lt;/span&gt;(&lt;span &gt;max&lt;/span&gt;)&lt;/pre&gt;&lt;pre &gt;,@&lt;span &gt;CHAR&lt;/span&gt; &lt;span &gt;CHAR&lt;/span&gt;(1)&lt;/pre&gt;&lt;pre&gt;)&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;returns&lt;/span&gt; @r_table &lt;span &gt;table&lt;/span&gt;    &lt;/pre&gt;&lt;pre&gt;(COL NVARCHAR(&lt;span &gt;MAX&lt;/span&gt;) )   &lt;/pre&gt;&lt;pre &gt;&lt;span &gt;AS&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;BEGIN&lt;/span&gt;&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;IF&lt;/span&gt;(CHARINDEX(@&lt;span &gt;CHAR&lt;/span&gt;,@S)&amp;gt;0)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;BEGIN&lt;/span&gt;&lt;/pre&gt;&lt;pre &gt;insert @r_table &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;select&lt;/span&gt; LTRIM(RTRIM(&lt;span &gt;LEFT&lt;/span&gt;(@S,CHARINDEX(@&lt;span &gt;CHAR&lt;/span&gt;,@S)-1))) &lt;span &gt;WHERE&lt;/span&gt; &lt;span &gt;LEFT&lt;/span&gt;(@S,CHARINDEX(@&lt;span &gt;CHAR&lt;/span&gt;,@S)-1)&amp;lt;&amp;gt;&lt;span &gt;''&lt;/span&gt;;&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;select&lt;/span&gt; @S=RTRIM(LTRIM(&lt;span &gt;RIGHT&lt;/span&gt;(@S,len(@S)-CHARINDEX(@&lt;span &gt;CHAR&lt;/span&gt;,@S))));&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;END&lt;/span&gt;&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;IF&lt;/span&gt;(CHARINDEX(@&lt;span &gt;CHAR&lt;/span&gt;,@S)&amp;gt;0)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;BEGIN&lt;/span&gt;&lt;/pre&gt;&lt;pre &gt;insert @r_table&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;SELECT&lt;/span&gt; * &lt;span &gt;FROM&lt;/span&gt; [f_String2Table](@S,@&lt;span &gt;CHAR&lt;/span&gt;);&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;END&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;ELSE&lt;/span&gt;&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;BEGIN&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;insert @r_table &lt;/pre&gt;&lt;pre &gt;&lt;span &gt;select&lt;/span&gt; @S &lt;span &gt;WHERE&lt;/span&gt; @S&amp;lt;&amp;gt;&lt;span &gt;''&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;END&lt;/span&gt;&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;RETURN&lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;END&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;代码执行如下：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/yiyumeng/201202/201202031556313216.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/yiyumeng/201202/201202031556325757.png" width="736" height="178"&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;在应用上线后，有一天，美国佬发来了一封邮件，如下：&lt;/p&gt;&#xD;
&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&#xD;
&lt;p&gt;I tried using the system again today and received the following error message (See screenshot below).&amp;nbsp; &lt;p&gt;I completely understand the importance of creating a system that I should be able to use myself, but I’m sure you agree we have had our fair share of problems on this.&amp;nbsp; Due to all the problems we have &#xD;
&lt;p&gt;been having with this, I believe it would be much faster if you could run the data in HZ for the 184 lots &#xD;
&lt;p&gt;that I am looking to get the new id’s for.&amp;nbsp; The list of these 184 are attached via the excel file.&amp;nbsp; &lt;p&gt;Please approve for Xie TangWen to run these for me so I can move forward with my project.&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/yiyumeng/201202/201202031556352217.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/yiyumeng/201202/201202031556368695.png" width="650" height="317"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&lt;p&gt;这次，才真的认真看了看我的代码，后来才发现问题出在这个字符串处理的函数上，怪就怪当时认为是小功能，没有&lt;/p&gt;&#xD;
&lt;p&gt;TDD用去做。也才发现，对ＭＳ　ＳＱＬ中的递归调用函数了解得不够，这个问题在７.０的时候就有的了，一直到现在的SQL 2008R2都是存在的，因为错误信息“&lt;font color="#ff0000"&gt;No more the lock and the classes available from transaction.&lt;/font&gt;”告诉我问题所在，原来它只有２４，我给提交的是１８４个条码，从我的代码就就是调用１８２次，就出错了。就算是&lt;/p&gt;&#xD;
&lt;p&gt;ＳＱＬ　２００８Ｒ２也只有３２次。&lt;/p&gt;&#xD;
&lt;p&gt;只好改代码逻辑了。&lt;/p&gt;&#xD;
&lt;p&gt;用以下的版本代替才得到解决：&lt;/p&gt;&#xD;
&lt;div &gt;&lt;pre &gt;&lt;span &gt;alter&lt;/span&gt; &lt;span &gt;FUNCTION&lt;/span&gt; [dbo].[f_String2Table]&lt;/pre&gt;&lt;pre&gt;(    &lt;/pre&gt;&lt;pre &gt;@S &lt;span &gt;varchar&lt;/span&gt;(&lt;span &gt;max&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;,@&lt;span &gt;CHAR&lt;/span&gt; &lt;span &gt;CHAR&lt;/span&gt;(1)&lt;/pre&gt;&lt;pre &gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;returns&lt;/span&gt; @r_table &lt;span &gt;table&lt;/span&gt;    &lt;/pre&gt;&lt;pre &gt;(COL NVARCHAR(&lt;span &gt;MAX&lt;/span&gt;) )   &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;AS&lt;/span&gt;&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;BEGIN&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;IF&lt;/span&gt;(CHARINDEX(@&lt;span &gt;CHAR&lt;/span&gt;,@S)&amp;gt;0)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;BEGIN&lt;/span&gt;&lt;/pre&gt;&lt;pre &gt;insert @r_table &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;select&lt;/span&gt; LTRIM(RTRIM(&lt;span &gt;LEFT&lt;/span&gt;(@S,CHARINDEX(@&lt;span &gt;CHAR&lt;/span&gt;,@S)-1))) &lt;span &gt;WHERE&lt;/span&gt; &lt;span &gt;LEFT&lt;/span&gt;(@S,CHARINDEX(@&lt;span &gt;CHAR&lt;/span&gt;,@S)-1)&amp;lt;&amp;gt;&lt;span &gt;''&lt;/span&gt;;&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;select&lt;/span&gt; @S=RTRIM(LTRIM(&lt;span &gt;RIGHT&lt;/span&gt;(@S,len(@S)-CHARINDEX(@&lt;span &gt;CHAR&lt;/span&gt;,@S))));&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;END&lt;/span&gt;&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;while&lt;/span&gt;(CHARINDEX(@&lt;span &gt;CHAR&lt;/span&gt;,@S)&amp;gt;0)&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;BEGIN&lt;/span&gt;&lt;/pre&gt;&lt;pre &gt;insert @r_table &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;select&lt;/span&gt; LTRIM(RTRIM(&lt;span &gt;LEFT&lt;/span&gt;(@S,CHARINDEX(@&lt;span &gt;CHAR&lt;/span&gt;,@S)-1))) &lt;span &gt;WHERE&lt;/span&gt; &lt;span &gt;LEFT&lt;/span&gt;(@S,CHARINDEX(@&lt;span &gt;CHAR&lt;/span&gt;,@S)-1)&amp;lt;&amp;gt;&lt;span &gt;''&lt;/span&gt;;&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;select&lt;/span&gt; @S=RTRIM(LTRIM(&lt;span &gt;RIGHT&lt;/span&gt;(@S,len(@S)-CHARINDEX(@&lt;span &gt;CHAR&lt;/span&gt;,@S))));&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;END&lt;/span&gt;&lt;/pre&gt;&lt;pre &gt;insert @r_table &lt;/pre&gt;&lt;pre&gt;&lt;span &gt;select&lt;/span&gt; @S &lt;span &gt;WHERE&lt;/span&gt; @S&amp;lt;&amp;gt;&lt;span &gt;''&lt;/span&gt;;&lt;/pre&gt;&lt;pre &gt;&lt;/pre&gt;&lt;pre&gt;&lt;span &gt;RETURN&lt;/span&gt; &lt;/pre&gt;&lt;pre &gt;END&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;在ＳＱＬ中函数调用函数自身需要注意了。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/yiyumeng/aggbug/2337218.html?type=0" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/yiyumeng/archive/2012/02/03/2337218.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
