SqlServer2000和2005多行转一行

时间:2023-02-09 19:03:39

1.描述:将如下形式的数据按id字段合并value字段

id    value
----- ------
1 aa
1 bb
2 aaa
2 bbb
2 ccc

需要得到结果:

id     value
------ -----------
1 aa,bb
2 aaa,bbb,ccc

即:group by id, 求 value 的和(字符串相加)

(1).sql2000中只能用自定义的函数解决
create table tb(id int, value varchar(10))
insert into tb values(1, 'aa')
insert into tb values(1, 'bb')
insert into tb values(2, 'aaa')
insert into tb values(2, 'bbb')
insert into tb values(2, 'ccc')
go

create function dbo.f_str(@id int) returns varchar(100)
as
begin
declare @str varchar(1000)
set @str = ''
select @str = @str + ',' + cast(value as varchar) from tb where id = @id
set @str = right(@str , len(@str) - 1)
return @str
end
go

调用函数:

select id , value = dbo.f_str(id) from tb group by id;

drop function dbo.f_str;
drop table tb;
(2).sql2005中的方法
create table tb(id int, value varchar(10))
insert into tb values(1, 'aa')
insert into tb values(1, 'bb')
insert into tb values(2, 'aaa')
insert into tb values(2, 'bbb')
insert into tb values(2, 'ccc')
go

select id, [value] = stuff((select ',' + [value] from tb t where id = tb.id for xml path('')) , 1 , 1 , '')
from tb
group by id

drop table tb

(3).使用游标合并数据
create table tb(id int, value varchar(10))
insert into tb values(1, 'aa')
insert into tb values(1, 'bb')
insert into tb values(2, 'aaa')
insert into tb values(2, 'bbb')
insert into tb values(2, 'ccc')
go
declare @t table(id int,value varchar(100))--定义结果集表变量
--定义游标并进行合并处理
declare my_cursor cursor local for
select id , value from tb
declare @id_old int , @id int , @value varchar(10) , @s varchar(100)
open my_cursor
fetch my_cursor into @id , @value
select @id_old = @id , @s=''
while @@FETCH_STATUS = 0
begin
if @id = @id_old
select @s = @s + ',' + cast(@value as varchar)
else
begin
insert @t values(@id_old , stuff(@s,1,1,''))
select @s = ',' + cast(@value as varchar) , @id_old = @id
end
fetch my_cursor into @id , @value
END
insert @t values(@id_old , stuff(@s,1,1,''))
close my_cursor
deallocate my_cursor

select * from @t
drop table tb
(4).创建表,添加测试数据
CREATE TABLE tb(id int, [value] varchar(10))
INSERT tb SELECT 1, 'aa'
UNION ALL SELECT 1, 'bb'
UNION ALL SELECT 2, 'aaa'
UNION ALL SELECT 2, 'bbb'
UNION ALL SELECT 2, 'ccc'

--SELECT * FROM tb
/**//*
id value
----------- ----------
1 aa
1 bb
2 aaa
2 bbb
2 ccc

(5 row(s) affected)
*/
(5).在SQL2000只能用自定义函数实现

创建合并函数fn_strSum,根据id合并value值

GO
CREATE FUNCTION dbo.fn_strSum(@id int)
RETURNS varchar(8000)
AS
BEGIN
DECLARE @values varchar(8000)
SET @values = ''
SELECT @values = @values + ',' + value FROM tb WHERE
RETURN STUFF(@values, 1, 1, '')
END
GO

-- 调用函数
SELECT id, VALUE = dbo.fn_strSum(id) FROM tb GROUP BY id
DROP FUNCTION dbo.fn_strSum

创建合并函数fn_strSum2,根据id合并value值

GO
CREATE FUNCTION dbo.fn_strSum2(@id int)
RETURNS varchar(8000)
AS
BEGIN
DECLARE @values varchar(8000)
SELECT @values = isnull(@values + ',', '') + value FROM tb WHERE
RETURN @values
END
GO

-- 调用函数
SELECT id, VALUE = dbo.fn_strSum2(id) FROM tb GROUP BY id
DROP FUNCTION dbo.fn_strSum2
(6).在SQL2005中的新解法

使用OUTER APPLY

SELECT * 
FROM (SELECT DISTINCT id FROM tb) A OUTER APPLY(
SELECT [values]= STUFF(REPLACE(REPLACE(
(
SELECT value FROM tb N
WHERE id = A.id
FOR XML AUTO
), '<N value="', ','), '"/>', ''), 1, 1, '')
)N

使用XML

SELECT id, [values]=STUFF((SELECT ','+[value] FROM tb t WHERE id=tb.id FOR XML PATH('')), 1, 1, '')
FROM tb
GROUP BY id

删除测试表tb

drop table tb

/**//*
id values
----------- --------------------
1 aa,bb
2 aaa,bbb,ccc

(2 row(s) affected)
*/

2.实际使用的例子

SqlServer2000和2005多行转一行

语句如下:

WITH aa AS(
SELECT '0' id,
'1' systype,
'体温单' datatype,
'体温单' name,
bm.PAT_ID index1,
bm.PAT_NAME index2,
d.HIS_CODE parentnodename,
d.HIS_CODE nodename,
bd.ITEM_VALUE nodevalue,
bm.RECORD_USER_CODE operator_code,
bm.MODIFY_DATE operator_time,
CONVERT(varchar(10),bm.RECORD_DATE,120) RECORD_DATE,
'H0' record_index,
bd.ITEM_CODE nodecode
from dbo.PAT_BODYSIGN_MAS bm
inner join dbo.PAT_BODYSIGN_DETAIL bd on bm.ID = bd.MAS_ID
inner join dbo.COM_DIC d on bd.ITEM_CODE = d.CODE
where bm.MODIFY_DATE >= CONVERT(varchar(10),'2015-11-02 20:00:00',120)
and bm.MODIFY_DATE <= '2015-11-03'
--and bd.ITEM_CODE = 'bloodPress'
and CONVERT(varchar(12), bm.RECORD_DATE, 108) in
('00:00:00', '03:00:00', '07:00:00', '11:00:00', '15:00:00',
'19:00:00', '23:00:00')
),
bb AS
(
SELECT index1, [values]=STUFF((SELECT ' '+nodevalue FROM aa t WHERE index1=aa.index1 AND nodename=aa.nodename FOR XML PATH('')), 1, 1, '')
FROM aa
GROUP BY index1,nodename
)
SELECT * FROM bb;

SqlServer2000和2005多行转一行