Reputation: 53
I want to convert the columns to rows using SQL Server. I have already tried unpivot but I don't have enough knowledge to make it, only can make one column.
This is the script for the original table:
CREATE TABLE #tb1(
[item] [numeric](6, 0) NULL,
[class] [char](9) NULL,
[P_1YEAR] [numeric](5, 0) NULL,
[P_2YEAR] [numeric](5, 0) NULL,
[P_3YEAR] [numeric](5, 0) NULL,
[C_YR_RET1] [numeric](8, 4) NULL,
[C_YR_RET2] [numeric](8, 4) NULL,
[C_YR_RET3] [numeric](7, 4) NULL,
) ON [PRIMARY]
GO
INSERT #tb1 ( [item], [class], [P_1YEAR], [P_2YEAR], [P_3YEAR], [C_YR_RET1], [C_YR_RET2], [C_YR_RET3])
VALUES ( CAST(29 AS Numeric(6, 0)), N'A ', CAST(2018 AS Numeric(5, 0)), CAST(2017 AS Numeric(5, 0)), CAST(2016 AS Numeric(5, 0)),CAST(-7.0755 AS Numeric(8, 4)), CAST(6.0703 AS Numeric(8, 4)), CAST(13.3893 AS Numeric(7, 4)))
INSERT #tb1 ( [item], [class], [P_1YEAR], [P_2YEAR], [P_3YEAR], [C_YR_RET1], [C_YR_RET2], [C_YR_RET3])
VALUES (CAST(29 AS Numeric(6, 0)), N'F ', CAST(2018 AS Numeric(5, 0)), CAST(2017 AS Numeric(5, 0)), CAST(2016 AS Numeric(5, 0)), CAST(-6.0276 AS Numeric(8, 4)), CAST(7.2750 AS Numeric(8, 4)), CAST(14.8798 AS Numeric(7, 4)))
GO
The final table should look like this:
Thanks!
Upvotes: 0
Views: 80
Reputation: 1269873
I think the simplest method, by far, is to use apply
and conditional aggregation:
select item, year,
max(case when class = 'A' then c end) as a,
max(case when class = 'F' then c end) as f
from tb1 cross apply
(values (p_1year, c_yr_ret1),
(p_2year, c_yr_ret2),
(p_3year, c_yr_ret3)
) v(year, c)
group by item, year
order by item, year desc;
apply
usually has better performance then using union all
, because it only scans the underlying table once.
Here is a db<>fiddle.
Upvotes: 1
Reputation: 1
you can do it with pivot only if you know that the column 'class' has static values that rarely change, else you'll have to do it with building this pivot into a string and execute it with 'EXECUTE sp_executesql'.
SELECT *
FROM
(
SELECT item, class, p_1year as year, c_yr_ret_1 as value FROM table_name
union all
SELECT item, class, p_2year, c_yr_ret_2 FROM table_name
union all
SELECT item, class, p_3year, c_yr_ret_3 FROM table_name
) table1
PIVOT
(
SUM(value) for class in ([A], [F])
) as pivoted_table;
Upvotes: 0
Reputation: 16908
Try this-
SELECT item, [Year],
SUM(A) A,SUM(F) F
FROM
(
SELECT item, p_1year [Year],
CASE WHEN class = 'A' THEN c_yr_rate_1year ELSE 0 END 'A',
CASE WHEN class = 'F' THEN c_yr_rate_1year ELSE 0 END 'F'
FROM your_table
UNION ALL
SELECT item, p_2year [Year],
CASE WHEN class = 'A' THEN c_yr_rate_2year ELSE 0 END 'A',
CASE WHEN class = 'F' THEN c_yr_rate_2year ELSE 0 END 'F'
FROM your_table
UNION ALL
SELECT item, p_3year [Year],
CASE WHEN class = 'A' THEN c_yr_rate_3year ELSE 0 END 'A',
CASE WHEN class = 'F' THEN c_yr_rate_3year ELSE 0 END 'F'
FROM your_table
)A
GROUP BY item, [Year]
ORDER BY 2
Upvotes: 1
Reputation: 12737
One way to do that is,
SELECT
ITEM,
YEAR,
SUM(CASE WHEN CLASS='A' THEN C_YR_RET_1YR ELSE 0 /* OR NULL */ END) AS A,
SUM(CASE WHEN CLASS='F' THEN C_YR_RET_12YR ELSE 0 /* OR NULL*/ END) AS F
FROM
TABLE_NAME
GROUP BY
ITEM,
YEAR
You might want to use null or 0 depending on if you decide to use aggregate functions on the same field later on. Zeros will make sums easier. Nulls will make Averages easier.
Upvotes: 0