T-SQL技巧收集——拆分字符串
在开发中,很多时候都需要处理拆分字符串的操作。下面收集了几种方法供大家分享,其中的逗号可以改为多种有需要的符号,但是不能针对多种符号同时存在的例子。有待各位补充:
说明:
将字符串转换为正规化的数据表,可以使用多种方法实现,比如前端程序处理、游标、数据库循环函数,都是常用的技巧。
对于处理这些问题,比较好的思路就是使用SUBSTRING函数取出字符串,然后使用CHARINDEX函数定位。最后搭配排序函数完成拆分。
对于2005以后,可以使用CTE来实现。另外可以自定义一个函数处理。搭配输入分隔符与字符串,然后以TABLE方式返回。
解决方法:
下面是这4种方式的示例:
备注:首先针对原始字符串,可以使用BULKINSERT 后者BCP命令甚至直接INSERT语句,把原始数据导入数据表。以下语句是待处理的数据产生脚本,有业务代号和业务员订单:
为了输出每个业务员的每笔订单序号,所以用循环产生一个数据表,储存指定数量的序号。
接下来就是上面提到的4种方式的实现:
USE tempdb
GO
--建立数据表存储原始数据:
CREATE TABLE
Arrays
(
salesID
VARCHAR(10)
NOT NULL
,
salesOrd
VARCHAR(8000)
NOT NULL
)
GO
--注意:下面insert
语句中逗号后面有一个空格
INSERT
INTO Arrays
VALUES (
'A',
'20, 223, 2544' )
;
INSERT
INTO Arrays
VALUES (
'B',
'30, 23433, 28' )
;
INSERT
INTO Arrays
VALUES (
'C',
'12, 10' ) ;
INSERT
INTO Arrays
VALUES (
'D',
'4, 6, 45678, 2' )
;
GO
--通过循环产生存储指定数量的序号的表
CREATE TABLE
Nums
(
c1
INT NOT NULL
PRIMARY
KEY
) ;
GO
--产生数据
DECLARE
@i INT
SET @i
= 1
WHILE @i
<= 8000
BEGIN
INSERT
INTO Nums
VALUES (
@i )
SET
@i = @i
+ 1
END
以上版本使用。使用ROW_NUBMER函数
SELECT
salesID [业务编号]
,
ROW_NUMBER()
OVER (
PARTITION BY salesID
ORDER BY
c1 ) AS
[序号]
,
SUBSTRING(salesOrd,
c1,
CHARINDEX(', ',
salesOrd +
', ', c1)
- c1)
AS [值]
FROM
Arrays
JOIN
Nums ON c1
<= LEN(salesOrd)
ANDSUBSTRING(', '
+ salesOrd,
c1, 1)
= ', '
ORDER BY
salesID ,
[序号]
--方法二:适用于任何版本
SELECT
salesID [业务编号]
,
c1
- LEN(REPLACE(LEFT(salesOrd,
c1),
', ', ''))
+ 1 [序号]
,
SUBSTRING(salesOrd,
c1,
CHARINDEX(', ',
salesOrd +
', ', c1)
- c1)
AS [值]
FROM
arrays
JOIN
Nums ON c1
<= LEN(salesOrd)
ANDSUBSTRING(', '
+ salesOrd,
c1, 1)
= ', '
ORDER BY
salesID ,
[序号]
以上版本,使用CTE实现:
;
WITH
SplitCTE
AS (
SELECT salesID
,
1 AS
pos ,
1 AS
startpos ,
CHARINDEX(', ',
salesOrd +
', ') - 1
AS endpos
FROM dbo.Arrays
WHERE LEN(salesOrd)
> 0
UNION
ALL
SELECT Prv.salesID
,
Prv.pos+ 1
,
Prv.endpos+ 2
,
CHARINDEX(', ',
CUR.salesOrd
+ ', ',
Prv.endpos
+ 2)
- 1
FROM SplitCTE
ASPrv
JOIN
dbo.Arrays
AS Cur
ON CUR.salesID
= Prv.salesID
AND
CHARINDEX(', ',
cur.salesOrd
+
', ',
Prv.endpos
+ 2)
> 0
)
SELECT
A.salesID
AS [业务编号]
,
pos
[序号]
,
CAST(SUBSTRING(salesOrd,
startpos,
endpos - startpos
+ 1)
AS INT)
AS [值]
FROM
dbo.Arrays
AS a
JOIN
SplitCTEAS S
ON S.salesID
= A.salesID
ORDER
BY A.salesID
,
pos
GO
:使用自定义函数
CREATE FUNCTION
dbo.fn_split(
@orders AS
VARCHAR(MAX)
)
RETURNS
TABLE
AS
RETURN
SELECT
c1 - LEN(REPLACE(LEFT(@orders,
c1),
', ', ''))
+ 1 AS
[序号]
,
SUBSTRING(@orders,
c1,
CHARINDEX(', ',
@orders +
', ', c1)
- c1)
AS [值]
FROM
dbo.Nums
WHERE
c1 <= LEN(@orders)
AND
SUBSTRING(', '
+ @orders,
c1, 1)
= ', '
;
GO
--然后使用cross apply技巧,合并分解字符串
SELECT
salesID ,
B.*
FROM
Arrays a
CROSS
APPLY dbo.fn_split(a.salesOrd)
b
GO
通过一下执行计划的开销可以看到CTE方法的实现开销最小,所以建议使用这种方式处理:
T-SQL技巧收集——拆分字符串的更多相关文章
- 【SQL】sql版Split函数。用于拆分字符串为单列表格
功能与.net版string.Split函数类似,只不过.net返回的是数组,这个返回的是一个单列表格,每个拆分出来的子串占一行.可选是否移除空格子串和重复项.市面上类似的函数不算少,但大多都是在循环 ...
- oracle11g 拆分字符串的详细技巧
转自:http://m.blog.csdn.net/article/details?id=51946573 <-->功能需求 有一个比较长的SQL语句,查询 ...
- 在论坛中出现的比较难的sql问题:38(字符拆分 字符串检索问题)
原文:在论坛中出现的比较难的sql问题:38(字符拆分 字符串检索问题) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以,觉得 ...
- 在论坛中出现的比较难的sql问题:27(字符串拆分、字符串合并、非连续数字的间隔范围、随机返回字符串)
原文:在论坛中出现的比较难的sql问题:27(字符串拆分.字符串合并.非连续数字的间隔范围.随机返回字符串) 在论坛中看到一个帖子,帖子中有一些sql方面的面试题,我觉得这些面试题很有代表性. 原帖的 ...
- 在论坛中出现的比较难的sql问题:25(字符串拆分3)
原文:在论坛中出现的比较难的sql问题:25(字符串拆分3) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以,觉得有必要记录下 ...
- 在论坛中出现的比较难的sql问题:12(递归问题2 拆分字符串)
原文:在论坛中出现的比较难的sql问题:12(递归问题2 拆分字符串) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以,觉得有 ...
- SQL中拆分字符串substr及统计字符出现频数replace用法实例讲解
一.拆分字符串为若干行 例一:要求将表emp中的'king'按照每行一个单词拆成四行 注意:substr(str,pos):截取pos位置开始的字符: substr(str,pos,len):从pos ...
- MySQL基础操作&&常用的SQL技巧&&SQL语句优化
基础操作 一:MySQL基础操作 1:MySQL表复制 复制表结构 + 复制表数据 create table t3 like t ...
- DelphiXE2 DataSnap开发技巧收集
DelphiXE2 DataSnap开发技巧收集 作者: 2012-08-07 09:12:52 分类:Delphi 标签: 作为DelphiXE2 DataSnap开发的私家锦囊, ...
随机推荐
- DIV水平和垂直居中的实现
在div的宽度和高度固定的情况下,实现div水平和垂直居中普遍采用如下的方式: <!DOCTYPE html> <html> <head> <style ty ...
- myeclipse中,项目上有个叉报错,文件没有错误
同事将他的java项目交接给了我.和平时的交接一样.他把他最新的源码.打成压缩包,发给我. 我解压后.使用myeclipse开发工具.通过导入,将项目导入到我的开发工具中.这个时候有一个问题出现了.在 ...
- Struts开发问题集锦
在struts2de 1.6以前版本,都是用<s:datepicker>标签来获取时间,1.8后可以用struts-dojo.plugin里的<sx:datetimepicker&g ...
- Linux渗透+SSH内网转发
http://www.jb51.net/hack/58514.html http://blog.chinaunix.net/uid-756931-id-353243.html http://blog. ...
- Java集合类汇总记录-- apache.commons4(TreeList)
通常.Tree是Tree,List是List,两者不太可能混在一起.但apache-commons库却用tree实现了实现了List的接口,也就是TreeList类.与标准的LinkedList相比. ...
- 在TextView中加入图片
TextView是一个非常强大的控件,有时须要在一个控件中同一时候显示图片和文字,使用TextView非常easy实现. 方法一: 聊天软件比方QQ一般都会有发送表情的功能,使用SpannableSt ...
- boost::signals::signal的使用方法
吃力的讲完boost::signals的ppt.然后接着就是做练习题. 通过讲ppt,发现有一句话说的真好:你自己知道是一回事.你能给别人讲明确又是另外一回事.真的有些东西你自己理解,可是用语言去非常 ...
- javascript - 浏览TOM大叔博客的学习笔记
part1 ---------------------------------------------------------------------------------------------- ...
- [置顶] ffmpg简介以及用它实现音频视频合并(java)
1.简介 FFmpeg是一个自由软件,可以运行音频和视频多种格式的录影.转档.流功能. 2.下载 源代码 git://git.libav.org/libav.git Windo ...
- java程序开发代写(QQ:928900200)
条件:手机1.2都是安卓智能机,手机1开热点,手机2链接手机1,功能:A手机2通过刷手机网页,登陆手机1设定的页面并下载其手机的指定文件,B手机1控制手机2的流量,当通过的流量多的时候,停止流量的供应