惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
V
Visual Studio Blog
博客园 - Franky
N
Netflix TechBlog - Medium
WordPress大学
WordPress大学
小众软件
小众软件
Jina AI
Jina AI
L
Lohrmann on Cybersecurity
罗磊的独立博客
I
Intezer
W
WeLiveSecurity
T
Tenable Blog
Cyberwarzone
Cyberwarzone
P
Privacy & Cybersecurity Law Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
S
Securelist
Recent Announcements
Recent Announcements
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Engineering at Meta
Engineering at Meta
Hacker News: Ask HN
Hacker News: Ask HN
F
Full Disclosure
S
SegmentFault 最新的问题
S
Security Affairs
L
LINUX DO - 热门话题
C
CERT Recently Published Vulnerability Notes
博客园 - 叶小钗
Stack Overflow Blog
Stack Overflow Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
Secure Thoughts
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Register - Security
The Register - Security
月光博客
月光博客
Microsoft Azure Blog
Microsoft Azure Blog
Last Week in AI
Last Week in AI
PCI Perspectives
PCI Perspectives
N
News | PayPal Newsroom
Schneier on Security
Schneier on Security
T
Threat Research - Cisco Blogs
B
Blog RSS Feed
L
LINUX DO - 最新话题
F
Fortinet All Blogs
雷峰网
雷峰网
Security Latest
Security Latest
大猫的无限游戏
大猫的无限游戏
P
Palo Alto Networks Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
V
V2EX
人人都是产品经理
人人都是产品经理
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 【当耐特】

博客园 - 谢堂文(Darren Xie)

