使用自定义值透视 table

Pivot table with custom values

我有 table 说 FIDDLE HERE

+----+------+------+-----+-----+
| id | year | sell | buy | own |
+----+------+------+-----+-----+
| 1  | 2016 | 9    | 2   | 10  |
| 1  | 2017 | 9    |     | 10  |
| 1  | 2018 |      | 2   | 10  |
| 2  | 2016 | 7    | 2   | 11  |
| 2  | 2017 | 2    |     |     |
| 2  | 2018 |      |     | 18  |
+----+------+------+-----+-----+
create table test(id varchar(20), year varchar(20), 
sell varchar(20), buy varchar(20), 
own varchar(20));

insert into test values('1', '2016','9','2','10' )
insert into test values('1', '2017','9',NULL,'10' )
insert into test values('1', '2018',NULL,'2','10' )
insert into test values('2', '2016','7','2','11' )
insert into test values('2', '2017','2',NULL,'17' )
insert into test values('2', '2018','5','2','18' )

我正在尝试 PIVOT 但不是聚合值,我想保留一些不为空的字母 (S-Sell,B-Buy,O-Own )。如果特定年份的所有列都有值,那么那一年我需要 S_B_O。如果只有卖出和买入的价值,那么 S_B 等,那么预期输出是

+----+-------+------+------+
| ID | 2016  | 2017 | 2018 |
+----+-------+------+------+
| 1  | S_B_O | S_O  | B_O  |
+----+-------+------+------+
| 2  | S_B_O | S    | O    |
+----+-------+------+------+

我得到的最接近的是使用条件聚合(MAXconcat)而不是 PIVOT,但如果任何一个是 NULL,这也会给出 null。请提出解决方案。

select ID, 
MAX(CASE WHEN Year = '2016' AND sell is not null THEN 'S_' END + 
CASE WHEN Year = '2016' AND buy is not null THEN 'B_' END +
CASE WHEN Year = '2016' AND own is not null THEN 'O' END)
AS [2016],
MAX(CASE WHEN Year = '2017' AND sell is not null THEN 'S_' END + 
CASE WHEN Year = '2017' AND buy is not null THEN 'B_' END +
CASE WHEN Year = '2017' AND own is not null THEN 'O' END)
AS [2017]
/* ......for all year */
from test
group by id 

FIDDLE HERE

您可以使用 CONCAT 函数,它会自动处理 NULL。

select ID, 
CONCAT(MAX(CASE WHEN Year = '2016' AND sell is not null THEN 'S_' END) , 
MAX(CASE WHEN Year = '2016' AND buy is not null THEN 'B_' END) ,
MAX(CASE WHEN Year = '2016' AND buy is not null THEN 'O' END))
AS [2016],
CONCAT(MAX(CASE WHEN Year = '2017' AND sell is not null THEN 'S_' END) , 
MAX(CASE WHEN Year = '2017' AND buy is not null THEN 'B_' END) ,
MAX(CASE WHEN Year = '2017' AND buy is not null THEN 'O' END))
AS [2017]
from test
group by id

+----+-------+------+
| ID | 2016  | 2017 |
+----+-------+------+
|  1 | S_B_O | S_   |
|  2 | S_B_O | S_   |
+----+-------+------+

UPDATE 动态查询。正如@Larnu 所说,您应该将此作为单独的问题提出。您不应更改要求。

DECLARE @lst_Years NVARCHAR(MAX) , @query NVARCHAR(MAX)
SET @lst_Years = STUFF((SELECT distinct ',' + QUOTENAME([Year]) 
            FROM test 
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

SET @query = 'SELECT * FROM
(
select ID, [Year],
CONCAT(MAX(CASE WHEN  sell is not null THEN ''S_'' END) , 
MAX(CASE WHEN  buy is not null THEN ''B_'' END) ,
MAX(CASE WHEN buy is not null THEN ''O'' END))
AS [Value]
from test
group by id, [year]) as t
pivot
(
max(value) FOR YEAR IN (' + @lst_Years + ')
) as pvt'

EXEC(@query)

+----+-------+------+-------+
| ID | 2016  | 2017 | 2018  |
+----+-------+------+-------+
|  1 | S_B_O | S_   | B_O   |
|  2 | S_B_O | S_   | S_B_O |
+----+-------+------+-------+