SQL Server中多行合并为单行的实现方法及SQL代码解析
一、SQL Server 中将多行数据合并为单行的常用方法
在SQL Server里,把多行数据合并成单行字符串是非常常见的需求,我整理了几种实用方案,适配不同版本的SQL Server:
1. STRING_AGG(SQL Server 2017 及以上版本)
这是官方推荐的简洁方法,内置函数直接搞定,语法直观。比如要把同一部门的员工姓名合并成逗号分隔的字符串:
SELECT DepartmentID, STRING_AGG(EmployeeName, ', ') AS EmployeeList FROM Employees GROUP BY DepartmentID;
如果需要指定合并后的排序顺序,可以加WITHIN GROUP子句:
SELECT DepartmentID, STRING_AGG(EmployeeName, ', ') WITHIN GROUP (ORDER BY EmployeeName ASC) AS SortedEmployeeList FROM Employees GROUP BY DepartmentID;
2. FOR XML PATH + STUFF(兼容SQL Server 2008及以上低版本)
如果你的数据库版本不支持STRING_AGG,这个经典组合绝对靠谱。还是用上面的员工例子:
SELECT DepartmentID, STUFF( (SELECT ', ' + EmployeeName FROM Employees e2 WHERE e2.DepartmentID = e1.DepartmentID FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '' ) AS EmployeeList FROM Employees e1 GROUP BY DepartmentID;
简单解释下:FOR XML PATH('')会把查询结果拼接成XML字符串,TYPE让它返回XML类型,.value('.', 'NVARCHAR(MAX)')把XML转成普通字符串,STUFF则用来去掉开头多余的分隔符(这里是, ,所以从第1位开始删除2个字符)。
3. COALESCE 变量拼接(适合单分组场景)
如果只是要把某一个分组的多行数据拼成字符串,用变量加COALESCE也很方便:
DECLARE @EmployeeList NVARCHAR(MAX) = ''; SELECT @EmployeeList = COALESCE(@EmployeeList + ', ', '') + EmployeeName FROM Employees WHERE DepartmentID = 1; SELECT @EmployeeList AS EmployeeList;
不过这种方法批量处理多分组时效率不如前两种,适合单分组的简单场景。
二、给定SQL查询代码的功能解析
先把你提供的截断代码整理完整(补全合理的截断部分):
DECLARE @Count BIGINT SELECT @Count = Count(ID) FROM Users; SELECT TOP 50 CustUser.[ID], CustUser.[FirstName] + ' ' + CustUser.[LastName] FirstName, CustUser.[NickName], CustUser.[UserName], R.[Name] Roles FROM ( SELECT ROW_NUMBER() OVER(ORDER BY US.ID Desc) AS Row, US.[ID], US.[FirstName], US.[LastName], US.[NickName], US.[UserName], US.[Password] FROM [Users] US ) CustUser LEFT JOIN Category CL ON CustUser.[LoginModeCode] = CL.CategoryCode LEFT JOIN Category CS ON CustUser.[StatusCode] = CS.CategoryCode LEFT JOIN Roles R ON CustUser.RoleID = R.ID -- 补全合理的角色关联逻辑
现在逐段解析功能:
变量声明与统计(冗余/未使用):
DECLARE @Count BIGINT:声明一个大整数类型的变量@CountSELECT @Count = Count(ID) FROM Users:统计Users表的总用户数并赋值给@Count,但这段代码里@Count后续没有被调用,大概率是残留代码,或者原本有分页计算(比如总页数)的逻辑被截断了。
子查询
CustUser:- 用
ROW_NUMBER() OVER(ORDER BY US.ID Desc)给Users表的每一行按ID降序生成行号Row,同时取出用户的核心字段:ID、姓名、昵称、用户名、密码。这个子查询的作用是给用户数据做排序标记,方便后续分页或筛选。
- 用
外层查询与关联逻辑:
SELECT TOP 50:只返回最新的50条用户数据(因为子查询按ID降序排序,ID大的是最新数据)- 拼接用户的
FirstName和LastName成一个新的FirstName字段(这里字段名和原字段重名,建议改成FullName更清晰) - 两次左连
Category表:- 第一次通过
LoginModeCode关联,目的是获取用户登录模式的分类名称(比如密码登录、短信登录等),但代码里没选择该表的字段,属于截断遗漏 - 第二次通过
StatusCode关联,目的是获取用户状态的分类名称(比如正常、禁用等),同样遗漏了字段选择
- 第一次通过
- 左连
Roles表(补全的合理逻辑):通过用户的角色ID关联,获取用户对应的角色名称,最终在结果中返回为Roles字段。
整体核心逻辑:
这段代码的核心是从Users表中获取最新的50条用户数据,同时关联分类表获取登录模式、用户状态的分类信息,关联角色表获取用户角色,最终返回用户的ID、全名、昵称、用户名、角色等关键信息。
内容的提问来源于stack exchange,提问作者Ram
相关产品推荐
相关产品推荐