Camstar MES 5.8 發現Ajax事件失效 验证(C#和正则表达式) 新MES已上線 Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine Microsoft SQL Server Reporting Services (SSRS)报表技巧之在图表中增加参考线 MS SQL,数据库增长时众多表中谁是你关注的目标 SQL调优日记之发挥SQL性能与你的写法有关--对比三种方式实现相同功能 想个法子找出性能差的SQL T-SQL 日期处理总结 从MS SQL删除大数据说开去 一步一步用C#写一个检查SQL Server假死警报服务 MM的Windows 7 登录密码忘记之后 基于工作实际需求的Ext.Net和C#搭配应用之一 取出网域(AD)中所有计算机名及位置描述等信息 2012,我的C#全能Excel操作(无需Office,不使用XML) 代码注释规范 2012年开发者该做的11件事 取出AD中一個組的所有成員信息(C#實現功能配合EXT做的界面) 一個文件文件和路徑的類 C#路径/文件/目录/I/O常见操作汇总
MS SQL自定义字符串拆分函数的惨痛经历
谢堂文(Darren Xie) · 2012-02-03 · via 博客园 - 谢堂文(Darren Xie)

我想大家都会有一个自己的函数来处理这样的需求,在SQL中按给定的分隔符来拆分字符串,产生一个表。

以下是我的经历,我以流水账式请有更高明的大侠指教。

话说有这么一个需求谈话:

Jeff:

“我们工厂生产的产品,有机会会从客户那里退回到工厂返工,返工后再发给客户,不过会更换新的条码。客户需要知道退回来的条码是什么,换成了新的条码是什么,返工过程中,有多少数量是更换了的。”

Darren Xie:

“你提供一个条码ID,系统找出这个条码在更换前后的信息以及过程中的信息,如旧条码和新条码、不良以及更换品信息,产生报表。这些信息都可以从我们的MES系统中得到,但是需要在后台经过计算,会需要一些时间。”

“有些问题需要您把答案补充到你的需求中。”

“你一次会提交多少个ID进行查询?”

“你以什么方式输入到系统中?比如一个条码一个条码进行扫描、手工一个一个输入、复制粘贴、上传固定格式的文件还是其它方式?”

“你想要的报表是什么样的?”

Jeff:

“需要一个功能,可以通过手工输入或复制粘贴的方式输入一些条码号(数据不确定),一次可以提交多个条码。系统需要产生这些条码的报表,报表的内容是MES中这些条码的反工信息:旧条码是什么,换成了新的条码是什么,返工过程中,有多少数量是更换了的。报表要可以在线查询和导出Excel文件。”

Darren Xie:

“我想复述一下,看我的理解是否正确,同时加上我的想法。”

“我将配合你的需求内容,做一个功能,用WEB的方式实现(因为你在美国,我在中国,中国和美国的同事都可能要用到这个功能),有一个网页提供给你输入要查询的条码,你输入条码(可以输入一个再输入一个的方式,也可以复制有格式的文本,如用逗号、空格、换行分隔的文本。),输入的条码系统会自动格式化系统认识的格式,你输入你的邮件地址后再提交,之后系统会发送报表的连接地址给你,你通过连接地址查看报表。因为你提交的条码可能会很多,系统处理的时间较长,你提交后,系统会在后台计算出你要的数据,完成后就发送一个连接地址给你,我不使用附件的方式,是因为不知道附件会有多大,同是你也要求在线查询,有了连接地址你就可以与同事分享你的报表。下面给你一些设计预想,你看看是否同意或有更好的主意!”

提供一个网页,接收你提供的条码信息:

image

你提交数据后,你会收到邮件告诉你,报表已产生以及报表的连接地址:

image

你打开连接地址就是你要的报表,可以导出包括Excel在内的多种格式文件:

image

Jeff:

“这就是我想要的,这样我得到报表的同时,也可以分享给需要的同事。请帮我做出来吧!”

这就是背景,我的设计是这样来处理的,用户在网面上输入信息,保存到数据库中,在数据库中建立Job或Trigger等去开始计算,计算好的结果保存好,再由数据库通过DBMail发邮件给用户,邮件中包括一个报表的连接地址,是一个网页,地址中带参数就可以了。

这中间有数据库的设计和使用(表、存储过程、函数、Jobs)、C#的功能代码、ASP.NET等等内容,但是我只是想说说这里要用到的SQL函数,其它的不会在本文中。

正题吧!这里提交的多个条码都是用逗号分的一个字符串,我就需要有一个功能在SQL中完成拆分成一个一列表,用于关联其它的表取数据计算。我的初始版本如下:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:        <Author,,Darren>
-- Create date: <Create Date,,20110823>
-- Description:    <Description,,傳入帶指定分隔符的字符串,返回分割後的單列表>
-- =============================================
ALTER FUNCTION [dbo].[f_String2Table]
(    
    @S varchar(max)
    ,@CHAR CHAR(1)
)
returns @r_table table    
 (COL NVARCHAR(MAX) )   
AS
BEGIN
    IF(CHARINDEX(@CHAR,@S)>0)
    BEGIN
        insert @r_table 
            select LTRIM(RTRIM(LEFT(@S,CHARINDEX(@CHAR,@S)-1))) WHERE LEFT(@S,CHARINDEX(@CHAR,@S)-1)<>'';
        select @S=RTRIM(LTRIM(RIGHT(@S,len(@S)-CHARINDEX(@CHAR,@S))));
    END
    IF(CHARINDEX(@CHAR,@S)>0)
    BEGIN
        insert @r_table
            SELECT * FROM [f_String2Table](@S,@CHAR);
    END
    ELSE
    BEGIN
    insert @r_table 
            select @S WHERE @S<>'';
    END
RETURN 
END

代码执行如下:

image

在应用上线后,有一天,美国佬发来了一封邮件,如下:

I tried using the system again today and received the following error message (See screenshot below). 

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.  Due to all the problems we have

been having with this, I believe it would be much faster if you could run the data in HZ for the 184 lots

that I am looking to get the new id’s for.  The list of these 184 are attached via the excel file. 

Please approve for Xie TangWen to run these for me so I can move forward with my project.

image

这次,才真的认真看了看我的代码,后来才发现问题出在这个字符串处理的函数上,怪就怪当时认为是小功能,没有

TDD用去做。也才发现,对MS SQL中的递归调用函数了解得不够,这个问题在7.0的时候就有的了,一直到现在的SQL 2008R2都是存在的,因为错误信息“No more the lock and the classes available from transaction.”告诉我问题所在,原来它只有24,我给提交的是184个条码,从我的代码就就是调用182次,就出错了。就算是

SQL 2008R2也只有32次。

只好改代码逻辑了。

用以下的版本代替才得到解决:

alter FUNCTION [dbo].[f_String2Table]
(    
    @S varchar(max)
    ,@CHAR CHAR(1)
)
returns @r_table table    
 (COL NVARCHAR(MAX) )   
AS
BEGIN
 
    IF(CHARINDEX(@CHAR,@S)>0)
    BEGIN
        insert @r_table 
            select LTRIM(RTRIM(LEFT(@S,CHARINDEX(@CHAR,@S)-1))) WHERE LEFT(@S,CHARINDEX(@CHAR,@S)-1)<>'';
        select @S=RTRIM(LTRIM(RIGHT(@S,len(@S)-CHARINDEX(@CHAR,@S))));
    END
    while(CHARINDEX(@CHAR,@S)>0)
    BEGIN
        insert @r_table 
            select LTRIM(RTRIM(LEFT(@S,CHARINDEX(@CHAR,@S)-1))) WHERE LEFT(@S,CHARINDEX(@CHAR,@S)-1)<>'';
        select @S=RTRIM(LTRIM(RIGHT(@S,len(@S)-CHARINDEX(@CHAR,@S))));
    END
    insert @r_table 
            select @S WHERE @S<>'';
RETURN 
END

在SQL中函数调用函数自身需要注意了。