我在数据库中有字符串,其中项目的序列号在一起,如下所示
项目表
A_NUMBER | 项目 |
---|---|
1 | i1,i2,i3,i4,i5,i6 |
2 | j1,j2,j3,j4,j5,i6,i7,i8 |
3 | k1,k2,k3 |
我想要这个字符串的结果输出如下所示:
Srllno1 | Srllno2 | Srllno3 | Srllno4 | 好好休息 |
---|---|---|---|---|
i1 | i2 | i3 | i4 | i5,i6 |
j1 | j2 | j3 | j4 | j5,i6,i7,i8 |
k1 | k2 | k3 |
我尝试了这个SQL语句:
SELECT
A_NUMBER,
items,
PARSENAME(REPLACE(items, ',', '.'), 1) AS Srllno1,
PARSENAME(REPLACE(items, ',', '.'), 2) AS Srllno2,
PARSENAME(REPLACE(items, ',', '.'), 3) AS Srllno3,
PARSENAME(REPLACE(items, ',', '.'), 4) AS Srllno4
FROM
db.itemtable;
但是除非我手动完成,否则我无法获得
SrlRest
。
STRING_SPLIT
但没有成功。
CRME:https://dbfiddle.uk/i_N273aI
如何达到想要的效果?
参见示例 STRING_SPLIT
select A_NUMBER,min(items) items
,max(case when ordinal=1 then value end)Srllno1
,max(case when ordinal=2 then value end)Srllno2
,max(case when ordinal=3 then value end)Srllno3
,max(case when ordinal=4 then value end)Srllno4
,string_agg(case when ordinal>4 then value end,',') within group (order by ordinal)SrllRest
from itemTable
cross apply(select value,ordinal from string_split(items,',',1))i
group by A_NUMBER
输出为
A_NUMBER | 项目 | Srllno1 | Srllno2 | Srllno3 | Srllno4 | 好好休息 |
---|---|---|---|---|---|---|
1 | i1,i2,i3,i4,i5,i6 | i1 | i2 | i3 | i4 | i5,i6 |
2 | j1,j2,j3,j4,j5,i6,i7,i8 | j1 | j2 | j3 | j4 | j5,i6,i7,i8 |
3 | k1,k2,k3 | k1 | k2 | k3 | 空 | 空 |
令人惊讶:) 对于 SQL Server 2017 及更高版本
select A_NUMBER,min(items) items
,max(case when ordinal=1 then value end)Srllno1
,max(case when ordinal=2 then value end)Srllno2
,max(case when ordinal=3 then value end)Srllno3
,max(case when ordinal=4 then value end)Srllno4
,string_agg(case when ordinal>4 then value end,',') within group (order by ordinal)SrllRest
from itemTable
cross apply(select value,row_number()over(order by (select null))ordinal from string_split(items,','))i
group by A_NUMBER
ordinal
替换为 row_number()over(order by (select null)
对于 SQL Server 2016
select A_NUMBER,items
,max(case when ordinal=1 then value end)Srllno1
,max(case when ordinal=2 then value end)Srllno2
,max(case when ordinal=3 then value end)Srllno3
,max(case when ordinal=4 then value end)Srllno4
,COALESCE(STUFF(
(select ','+value from(select value,row_number()over(order by (select null))ordinal
from string_split(items,','))i
where ordinal>4
for XML PATH('')
), 1, 2, N''
), N'')SrllRest
from itemTable
cross apply(select value,row_number()over(order by (select null))ordinal from string_split(items,','))i
group by A_NUMBER,items
string_agg
替换为 select ... XML Path
SQL Server 2008 版本
with r as(
select 1 lvl, A_NUMBER,items
,case when charindex(',',items)>0 then
substring(items,1,charindex(',',items)-1)
when len(items)>0 then items
else null
end SrllNo1
,cast(null as varchar) SrllNo2,cast(null as varchar) SrllNo3,cast(null as varchar) SrllNo4
,case when charindex(',',items)>0 then
substring(items,charindex(',',items)+1,1000)
else ''
end SrllRest
from itemTable
union all
select lvl+1 lvl, A_NUMBER,items
,SrllNo1
,cast(case when lvl=1 and charindex(',',SrllRest)>0 then
substring(SrllRest,1,charindex(',',SrllRest)-1)
when lvl=1 and len(SrllRest)>0 then SrllRest
else SrllNo2
end as varchar) SrllNo2
,cast(case when lvl=2 and charindex(',',SrllRest)>0 then
substring(SrllRest,1,charindex(',',SrllRest)-1)
when lvl=2 and len(SrllRest)>0 then SrllRest
else SrllNo3
end as varchar) SrllNo3
,cast(case when lvl=3 and charindex(',',SrllRest)>0 then
substring(SrllRest,1,charindex(',',SrllRest)-1)
when lvl=3 and len(SrllRest)>0 then SrllRest
else SrllNo4
end as varchar) SrllNo4
,case when charindex(',',SrllRest)>0 then
substring(SrllRest,charindex(',',SrllRest)+1,1000)
else ''
end SrllRest
from r where len(SrllRest)>0 and lvl<4
)
select * from r
where lvl=4 or len(SrllRest)=0
order by a_number
lvl | A_NUMBER | 项目 | 小号1 | 小号2 | 小号3 | 小号4 | 好好休息 |
---|---|---|---|---|---|---|---|
4 | 1 | i1,i2,i3,i4,i5,i6 | i1 | i2 | i3 | i4 | i5,i6 |
4 | 2 | j1,j2,j3,j4,j5,i6,i7,i8 | j1 | j2 | j3 | j4 | j5,i6,i7,i8 |
3 | 3 | k1,k2,k3 | k1 | k2 | k3 | 空 | |
2 | 4 | k1,k2 | k1 | k2 | 空 | 空 | |
1 | 5 | k1 | k1 | 空 | 空 | 空 | |
4 | 6 | k1,k2,k3,k4 | k1 | k2 | k3 | k4 | |
1 | 7 | 空 | 空 | 空 | 空 |
只是为了扩展我的评论。
concat()
,将 null 转换为空字符串是可选的
示例
Declare @YourTable Table ([Item] varchar(50)) Insert Into @YourTable Values
('i1,i2,i3,i4,i5,i6')
,('j1,j2,j3,j4,j5,i6,i7,i8')
,('k1,k2,k3')
Select Item
,Pos1 = concat('',JSON_VALUE(JS,'$[0]'))
,Pos2 = concat('',JSON_VALUE(JS,'$[1]'))
,Pos3 = concat('',JSON_VALUE(JS,'$[2]'))
,Pos4 = concat('',JSON_VALUE(JS,'$[3]'))
,Rest = concat( JSON_VALUE(JS,'$[4]')
,','+JSON_VALUE(JS,'$[5]')
,','+JSON_VALUE(JS,'$[6]')
,','+JSON_VALUE(JS,'$[7]')
,','+JSON_VALUE(JS,'$[8]')
,','+JSON_VALUE(JS,'$[9]')
,','+JSON_VALUE(JS,'$[10]')
)
From @YourTable A
Cross Apply (values ('["'+replace(string_escape([Item],'json'),',','","')+'"]') ) B(JS)
结果
请尝试以下基于 SQL Server 的 XML 和 XQuery 功能的解决方案。
XPath 谓词
/root/r[1]...
等发挥了所有作用。
通过
/root/r[position() ge 5]
谓词检索尾随标记。它是动态的,因此无需对该部分进行硬编码。
SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, items VARCHAR(200));
INSERT @tbl VALUES
('i1,i2,i3,i4,i5,i6')
,('j1,j2,j3,j4,j5,i6,i7,i8')
,('k1,k2,k3');
-- DDL and sample data population, end
DECLARE @separator CHAR(1) = ',';
SELECT t.*
-- , c
, c.value('(/root/r[1]/text())[1]', 'VARCHAR(20)') AS Srllno1
, c.value('(/root/r[2]/text())[1]', 'VARCHAR(20)') AS Srllno2
, c.value('(/root/r[3]/text())[1]', 'VARCHAR(20)') AS Srllno3
, COALESCE(c.value('(/root/r[4]/text())[1]', 'VARCHAR(20)'), '') AS Srllno4
, REPLACE(c.query('data(/root/r[position() ge 5]/text())').value('.', 'VARCHAR(50)')
,SPACE(1),',') AS SrllRest
FROM @tbl AS t
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' +
REPLACE(items, @separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t1(c);
输出
身份证 | 项目 | Srllno1 | Srllno2 | Srllno3 | Srllno4 | 好好休息 |
---|---|---|---|---|---|---|
1 | i1,i2,i3,i4,i5,i6 | i1 | i2 | i3 | i4 | i5,i6 |
2 | j1,j2,j3,j4,j5,i6,i7,i8 | j1 | j2 | j3 | j4 | j5,i6,i7,i8 |
3 | k1,k2,k3 | k1 | k2 | k3 |