SQL 多行拼成一行 (3种解决方案)

SQL 多行拼成一行 (3种解决方案)

运行环境 (sql 2000, 2005, 2008, 2014 ), 其中,最后一种方法 专为sql 2000提供。


原数据:

(5 行受影响)
UserID      RoleName          RoleID
----------- ----------       --------
2014000     developer           1
2014000     product             2
2014001     developer           1
2014002     developer           1
2014002     sales               3

期望结果:

UserID      NewRoleName                NewRoleID
----------- ------------------        ------------ 
2014000     developer, product          1|2
2014001     developer                   1
2014002     developer, sales            1|3

解决方案:

原始数据脚本

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TEST]') AND type in (N'U'))
DROP TABLE [dbo].[TEST]
GO

create TABLE TEST(UserID INT,RoleName VARCHAR(100),RoleID INT)
INSERT INTO TEST
SELECT 2014000,'developer',1
UNION ALL SELECT 2014000,'product',2
UNION ALL SELECT 2014001,'developer',1
UNION ALL SELECT 2014002,'developer',1
UNION ALL SELECT 2014002,'sales',3

-- SELECT * FROM TEST 
-- SELECT * FROM TEST pivot( min(ROLEID) for USERID IN([2014000],[2014001],[2014002])) A

解决方法1:

SELECT t.UserID
	,STUFF((SELECT ','+ltrim(RoleName)
                    FROM TEST  
                    WHERE UserID=t.UserID FOR XML PATH('')), 1, 1, '') 
	AS NewRoleName
	,STUFF((SELECT '|'+ltrim(RoleID)
                    FROM TEST  
                    WHERE UserID=t.UserID FOR XML PATH('')), 1, 1, '') 
	AS NewRoleID
FROM TEST t
GROUP BY UserID

解决方法2:

SELECT A.*
	,STUFF(CONVERT(VARCHAR(100),C.RoleID),1,1,'') AS NewRoleID
	,REPLACE(
		STUFF(CONVERT(VARCHAR(100),C.RoleName),1,1,'')
		,'|',', ') AS NewRoleName
FROM (
	 SELECT DISTINCT UserID
		-- ,COUNT(DISTINCT ID) AS CountOfID
	 FROM TEST
	 GROUP BY UserID
) A
CROSS APPLY (
	 SELECT RoleID = (
		SELECT '|' + Convert(varchar(10),RoleID)
		FROM TEST B
		WHERE B.UserID = A.UserID
		FOR XML PATH(''), TYPE
	   ),
		RoleName = (
		SELECT '|' + Convert(varchar(10),RoleName)
		FROM TEST B
		WHERE B.UserID = A.UserID
		FOR XML PATH(''), TYPE
	   )
) C
 

解决方法3:

if object_id('F_RoleName') is not null 
    drop function F_RoleName 
go 
create function F_RoleName(@UserID VARCHAR(100)) 
returns nvarchar(100) 
as 
begin 
    declare @S nvarchar(100) 
    select @S=isnull(@S+', ','')+ RoleName from TEST where UserID=@UserID 
    return @S 
end 
go 


if object_id('F_RoleID') is not null 
    drop function F_RoleID 
go 
create function F_RoleID(@UserID VARCHAR(100)) 
returns nvarchar(100) 
as 
begin 
    declare @S nvarchar(100) 
    select @S=isnull(@S+'|','')+ ltrim(RoleID) from TEST where UserID=@UserID 
    return @S 
end 
go 

Select distinct UserID
	,NewRoleName=dbo.F_RoleName(UserID) 
	,NewRoleID=dbo.F_RoleID(UserID) 
from TEST 


### Oracle SQL 多行转单行并用逗号分隔 在Oracle数据库中,可以使用 `LISTAGG` 函数将多行数据聚合到一行,并通过指定的分隔符连接这些值。此方法适用于需要汇总特定字段的情况。 对于早期版本的Oracle数据库,在不支持 `LISTAGG` 的情况下,则可以通过自定义方式实现相同功能,比如利用 `SYS_CONNECT_BY_PATH` 和层次查询来达到目的[^1]。 下面展示两种不同场景下的解决方案: #### 使用 LISTAGG 函数 (推荐) 当目标是获取某列的不同值组合单一字符串时,可以直接调用 `LISTAGG` 来完操作。这里给出一个简单的例子说明如何应用该函数: ```sql SELECT department_id, LISTAGG(employee_name, ', ') WITHIN GROUP (ORDER BY employee_name) AS employees_list FROM employees GROUP BY department_id; ``` 这段代码会按照部门编号(`department_id`)进行分组,并把每个部门内的员工名字(`employee_name`)以逗号加空格的形式拼接起来形新的字段`employees_list`。 #### 对于旧版 Oracle 数据库或特殊情况 如果所在环境不允许使用 `LISTAGG` 或者有更复杂的需求,那么可以考虑采用如下替代方案之一: - **使用 SYS_CONNECT_BY_PATH** 这种方法依赖于构建一棵树形结构的数据集并通过路径表达式提取所需的结果。需要注意的是要设置合适的伪列作为根节点以及调整排序逻辑确保最终输出顺序正确。 ```sql WITH emp_hierarchy AS ( SELECT e.department_id, e.employee_name, ROW_NUMBER() OVER(PARTITION BY e.department_id ORDER BY e.employee_name) rn, COUNT(*) OVER(PARTITION BY e.department_id) cnt FROM employees e ) SELECT DISTINCT eh.department_id, LTRIM(MAX(SYS_CONNECT_BY_PATH(eh.employee_name, ',')) KEEP(DENSE_RANK LAST ORDER BY eh.rn), ',') AS employees_list FROM emp_hierarchy eh CONNECT BY PRIOR eh.rn = eh.rn - 1 AND PRIOR eh.department_id = eh.department_id START WITH eh.rn = 1 GROUP BY eh.department_id; ``` 上述脚本首先计算每一行在其所属分区中的相对位置 (`ROW_NUMBER()`),接着基于这个序号建立父子关系链路最后再做一次最大值保留去除多余前缀得到期望格式化的列表[^2].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值