34,588
社区成员
发帖
与我相关
我的任务
分享
--分拆列值
--原著:邹建
--改编:爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开) 2007-12-16 广东深圳
/*
有表tb, 如下:
id value
----------- -----------
1 aa,bb
2 aaa,bbb,ccc
*/
--欲按id,分拆value列, 分拆后结果如下:
/*
id value
----------- --------
1 aa
1 bb
2 aaa
2 bbb
2 ccc
*/
--1. 旧的解决方法(sql server 2000)
select top 8000 id = identity(int, 1, 1) into # from syscolumns a, syscolumns b
select A.id, substring(A.[values], B.id, charindex(',', A.[values] + ',', B.id) - B.id)
from tb A, # B
where substring(',' + A.[values], B.id, 1) = ','
drop table #
--2. 新的解决方法(sql server 2005)
create table tb(id int,value varchar(30))
insert into tb values(1,'aa,bb')
insert into tb values(2,'aaa,bbb,ccc')
go
select A.id, B.value
from(
select id, [value] = convert(xml,' <root> <v>' + replace([value], ',', ' </v> <v>') + ' </v> </root>') from tb
)A
outer apply(
select value = N.v.value('.', 'varchar(100)') from A.[value].nodes('/root/v') N(v)
)B
drop table tb
/*
id value
----------- ------------------------------
1 aa
1 bb
2 aaa
2 bbb
2 ccc
(5 行受影响)
*/
/******************************************************************************************************************************************************
合并分拆表数据
整理人:中国风(Roy)
日期:2008.06.06
******************************************************************************************************************************************************/
--> --> (Roy)生成測試數據
if not object_id('Tab') is null
drop table Tab
Go
Create table Tab([Col1] int,[Col2] nvarchar(1))
Insert Tab
select 1,N'a' union all
select 1,N'b' union all
select 1,N'c' union all
select 2,N'd' union all
select 2,N'e' union all
select 3,N'f'
Go
合并表:
SQL2000用函数:
go
if object_id('F_Str') is not null
drop function F_Str
go
create function F_Str(@Col1 int)
returns nvarchar(100)
as
begin
declare @S nvarchar(100)
select @S=isnull(@S+',','')+Col2 from Tab where Col1=@Col1
return @S
end
go
Select distinct Col1,Col2=dbo.F_Str(Col1) from Tab
go
SQL2005用XML:
方法1:
select
a.Col1,Col2=stuff(b.Col2.value('/R[1]','nvarchar(max)'),1,1,'')
from
(select distinct COl1 from Tab) a
Cross apply
(select COl2=(select N','+Col2 from Tab where Col1=a.COl1 For XML PATH(''), ROOT('R'), TYPE))b
方法2:
select
a.Col1,COl2=replace(b.Col2.value('/Tab[1]','nvarchar(max)'),char(44)+char(32),char(44))
from
(select distinct COl1 from Tab) a
cross apply
(select Col2=(select COl2 from Tab where COl1=a.COl1 FOR XML AUTO, TYPE)
.query(' <Tab>
{for $i in /Tab[position() <last()]/@COl2 return concat(string($i),",")}
{concat("",string(/Tab[last()]/@COl2))}
</Tab>')
)b
SQL05用CTE:
;with roy as(select Col1,Col2,row=row_number()over(partition by COl1 order by COl1) from Tab)
,Roy2 as
(select COl1,cast(COl2 as nvarchar(100))COl2,row from Roy where row=1
union all
select a.Col1,cast(b.COl2+','+a.COl2 as nvarchar(100)),a.row from Roy a join Roy2 b on a.COl1=b.COl1 and a.row=b.row+1)
select Col1,Col2 from Roy2 a where row=(select max(row) from roy where Col1=a.COl1) order by Col1 option (MAXRECURSION 0)
生成结果:
/*
Col1 COl2
----------- ------------
1 a,b,c
2 d,e
3 f
(3 行受影响)
*/
--参考
拆分表:
--> --> (Roy)生成測試數據
if not object_id('Tab') is null
drop table Tab
Go
Create table Tab([Col1] int,[COl2] nvarchar(5))
Insert Tab
select 1,N'a,b,c' union all
select 2,N'd,e' union all
select 3,N'f'
Go
--SQL2000用辅助表:
if object_id('Tempdb..#Num') is not null
drop table #Num
go
select top 100 ID=Identity(int,1,1) into #Num from syscolumns a,syscolumns b
Select
a.Col1,COl2=substring(a.Col2,b.ID,charindex(',',a.Col2+',',b.ID)-b.ID)
from
Tab a,#Num b
where
charindex(',',','+a.Col2,b.ID)=b.ID --也可用 substring(','+a.COl2,b.ID,1)=','
--2000不使用辅助表
Select
a.Col1,COl2=substring(a.Col2,b.number,charindex(',',a.Col2+',',b.number)-b.number)
from
Tab a join master..spt_values b
ON B.type='p' AND B.number BETWEEN 1 AND LEN(A.col2)
where
substring(','+a.COl2,b.number,1)=','
SQL2005用Xml:
select
a.COl1,b.Col2
from
(select Col1,COl2=convert(xml,'<root><v>'+replace(COl2,',','</v><v>')+'</v></root>') from Tab)a
outer apply
(select Col2=C.v.value('.','nvarchar(100)') from a.COl2.nodes('/root/v')C(v))b
SQL05用CTE:
;with roy as
(select Col1,COl2=cast(left(Col2,charindex(',',Col2+',')-1) as nvarchar(100)),Split=cast(stuff(COl2+',',1,charindex(',',Col2+','),'') as nvarchar(100)) from Tab
union all
select Col1,COl2=cast(left(Split,charindex(',',Split)-1) as nvarchar(100)),Split= cast(stuff(Split,1,charindex(',',Split),'') as nvarchar(100)) from Roy where split>''
)
select COl1,COl2 from roy order by COl1 option (MAXRECURSION 0)
生成结果:
/*
Col1 COl2
----------- -----
1 a
1 b
1 c
2 d
2 e
3 f
*/
CREATE Table #tb(
F1 varchar(12),
F2 VARCHAR(100)
)
insert into #tb select 'a','1,2,5'
union all select 'b','1,3'
union all select 'c','3,5'
--方法一:
SELECT A.F1,B.F2
FROM(
SELECT F1, F2 = CONVERT(xml,'<root><v>' + REPLACE(F2, ',', '</v><v>') + '</v></root>') FROM #tb
)A
OUTER APPLY(
SELECT F2 = N.v.value('.', 'varchar(100)') FROM A.F2.nodes('/root/v') N(v)
)B
go
--方法二:
select a.F1,F2=SUBSTRING(a.F2,b.number,CHARINDEX(',',a.F2+',',b.number)-b.number)
from #tb a join master..spt_values b on b.type='p' and b.number <=len(a.F2)
where CHARINDEX(',',','+a.F2,b.number)=b.number
结果为:
F1 F2
a 1
a 2
a 5
b 1
b 3
c 3
c 5
create table tb(F1 varchar(10),F2 varchar(20))
insert into tb select 'a','1,2,5'
insert into tb select 'b','1,3'
insert into tb select 'c','3,5'
go
select a.F1,substring(a.F2,b.number,charindex(',',a.F2+',',b.number+1)-b.number)F2
from tb a,master..spt_values b
where b.type='p' and b.number<=len(a.F2) and substring(a.F2,b.number,1)<>',' and substring(','+a.F2,b.number,1)=','
/*
F1 F2
---------- --------------------
a 1
a 2
a 5
b 1
b 3
c 3
c 5
(7 行受影响)
*/
go
drop table tb
create table tb(F1 varchar(10),F2 varchar(20))
insert into tb select 'a','1,2,5'
insert into tb select 'b','1,3'
insert into tb select 'c','3,5'
go
SELECT TOP 8000 id = IDENTITY(int, 1, 1) INTO # FROM syscolumns a, syscolumns b
SELECT A.F1, SUBSTRING(A.F2, B.id, CHARINDEX(',', A.F2 + ',', B.id) - B.id) F2
FROM tb A, # B
WHERE SUBSTRING(',' + A.F2, B.id, 1) = ','
/*
F1 F2
---------- --------------------
a 1
a 2
a 5
b 1
b 3
c 3
c 5
(7 行受影响)
*/
go
DROP TABLE tb,#
create table tb(F1 char(1),F2 varchar(10))
insert into tb
select 'a','1,2,5' union
select 'b','1,3' union
select 'c','3,5'
create function f(@str varchar(20))
returns @t table (F varchar(2))
as
begin
set @str=@str+','
while CHARINDEX(',',@str)>0
begin
insert into @t
select left(@str,CHARINDEX(',',@str)-1)
set @str=right(@str,len(@str)-CHARINDEX(',',@str))
end
return
end
select a.F1,b.* from tb a
cross apply f(a.F2)b
/*
F1 F
---- ----
a 1
a 2
a 5
b 1
b 3
c 3
c 5
DECLARE @tb Table(
CompanyID INT,
CompanyCodes VARCHAR(100)
)
insert into @tb select 1,'1|2'
union all select 2,'1|2|3'
union all select 3,'1|2|3|4'
union all select 4,'1|2|3|4|5'
select a.CompanyID,
CompanyCodes = substring(a.CompanyCodes,b.number,charindex('|',a.CompanyCodes+'|',b.number)-b.number)
from @tb a join master..spt_values b
on b.[type] = 'p' and b.number between 0 and len(a.CompanyCodes)
and substring('|'+a.CompanyCodes,b.number,1) = '|'
/****************
CompanyID CompanyCodes
----------- ----------------------------------------------------------------------------------------------------
1 1
1 2
2 1
2 2
2 3
3 1
3 2
3 3
3 4
4 1
4 2
4 3
4 4
4 5
(14 行受影响)