从 SQL 服务器中的行连接

Concatenate from rows in SQL server

我想连接多行

Table:

|id      |Attribute   |Value    |
|--------|------------|---------|
|101     |Manager     |Rudolf   |
|101     |Account     |456      |
|101     |Code        |B        |
|102     |Manager     |Anna     |
|102     |Cardno      |123      |
|102     |Code        |B        |
|102     |Code        |C        |

我要找的结果是:

|id      |Manager|Account|Cardno|Code      |
|--------|-------|-------|------|----------|
|101     |Rudolf |456    |      |B         |
|102     |Anna   |       |123   |B,C       |

我有以下来自 的代码:

select
  p.*,
  a.value as Manager,
  b.value as Account,
  c.value as Cardno
from table1 p
left join table2 a on a.id = p.id and a.attribute = 'Manager'
left join table2 b on b.id = p.id and b.attribute = 'Account'
left join table2 c on c.id = p.id and b.attribute = 'Cardno'

但是,对于 ID# 102 的 Code 属性,它失败了,其中存在 BC 值。

我如何更新它以在同一结果中包含这两个值?

UPD:“STRING_AGG 仅服务器 2017+” 您可以使用 CTE 和 STRING_AGG 函数解决此任务,例如:

declare
    @t table (id int, Attribute varchar (100), [Value] varchar (100) )

insert into @t
values
(101,     'Manager',     'Rudolf'),
(101,     'Account',     '456'),
(101,     'Code',        'B'),
(102,     'Manager',     'Anna'),
(102,     'Cardno',      '123'),
(102,     'Code',        'B'),
(102,     'Code',        'C')

;with cte as 
(
select id, Attribute 
,STRING_AGG([Value], ', ') WITHIN GROUP (ORDER BY ID ASC) AS [Value] 
from @t
group by ID, Attribute
)
select
    max(p.ID) ID
    ,a.Value Manager
    ,isnull(b.Value, '') Account
    ,isnull(c.Value, '') Cardno
    ,isnull(e.Value, '') Code
from cte p
left join cte a on a.id =p.ID and a.attribute = 'Manager'
left join cte b on b.id = p.id and b.attribute = 'Account'
left join cte c on c.id = p.id and c.attribute = 'Cardno'
left join cte e on e.id = p.id and e.attribute = 'Code'
group by p.ID, a.Value,b.Value,c.Value,e.Value

通过 XML 和 XQuery 的另一种方法。

适用于 SQL Server 2008 以上版本。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT, attribute VARCHAR(20), [Value] VARCHAR(30));
INSERT INTO @tbl (ID, attribute, Value) VALUES
(101,'Manager','Rudolf'),
(101,'Account','456'),
(101,'Code','B'),
(102,'Manager','Anna'),
(102,'Cardno','123'),
(102,'Code','B'),
(102,'Code','C');
-- DDL and sample data population, end

;WITH rs AS
(
    SELECT ID, (
        SELECT *
        FROM @tbl AS c
        WHERE c.id = p.id
        FOR XML PATH('r'), TYPE, ROOT('root')

    ) AS xmldata
    FROM @tbl AS p
    GROUP BY id
)
SELECT ID
    , COALESCE(xmldata.value('(/root/r[attribute="Manager"]/Value/text())[1]','VARCHAR(30)'),'') AS Manager
    , COALESCE(xmldata.value('(/root/r[attribute="Account"]/Value/text())[1]','VARCHAR(30)'),'') AS Account
    , COALESCE(xmldata.value('(/root/r[attribute="Cardno"]/Value/text())[1]','VARCHAR(30)'),'') AS Cardno
    , COALESCE(REPLACE(xmldata.query('data(/root/r[attribute="Code"]/Value)').value('.', 'VARCHAR(MAX)'), SPACE(1), ','),'') AS Code
FROM rs
ORDER BY ID;

输出

+-----+---------+---------+--------+------+
| ID  | Manager | Account | Cardno | Code |
+-----+---------+---------+--------+------+
| 101 | Rudolf  |     456 |        | B    |
| 102 | Anna    |         |    123 | B,C  |
+-----+---------+---------+--------+------+

如果您使用的是 SQL SERVER 2017 或更高版本,那么 string_agg()PIVOT() 将易于使用,但在性能解决方案中速度更快 (Query#1)。

如果您使用的是旧版本的 SQL 服务器,则使用 Query#2STUFF() 以及 XML PATH FOR() 将值与 PIVOT()[= 连接起来23=]

架构:

 create table table1 (id int, Attribute varchar(50) , Value  varchar(50));
 
 insert into table1 values(101     ,'Manager'     ,'Rudolf');   
 insert into table1 values(101     ,'Account'     ,'456');   
 insert into table1 values(101     ,'Code'        ,'B');
 insert into table1 values(102     ,'Manager'     ,'Anna');
 insert into table1 values(102     ,'Cardno'      ,'123');
 insert into table1 values(102     ,'Code'        ,'B');
 insert into table1 values(102     ,'Code'        ,'C');
 GO

查询#1 PIVOT() 与 STRING_AGG():

 select *  
 from
 (
     select t1.id,t1.attribute,
     string_agg(value,',')  AS value
     from table1 t1
     group by t1.id,t1.attribute
 ) d
 pivot
 (
   max(value)
   for attribute in (manager,account,cardno,code)
 ) piv
 

输出:

id manager account cardno code
101 Rudolf 456 <emnull</em B
102 Anna <emnull</em 123 B,C

Query#2 PIVOT() WITH STUFF() AND XML PATH FOR():

 select *  
 from
 (
     select distinct t1.id,t1.attribute,
   STUFF(
          (SELECT ', ' + convert(varchar(10), t2.value, 120)
           FROM table1 t2
           where t1.id = t2.id and t1.attribute=t2.attribute
           FOR XML PATH (''))
           , 1, 1, '')  AS value
 from table1 t1
 ) d
 pivot
 (
   max(value)
   for attribute in (manager,account,cardno,code)
 ) piv

输出:

id manager account cardno code
101 Rudolf 456 <emnull</em B
102 Anna <emnull</em 123 B, C

dbhere