Я хочу объединить несколько строк

Таблице:

|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'

Однако это не удается для атрибута Code с ID # 102, где присутствуют значения как B, так и C.

Как я могу обновить это, чтобы включить оба этих значения в один и тот же результат?

1
Mikael 11 Фев 2021 в 22:32

3 ответа

Лучший ответ

Вы можете попробовать повороты с такими вещами:

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

Вывод:

enter image description here

0
Kazi Mohammad Ali Nur 11 Фев 2021 в 21:03

Другой метод через 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  |
+-----+---------+---------+--------+------+
0
Yitzhak Khabinsky 11 Фев 2021 в 20:51

UPD: «Только STRING_AGG Server 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
0
dzhukov 11 Фев 2021 в 22:05
66161582