【问题标题】:MS-SQL Combining multiple rows, columns into a single record?MS-SQL 将多行、多列组合成一条记录?
【发布时间】:2017-10-03 16:35:13
【问题描述】:

MS-SQL,..

假设我有一个名为 dbo.students 的表,其中包含如下字段

SubjectID       StudentfName   StudentsName ----------      -------------  ------------ 1               Mary           Abc 1               John           Defs 1               Sam            Ghix 2               Alaina         Jklxx 2               Edward         Mnoqwww

我期望的结果是这样的:

SubjectID       StudentName ----------      ------------- 1               Mary Abc, John Defs, Sam Ghix 2               Alaina Jklxx, Edward Mnoqwww

我知道如何将 StudentfName 和 StudentsName 组合为 StudentName,但我想使用 SubjectID 中的唯一值将所有名称组合在一行中?

【问题讨论】:

标签: sql-server string-aggregation


【解决方案1】:

如果是sql server VNext >= 2017 那么可以使用string_agg函数

select subjectid, string_agg(studentName,', ') from yourtable
    group by subjectid

对于早期版本,您需要使用以下内容和自定义代码:

select subjectid,  stuff(( select concat( ',', studentfname, ' ', studentsname) from #yourstudent y where y.subjectid = u.subjectid for xml path('')),1,1, '') 
    from #yourstudent u
    group by subjectid

你的表格输入数据:

create table #yourstudent (subjectid int, studentfname varchar(10), studentsname varchar(10))

insert into #yourstudent (subjectid, studentfname, studentsname) values
 ( 1       ,'Mary','Abc')
,( 1       ,'John','Defs')
,( 1       ,'Sam','Ghix')
,( 2       ,'Alaina','Jklxx  ')
,( 2       ,'Edward','Mnoqwww')

【讨论】:

  • XML PATH 如果文本包含&< 或任何其他在转换为 XML 时必须进行 HTML 编码的字符,则会失败
  • 是名字,我不认为他们会有特殊字符...如果是问题海报可能会提供示例数据...
  • 你的意思是像O'Reilly?在 Aaron Bertrand 的文章中描述了使用 XML PATH 进行字符串聚合,这些文章解释了这个问题。他还解释了为什么他使用varchar,因为表格可能包含非拉丁文本。
【解决方案2】:

希望这会奏效,

select
    SubjectID,
    stuff((
        select ',' + t.[StudentfName]+ ' ' +t.[StudentsName]
        from #your_table t
        where t.SubjectID = t1.SubjectID
        order by t.SubjectID
        for xml path('')
    ),1,1,'') as StudentName
from #your_table t1
group by SubjectID; 

【讨论】:

  • 不妨解释一下它的作用和来源
  • 谢谢,根据示例,这对我有用,.. concat 失败,不幸的是可以使用 SQL 2008 r2。
  • 当我在 ID 上使用 GROUP BY 时(在我的情况下,我的应用程序使用不同的表)我在我选择的字段上收到错误,如果我在下一个之前将该字段添加到组中选择中的字段失败(等等)并出现相同的错误:列 'dbo.AB_AB_ABC.State' 在选择列表中无效,因为它不包含在聚合函数或 GROUP BY 子句中。
【解决方案3】:
;WITH cte(SubjectID,StudentfName,StudentsName)
AS
(

SELECT 1,'Mary'  ,'Abc'     Union all
SELECT 1,'John'  ,'Defs'    Union all
SELECT 1,'Sam'   ,'Ghix'    Union all
SELECT 2,'Alaina','Jklxx'   Union all
SELECT 2,'Edward','Mnoqwww'
)
SELECT   SubjectID ,(STUFF((SELECT DISTINCT ', ' + CONCAT(CAST( StudentfName AS VARCHAR(50)), ',' ,CAST(StudentsName AS VARCHAR(50)))
        FROM cte i  WHERE i.SubjectID =u.SubjectID FOR XML PATH('')),1,1,'')) AS Studentfullname
From cte u
group by SubjectID

【讨论】:

    【解决方案4】:

    这称为字符串聚合或分组连接。

    有多种技术。所有这些都在 Aaron Bertrand 的文章中进行了描述,例如 Grouped Concatenation in SQL Server

    最快和最简单的使用是创建和使用 SQLCLR 聚合。像 Aaron Bertrand 那样使用 GROUPED_CONCAT_S

    SELECT 
       SubjectID, 
       dbo.GROUP_CONCAT_S(StudentfName + ' ' + StudentsName, 1)
    FROM dbo.Students
    GROUP BY SubjectID
    ORDER BY SubjectID;
    

    编写和部署 SQLCLR 聚合需要几个步骤,但内存、性能和可用性方面的好处是显着的。

    SQL Server 2017 将提供一个本机 STRING_AGG,它甚至比 SQLCLR 还要快,例如:

    SELECT 
       SubjectID, 
       STRING_AGG(StudentfName + ' ' + StudentsName, 1)
    FROM dbo.Students
    GROUP BY SubjectID
    ORDER BY SubjectID;
    

    接下来是 XML PATH。 输入更容易,但使用起来并不容易。本质上,您将所有字段转换为 XML 元素,并使用空字符串作为元素标记将它们与 XPATH 组合:

    SELECT SubjectID, 
           Students = STUFF((SELECT N', ' + 
                             StudentfName + ' ' + StudentsName
                             FROM Students AS p2
                             WHERE p2.SubjectID = p.SubjectID 
                             ORDER BY StudentfName, StudentsName
                             FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)')
                          ,1, 2, N'')
    FROM Students AS p
    GROUP BY subjectid
    ORDER BY subjectid;
    

    注意PATH, TYPE).value(...) 函数。如果字段包含任何对 XML 具有特殊含义的字符,例如 '<&,它们将被 XML 编码,例如 >,TYPE).value() 改为返回元素的值。

    其他技术并没有真正使用,因为它们更麻烦且速度更慢。

    【讨论】:

      猜你喜欢
      • 2018-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多