I have to rotate a given table from an SQL Server but a normal pivot just doesn't work (as far as i tried). So has anybody an idea how to rotate the table into the desired format?
Just to make the problem more complicated, the list of given labels can vary and it is possible that a new label name can come into at any given time.
Given Data
ID | Label | Numerator | Denominator | Ratio
---+-----------------+-------------+---------------+--------
1 | LabelNameOne | 41 | 10 | 4,1
1 | LabelNameTwo | 0 | 0 | 0
1 | LabelNameThree | 21 | 10 | 2,1
1 | LabelNameFour | 15 | 10 | 1,5
2 | LabelNameOne | 19 | 19 | 1
2 | LabelNameTwo | 0 | 0 | 0
2 | LabelNameThree | 15 | 16 | 0,9375
2 | LabelNameFive | 19 | 19 | 1
2 | LabelNameSix | 17 | 17 | 1
3 | LabelNameOne | 12 | 12 | 1
3 | LabelNameTwo | 0 | 0 | 0
3 | LabelNameThree | 11 | 12 | 0,9167
3 | LabelNameFour | 12 | 12 | 1
3 | LabelNameSix | 0 | 1 | 0
Wanted result
ID | ValueType | LabelNameOne | LabelNameTwo | LabelNameThree | LabelNameFour | LabelNameFive | LabelNameSix
---+-------------+--------------+--------------+----------------+---------------+---------------+--------------
1 | Numerator | 41 | 0 | 21 | 15 | |
1 | Denominator | 10 | 0 | 10 | 10 | |
1 | Ratio | 4,1 | 0 | 2,1 | 1,5 | |
2 | Numerator | 19 | 0 | 15 | | 19 | 17
2 | Denominator | 19 | 0 | 16 | | 19 | 17
2 | Ratio | 1 | 0 | 0,9375 | | 1 | 1
3 | Numerator | 12 | 0 | 11 | 12 | | 0
3 | Denominator | 12 | 0 | 12 | 12 | | 1
3 | Ratio | 1 | 0 | 0,9167 | 1 | | 0
This should sort you out. It's really an UNPIVOT and a PIVOT. Note that you have to conform your data because the UNPIVOT puts all the data in the same column.
Note that I had to recreate/repopulate the table variable in the inner dynamic SQL - typically this is not necessary when dealing with a permanent table.
SET NOCOUNT ON ;
DECLARE #pivot_cols AS varchar(max) ;
DECLARE #src AS TABLE
(
ID int NOT NULL
,Label varchar(14) NOT NULL
,Numerator int NOT NULL
,Denominator int NOT NULL
,Ratio decimal(5, 4) NOT NULL
) ;
DECLARE #label_order AS TABLE
(
Label varchar(14) NOT NULL
,Sort int NOT NULL
)
INSERT INTO #src
VALUES (1, 'LabelNameOne', 41, 10, 4.1) ;
INSERT INTO #src
VALUES (1, 'LabelNameTwo', 0, 0, 0) ;
INSERT INTO #src
VALUES (1, 'LabelNameThree', 21, 10, 2.1) ;
INSERT INTO #src
VALUES (1, 'LabelNameFour', 15, 10, 1.5) ;
INSERT INTO #src
VALUES (2, 'LabelNameOne', 19, 19, 1) ;
INSERT INTO #src
VALUES (2, 'LabelNameTwo', 0, 0, 0) ;
INSERT INTO #src
VALUES (2, 'LabelNameThree', 15, 16, 0.9375) ;
INSERT INTO #src
VALUES (2, 'LabelNameFive', 19, 19, 1) ;
INSERT INTO #src
VALUES (2, 'LabelNameSix', 17, 17, 1) ;
INSERT INTO #src
VALUES (3, 'LabelNameOne', 12, 12, 1) ;
INSERT INTO #src
VALUES (3, 'LabelNameTwo', 0, 0, 0) ;
INSERT INTO #src
VALUES (3, 'LabelNameThree', 11, 12, 0.9167) ;
INSERT INTO #src
VALUES (3, 'LabelNameFour', 12, 12, 1) ;
INSERT INTO #src
VALUES (3, 'LabelNameSix', 0, 1, 0) ;
INSERT INTO #label_order
VALUES ('LabelNameOne', 1) ;
INSERT INTO #label_order
VALUES ('LabelNameTwo', 2) ;
INSERT INTO #label_order
VALUES ('LabelNameThree', 3) ;
INSERT INTO #label_order
VALUES ('LabelNameFour', 4) ;
INSERT INTO #label_order
VALUES ('LabelNameFive', 5) ;
INSERT INTO #label_order
VALUES ('LabelNameSix', 6) ;
WITH Labels
AS (
SELECT DISTINCT
src.Label
,ISNULL(label_order.Sort, 0) AS Sort
FROM #src AS src
LEFT JOIN #label_order AS label_order
ON src.label = label_order.label
)
SELECT #pivot_cols = COALESCE(#pivot_cols + ',', '') + QUOTENAME(Label, '[')
FROM Labels
ORDER BY Sort
,Label ;
DECLARE #template AS varchar(max) ;
SET #template = '
DECLARE #src AS TABLE
(
ID int NOT NULL
,Label varchar(14) NOT NULL
,Numerator int NOT NULL
,Denominator int NOT NULL
,Ratio decimal(5, 4) NOT NULL
) ;
INSERT INTO #src
VALUES (1, ''LabelNameOne'', 41, 10, 4.1) ;
INSERT INTO #src
VALUES (1, ''LabelNameTwo'', 0, 0, 0) ;
INSERT INTO #src
VALUES (1, ''LabelNameThree'', 21, 10, 2.1) ;
INSERT INTO #src
VALUES (1, ''LabelNameFour'', 15, 10, 1.5) ;
INSERT INTO #src
VALUES (2, ''LabelNameOne'', 19, 19, 1) ;
INSERT INTO #src
VALUES (2, ''LabelNameTwo'', 0, 0, 0) ;
INSERT INTO #src
VALUES (2, ''LabelNameThree'', 15, 16, 0.9375) ;
INSERT INTO #src
VALUES (2, ''LabelNameFive'', 19, 19, 1) ;
INSERT INTO #src
VALUES (2, ''LabelNameSix'', 17, 17, 1) ;
INSERT INTO #src
VALUES (3, ''LabelNameOne'', 12, 12, 1) ;
INSERT INTO #src
VALUES (3, ''LabelNameTwo'', 0, 0, 0) ;
INSERT INTO #src
VALUES (3, ''LabelNameThree'', 11, 12, 0.9167) ;
INSERT INTO #src
VALUES (3, ''LabelNameFour'', 12, 12, 1) ;
INSERT INTO #src
VALUES (3, ''LabelNameSix'', 0, 1, 0) ;
WITH src_conformed
AS (
SELECT ID
,Label
,CAST (Numerator AS decimal(10, 4)) AS Numerator
,CAST (Denominator AS decimal(10, 4)) AS Denominator
,CAST (Ratio AS decimal(10, 4)) AS Ratio
FROM #src
),
UNPIVOTED
AS (
SELECT *
FROM src_conformed UNPIVOT ( Val FOR Col IN (Numerator, Denominator, Ratio) ) AS unpvt
)
SELECT *
FROM UNPIVOTED PIVOT ( SUM(Val) FOR Label IN ({#pivot_cols}) ) AS pvt
ORDER BY ID
,Col ;' ;
SET #template = REPLACE(#template, '{#pivot_cols}', #pivot_cols) ;
EXEC (#template) ;
select
id,
'Numerator' as ValueType,
case when label = labelNameOne then Numerator else 0 end as LabelNameOne,
case when label = labelNameTwo then Numerator else 0 end as LabelNameTwo,
case when label = labelNameTree then Numerator else 0 end as LabelNameTree,
case when label = labelNameFour then Numerator else 0 end as LabelNameFour,
case when label = labelNameFive then Numerator else 0 end as LabelNameFive,
case when label = labelNameSix then Numerator else 0 end as LabelNameSix
union All
... similar query with Denominator ...
union all
... similar query with Ratio...
What you seek is dynamic cross tab. The short answer is that it cannot be done in T-SQL without some fugly dynamic SQL. The Hoyle answer is that you should pivot the data in a reporting tool or in the middle tier.
Related
On a Sql-Server instance, I have three tables:
ActionItem
Id
Name
1
Fish
2
Gravy
3
Pants
ActionData
Id
ActionId
Group
Field
Value
1
1
1
1
100
2
1
1
2
200
3
1
1
3
300
4
1
1
4
NULL
5
1
1
5
NULL
6
1
2
6
"Some Text"
7
2
1
1
50
8
2
1
2
60
9
2
1
3
70
Costing
Id
ActionId
Break
Cost
1
1
Normal
11.3
2
1
Sub
54
3
1
Premium
0.4
4
3
Normal
22
5
3
Premium
0.67
I have a query that sums the cost for each ActionItem:
select
ai.Id,
ai.Name,
sum(c.Cost)
from ActionItem ai
left join Costing c on ai.Id = c.ActionId
group by
ai.Id,
ai.Name
Nice and straight-forward:
Id
Name
(No column name)
1
Fish
65.7
2
Gravy
NULL
3
Pants
22.67
I created a pivot too:
select * from
(select [ActionId], [Group], [Field], [Value] from ActionData) src
pivot (max([Value]) for [ActionId] in ([1],[2],[3],[4])) ppp
Which gets me data in the right format:
Group
Field
1
2
3
4
1
1
100
50
NULL
NULL
1
2
200
60
NULL
NULL
1
3
300
70
NULL
NULL
1
4
NULL
NULL
NULL
NULL
1
5
NULL
NULL
NULL
NULL
2
6
"Some Text"
NULL
NULL
NULL
But I cannot join these two queries together because that PIVOT doesn't contain the ActionId ... even though I use Select * from - how can I get the ActionId col to show on my pivoted data, so I can join it to the rest of my original query?
I could not get sqlfiddle.com to work for MS SQL SERVER today but here are create and inserts if anyone's interested:
CREATE TABLE ActionItem
([Id] int, [Name] varchar(5));
INSERT INTO ActionItem
([Id], [Name])
VALUES
(1, 'Fish'),
(2, 'Gravy'),
(3, 'Pants');
CREATE TABLE ActionData
([Id] int, [ActionId] int, [Group] int, [Field] int, [Value] varchar(11));
INSERT INTO ActionData
([Id], [ActionId], [Group], [Field], [Value])
VALUES
(1, 1, 1, 1, '100'),
(2, 1, 1, 2, '200'),
(3, 1, 1, 3, '300'),
(4, 1, 1, 4, NULL),
(5, 1, 1, 5, NULL),
(6, 1, 2, 6, '"Some Text"'),
(7, 2, 1, 1, '50'),
(8, 2, 1, 2, '60'),
(9, 2, 1, 3, '70')
;
CREATE TABLE Costing (
[Id] int,
[ActionId] int,
[Break] VARCHAR(9),
[Cost] FLOAT);
INSERT INTO Costing
([Id], [ActionId], [Break], [Cost])
VALUES
('1', '1', 'Normal', '11.3'),
('2', '1', 'Sub', '54'),
('3', '1', 'Premium', '0.4'),
('4', '3', 'Normal', '22'),
('5', '3', 'Premium', '0.67');
Not sure what output you expect.
But here's an attempt to join the two queries in 1 pivot.
select pvt.*
from
(
select d.ActionId, ai.Name
--, d.[Group]
, cast(d.[Field] as varchar(30)) as [Col]
, try_cast(d.[Value] as float) as [Value]
from ActionData d
left join ActionItem ai on ai.Id = d.ActionId
where isnumeric(d.[Value]) = 1
union all
select c.ActionId, ai.Name
--, 1 as [Group]
, c.[Break] as [Col]
, sum(c.Cost) as TotalCost
from Costing c
left join ActionItem ai
on ai.Id = c.ActionId
group by c.ActionId, ai.Name, c.[Break]
) src
pivot (
max([Value])
for [Col] in ([1],[2],[3],[4],[Normal],[Premium],[Sub])
) pvt
GO
ActionId | Name | 1 | 2 | 3 | 4 | Normal | Premium | Sub
-------: | :---- | ---: | ---: | ---: | ---: | -----: | ------: | ---:
1 | Fish | 100 | 200 | 300 | null | 11.3 | 0.4 | 54
2 | Gravy | 50 | 60 | 70 | null | null | null | null
3 | Pants | null | null | null | null | 22 | 0.67 | null
db<>fiddle here
I want to rank on ID and value columns based on ascending order of UID. Expected output has to change once value column has a different value than the previous value. Ranks has to restart on each new ID
UID ID Value Expected Output
1 1 0 1
2 1 0 1
3 1 1 2
4 1 1 2
5 1 1 2
6 1 0 3
7 1 1 4
8 1 0 5
9 1 0 5
10 1 0 5
11 2 1 1
12 2 1 1
13 2 0 2
14 2 0 2
15 2 1 3
Here is a sample dataset that I have created:
CREATE TABLE [dbo].[Data] (
[UID] [int] NOT NULL,
[ID] [int] NULL,
[Value] [int] NULL
);
INSERT [dbo].[Data] ([UID], [ID], [Value]) VALUES (1, 1, 0);
INSERT [dbo].[Data] ([UID], [ID], [Value]) VALUES (2, 1, 0);
INSERT [dbo].[Data] ([UID], [ID], [Value]) VALUES (3, 1, 1);
INSERT [dbo].[Data] ([UID], [ID], [Value]) VALUES (4, 1, 1);
INSERT [dbo].[Data] ([UID], [ID], [Value]) VALUES (5, 1, 1);
INSERT [dbo].[Data] ([UID], [ID], [Value]) VALUES (6, 1, 0);
INSERT [dbo].[Data] ([UID], [ID], [Value]) VALUES (7, 1, 1);
INSERT [dbo].[Data] ([UID], [ID], [Value]) VALUES (8, 1, 0);
INSERT [dbo].[Data] ([UID], [ID], [Value]) VALUES (9, 1, 0);
INSERT [dbo].[Data] ([UID], [ID], [Value]) VALUES (10, 1, 0);
INSERT [dbo].[Data] ([UID], [ID], [Value]) VALUES (11, 2, 1);
INSERT [dbo].[Data] ([UID], [ID], [Value]) VALUES (12, 2, 1);
INSERT [dbo].[Data] ([UID], [ID], [Value]) VALUES (13, 2, 0);
INSERT [dbo].[Data] ([UID], [ID], [Value]) VALUES (14, 2, 0);
INSERT [dbo].[Data] ([UID], [ID], [Value]) VALUES (15, 2, 1);
I think that the simplest approach to this gaps-and-islands problem is to use lag() to retrieve the "previous" value, and then a window sum that increments everytime the value changes.
select uid, id, value,
1 + sum(case when value <> lag_value then 1 else 0 end)
over(partition by id order by uid) grp
from (
select d.*, lag(value, 1, value) over(partition by id order by uid) lag_value
from data d
) d
order by uid
Demo on DB Fiddle:
uid | id | value | grp
--: | -: | ----: | --:
1 | 1 | 0 | 1
2 | 1 | 0 | 1
3 | 1 | 1 | 2
4 | 1 | 1 | 2
5 | 1 | 1 | 2
6 | 1 | 0 | 3
7 | 1 | 1 | 4
8 | 1 | 0 | 5
9 | 1 | 0 | 5
10 | 1 | 0 | 5
11 | 2 | 1 | 1
12 | 2 | 1 | 1
13 | 2 | 0 | 2
14 | 2 | 0 | 2
15 | 2 | 1 | 3
This is a gaps and islands problem. I think that the simplest approach is to use the difference in row numbers method:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY UID) rn1,
ROW_NUMBER() OVER (PARTITION BY ID, [Value] ORDER BY UID) rn2
FROM Data
)
SELECT *, DENSE_RANK() OVER (PARTITION BY ID ORDER BY rn1 - rn2, [Value]) AS output
FROM cte
ORDER BY UID;
Demo
We need to get the result of the column NEED, need the correlative grouped by the GROUP column in the order of the ORDER column and that increases when the FLAG column changes.
GROUP ORDER FLAG NEED
1111 1 0 1
1111 2 0 1
1111 3 1 2
1111 4 1 2
1111 5 1 2
1111 6 1 2
1111 7 1 2
1111 8 0 3
1111 9 1 4
1111 10 1 4
1111 11 0 5
1111 12 0 5
1111 13 0 5
6666 1 0 1
6666 2 0 1
6666 3 1 2
6666 4 1 2
We try the following code, but we need something cleaner with support for SQL Server 2008
if object_id('tempdb..#temp2','u') is not NULL
drop table #temp2
SELECT *
,ROW_NUMBER() OVER(oRDER BY (SELECT NULL)) RN
INTO #temp2
FROM DBO.PRUEBA​
SELECT T1.*
,SUM(CASE WHEN T1.NUM_GROUP = T2.NUM_GROUP and t1.NUM_FLAG = t2.NUM_FLAG THEN 0 ELSE 1 END) OVER (PARTITION BY T1.NUM_GROUP ORDER BY T1.rn)[Rank]
FROM #temp2 T1
LEFT JOIN #temp2 T2 ON T1.rn = T2.rn+1
order by t1.NUM_GROUP, t1.NUM_ORDER
I share the creation of tables and records
CREATE TABLE DBO.PRUEBA
(
NUM_GROUP INT,
NUM_ORDER INT,
NUM_FLAG INT
)
INSERT INTO DBO.PRUEBA VALUES (1111, 1, 0)
INSERT INTO DBO.PRUEBA VALUES (1111, 2, 0)
INSERT INTO DBO.PRUEBA VALUES (1111, 3, 1)
INSERT INTO DBO.PRUEBA VALUES (1111, 4, 1)
INSERT INTO DBO.PRUEBA VALUES (1111, 5, 1)
INSERT INTO DBO.PRUEBA VALUES (1111, 6, 1)
INSERT INTO DBO.PRUEBA VALUES (1111, 7, 1)
INSERT INTO DBO.PRUEBA VALUES (1111, 8, 0)
INSERT INTO DBO.PRUEBA VALUES (1111, 9, 1)
INSERT INTO DBO.PRUEBA VALUES (1111, 10, 1)
INSERT INTO DBO.PRUEBA VALUES (1111, 11, 0)
INSERT INTO DBO.PRUEBA VALUES (1111, 12, 0)
INSERT INTO DBO.PRUEBA VALUES (1111, 13, 0)
INSERT INTO DBO.PRUEBA VALUES (6666, 1, 0)
INSERT INTO DBO.PRUEBA VALUES (6666, 2, 0)
INSERT INTO DBO.PRUEBA VALUES (6666, 3, 1)
INSERT INTO DBO.PRUEBA VALUES (6666, 4, 1)
SELECT * FROM DBO.PRUEBA
A possible optimalization is to first create the temporary table.
Instead of using a SELECT INTO.
And with a primary key that benefits the self-join that's used to get the previous NUM_FLAG.
CREATE TABLE DBO.PRUEBA
(
NUM_GROUP INT NOT NULL,
NUM_ORDER INT NOT NULL,
NUM_FLAG INT NOT NULL,
PRIMARY KEY (NUM_GROUP, NUM_ORDER)
);
GO
INSERT INTO DBO.PRUEBA
(NUM_GROUP, NUM_ORDER, NUM_FLAG)
VALUES
(1111, 1, 0)
,(1111, 2, 0)
,(1111, 3, 1)
,(1111, 4, 1)
,(1111, 5, 1)
,(1111, 6, 1)
,(1111, 7, 1)
,(1111, 8, 0)
,(1111, 9, 1)
,(1111, 10, 1)
,(1111, 11, 0)
,(1111, 12, 0)
,(1111, 13, 0)
,(6666, 1, 0)
,(6666, 2, 0)
,(6666, 3, 1)
,(6666, 4, 1)
IF OBJECT_ID('tempdb..#tmpPRUEBA', 'U') IS NOT NULL
DROP TABLE #tmpPRUEBA;
CREATE TABLE #tmpPRUEBA
(
NUM_GROUP INT NOT NULL,
RN_GROUP INT NOT NULL,
NUM_ORDER INT NOT NULL,
NUM_FLAG INT NOT NULL,
PRIMARY KEY (NUM_GROUP, RN_GROUP)
);
GO
INSERT INTO #tmpPRUEBA
(NUM_GROUP, NUM_ORDER, NUM_FLAG, RN_GROUP)
SELECT NUM_GROUP, NUM_ORDER, NUM_FLAG
, ROW_NUMBER() OVER (
PARTITION BY NUM_GROUP
ORDER BY NUM_ORDER) AS RN_GROUP
FROM DBO.PRUEBA;
GO
SELECT
t1.NUM_GROUP,
t1.NUM_ORDER,
t1.NUM_FLAG,
SUM(CASE
WHEN t1.NUM_FLAG = t2.NUM_FLAG
THEN 0
ELSE 1
END)
OVER (PARTITION BY t1.NUM_GROUP
ORDER BY t1.RN_GROUP) AS [Rank]
FROM #tmpPRUEBA t1
LEFT JOIN #tmpPRUEBA t2
ON t2.NUM_GROUP = t1.NUM_GROUP
AND t2.RN_GROUP = t1.RN_GROUP - 1;
GO
NUM_GROUP | NUM_ORDER | NUM_FLAG | Rank
--------: | --------: | -------: | ---:
1111 | 1 | 0 | 1
1111 | 2 | 0 | 1
1111 | 3 | 1 | 2
1111 | 4 | 1 | 2
1111 | 5 | 1 | 2
1111 | 6 | 1 | 2
1111 | 7 | 1 | 2
1111 | 8 | 0 | 3
1111 | 9 | 1 | 4
1111 | 10 | 1 | 4
1111 | 11 | 0 | 5
1111 | 12 | 0 | 5
1111 | 13 | 0 | 5
6666 | 1 | 0 | 1
6666 | 2 | 0 | 1
6666 | 3 | 1 | 2
6666 | 4 | 1 | 2
db<>fiddle here
Given the following table
grp | ind | val
----------------------
a | 1 | 1
a | 2 | 1
a | 3 | 1
a | 4 | 2
a | 5 | 2
a | 6 | 4
a | 7 | 2
b | 1 | 1
b | 2 | 1
b | 3 | 1
b | 4 | 3
b | 5 | 3
b | 6 | 4
I need to select the following:
grp | ind | val
----------------------
a | 1 | 1
a | 4 | 2
a | 6 | 4
a | 7 | 2
b | 1 | 1
b | 4 | 3
b | 6 | 4
That is for each 'grp', each record where the 'val' is different to the proceeding 'val' (ordered by 'index') So each record where the 'value' "steps".
what would be the most efficient way to achieve this?
thanks.
Here is a script to create the test case:
create temp table test_table
(
grp character varying,
ind numeric,
val numeric
);
insert into test_table values
('a', 1 , 1),
('a', 2 , 1),
('a', 3 , 1),
('a', 4 , 2),
('a', 5 , 2),
('a', 6 , 4),
('a', 7 , 2),
('b', 1 , 1),
('b', 2 , 1),
('b', 3 , 1),
('b', 4 , 3),
('b', 5 , 3),
('b', 6 , 4);
select grp,
ind,
val
from (
select grp,
ind,
val,
lag(val,1,0::numeric) over (partition by grp order by ind) - val as diff
from test_table
) t
where diff <> 0;
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;
CREATE TABLE ztable
( zgroup CHAR(1)
, zindex int
, zvalue INTEGER
);
INSERT INTO ztable(zgroup,zindex,zvalue) VALUES
('a', 1, 1)
,('a', 2, 1)
,('a', 3, 1)
,('a', 4, 2)
,('a', 5, 2)
,('a', 6, 4)
,('b', 1, 1)
,('b', 2, 1)
,('b', 3, 1)
,('b', 4, 3)
,('b', 5, 3)
,('b', 6, 4)
;
WITH agg AS (
SELECT zgroup
, zindex
, zvalue
, row_number() OVER (PARTITION BY zgroup ORDER BY zindex) AS zrank
FROM ztable
)
SELECT t1.zgroup,t1.zindex,t1.zvalue
FROM agg t1
LEFT JOIN agg t0 ON t0.zgroup = t1.zgroup AND 1+t0.zrank = t1.zrank
WHERE t0.zvalue <> t1.zvalue OR t0.zrank IS NULL
;
select group,min(index) as index,value from table
group by group,value
After getting such a great feedback from my last question. Maybe someone can help me with this problem also.
I have to rotate a given table from an SQL Server but a normal pivot just doesn't work (as far as i tried). So has anybody an idea how to rotate the table into the desired format?
Just to make the problem more complicated, the list of given labels can vary and it is possible that a new label name can come into at any given time.
Given Data
ID | Label | Numerator | Denominator | Ratio
---+-----------------+-------------+---------------+--------
1 | LabelNameOne | 41 | 10 | 4,1
1 | LabelNameTwo | 0 | 0 | 0
1 | LabelNameThree | 21 | 10 | 2,1
1 | LabelNameFour | 15 | 10 | 1,5
2 | LabelNameOne | 19 | 19 | 1
2 | LabelNameTwo | 0 | 0 | 0
2 | LabelNameThree | 15 | 16 | 0,9375
2 | LabelNameFive | 19 | 19 | 1
2 | LabelNameSix | 17 | 17 | 1
3 | LabelNameOne | 12 | 12 | 1
3 | LabelNameTwo | 0 | 0 | 0
3 | LabelNameThree | 11 | 12 | 0,9167
3 | LabelNameFour | 12 | 12 | 1
3 | LabelNameSix | 0 | 1 | 0
Wanted result
ID | LabelNameOneNumerator | LabelNameOneDenominator | LabelNameOneRatio | LabelNameTwoNumerator | LabelNameTwoDenominator | LabelNameTwoRatio | LabelNameThreeNumerator | LabelNameThreeDenominator | LabelNameThreeRatio | ...
---+-----------------------+-------------------------+-------------------+-----------------------+-------------------------+-------------------+-------------------------+---------------------------+---------------------+-----
1 | 41 | 10 | 4,1 | 0 | 0 | 0 | 21 | 10 | 2,1 | ...
2 | 19 | 19 | 1 | 0 | 0 | 0 | 15 | 16 | 0,9375 | ...
3 | 12 | 12 | 1 | 0 | 0 | 0 | 11 | 12 | 0,9167 | ...
I know, after getting such a good answer for my previous question i should be able to solve this problem on myself, but i just can't get my head around this pivot, unpivot part.
Also if you need the sample data in a more SQL way, you can try this one:
DECLARE #src AS TABLE
(
ID int NOT NULL
,Label varchar(14) NOT NULL
,Numerator int NOT NULL
,Denominator int NOT NULL
,Ratio decimal(10, 4) NOT NULL
) ;
INSERT INTO #src
VALUES (1, 'LabelNameOne', 41, 10, 4.1) ;
INSERT INTO #src
VALUES (1, 'LabelNameTwo', 0, 0, 0) ;
INSERT INTO #src
VALUES (1, 'LabelNameThree', 21, 10, 2.1) ;
INSERT INTO #src
VALUES (1, 'LabelNameFour', 15, 10, 1.5) ;
INSERT INTO #src
VALUES (2, 'LabelNameOne', 19, 19, 1) ;
INSERT INTO #src
VALUES (2, 'LabelNameTwo', 0, 0, 0) ;
INSERT INTO #src
VALUES (2, 'LabelNameThree', 15, 16, 0.9375) ;
INSERT INTO #src
VALUES (2, 'LabelNameFive', 19, 19, 1) ;
INSERT INTO #src
VALUES (2, 'LabelNameSix', 17, 17, 1) ;
INSERT INTO #src
VALUES (3, 'LabelNameOne', 12, 12, 1) ;
INSERT INTO #src
VALUES (3, 'LabelNameTwo', 0, 0, 0) ;
INSERT INTO #src
VALUES (3, 'LabelNameThree', 11, 12, 0.9167) ;
INSERT INTO #src
VALUES (3, 'LabelNameFour', 12, 12, 1) ;
INSERT INTO #src
VALUES (3, 'LabelNameSix', 0, 1, 0) ;
You need to combine the labels before the PIVOT. The column list also needs to take account of the cross join of label possibilities:
SET NOCOUNT ON ;
DECLARE #pivot_cols AS varchar(max) ;
DECLARE #src AS TABLE
(
ID int NOT NULL
,Label varchar(14) NOT NULL
,Numerator int NOT NULL
,Denominator int NOT NULL
,Ratio decimal(5, 4) NOT NULL
) ;
DECLARE #label_order AS TABLE
(
Label varchar(14) NOT NULL
,Sort int NOT NULL
)
DECLARE #sub_label_order AS TABLE
(
SubLabel varchar(14) NOT NULL
,Sort int NOT NULL
)
INSERT INTO #src
VALUES (1, 'LabelNameOne', 41, 10, 4.1) ;
INSERT INTO #src
VALUES (1, 'LabelNameTwo', 0, 0, 0) ;
INSERT INTO #src
VALUES (1, 'LabelNameThree', 21, 10, 2.1) ;
INSERT INTO #src
VALUES (1, 'LabelNameFour', 15, 10, 1.5) ;
INSERT INTO #src
VALUES (2, 'LabelNameOne', 19, 19, 1) ;
INSERT INTO #src
VALUES (2, 'LabelNameTwo', 0, 0, 0) ;
INSERT INTO #src
VALUES (2, 'LabelNameThree', 15, 16, 0.9375) ;
INSERT INTO #src
VALUES (2, 'LabelNameFive', 19, 19, 1) ;
INSERT INTO #src
VALUES (2, 'LabelNameSix', 17, 17, 1) ;
INSERT INTO #src
VALUES (3, 'LabelNameOne', 12, 12, 1) ;
INSERT INTO #src
VALUES (3, 'LabelNameTwo', 0, 0, 0) ;
INSERT INTO #src
VALUES (3, 'LabelNameThree', 11, 12, 0.9167) ;
INSERT INTO #src
VALUES (3, 'LabelNameFour', 12, 12, 1) ;
INSERT INTO #src
VALUES (3, 'LabelNameSix', 0, 1, 0) ;
INSERT INTO #label_order
VALUES ('LabelNameOne', 1) ;
INSERT INTO #label_order
VALUES ('LabelNameTwo', 2) ;
INSERT INTO #label_order
VALUES ('LabelNameThree', 3) ;
INSERT INTO #label_order
VALUES ('LabelNameFour', 4) ;
INSERT INTO #label_order
VALUES ('LabelNameFive', 5) ;
INSERT INTO #label_order
VALUES ('LabelNameSix', 6) ;
INSERT INTO #sub_label_order
VALUES ('Numerator', 1) ;
INSERT INTO #sub_label_order
VALUES ('Denominator', 2) ;
INSERT INTO #sub_label_order
VALUES ('Ratio', 3) ;
WITH Labels
AS (
SELECT DISTINCT
src.Label + sublabel.SubLabel AS Label
,ISNULL(label_order.Sort, 0) AS Sort
,ISNULL(sublabel.Sort, 0) AS SubSort
FROM #src AS src
CROSS JOIN #sub_label_order AS sublabel
LEFT JOIN #label_order AS label_order
ON src.label = label_order.label
)
SELECT #pivot_cols = COALESCE(#pivot_cols + ',', '') + QUOTENAME(Label, '[')
FROM Labels
ORDER BY Sort
,SubSort
,Label ;
DECLARE #template AS varchar(max) ;
SET #template = '
DECLARE #src AS TABLE
(
ID int NOT NULL
,Label varchar(14) NOT NULL
,Numerator int NOT NULL
,Denominator int NOT NULL
,Ratio decimal(5, 4) NOT NULL
) ;
INSERT INTO #src
VALUES (1, ''LabelNameOne'', 41, 10, 4.1) ;
INSERT INTO #src
VALUES (1, ''LabelNameTwo'', 0, 0, 0) ;
INSERT INTO #src
VALUES (1, ''LabelNameThree'', 21, 10, 2.1) ;
INSERT INTO #src
VALUES (1, ''LabelNameFour'', 15, 10, 1.5) ;
INSERT INTO #src
VALUES (2, ''LabelNameOne'', 19, 19, 1) ;
INSERT INTO #src
VALUES (2, ''LabelNameTwo'', 0, 0, 0) ;
INSERT INTO #src
VALUES (2, ''LabelNameThree'', 15, 16, 0.9375) ;
INSERT INTO #src
VALUES (2, ''LabelNameFive'', 19, 19, 1) ;
INSERT INTO #src
VALUES (2, ''LabelNameSix'', 17, 17, 1) ;
INSERT INTO #src
VALUES (3, ''LabelNameOne'', 12, 12, 1) ;
INSERT INTO #src
VALUES (3, ''LabelNameTwo'', 0, 0, 0) ;
INSERT INTO #src
VALUES (3, ''LabelNameThree'', 11, 12, 0.9167) ;
INSERT INTO #src
VALUES (3, ''LabelNameFour'', 12, 12, 1) ;
INSERT INTO #src
VALUES (3, ''LabelNameSix'', 0, 1, 0) ;
WITH src_conformed
AS (
SELECT ID
,Label
,CAST (Numerator AS decimal(10, 4)) AS Numerator
,CAST (Denominator AS decimal(10, 4)) AS Denominator
,CAST (Ratio AS decimal(10, 4)) AS Ratio
FROM #src
),
UNPIVOTED
AS (
SELECT *
FROM src_conformed UNPIVOT ( Val FOR Col IN (Numerator, Denominator, Ratio) ) AS unpvt
)
,COMBINED AS (SELECT ID, Label + Col AS NewLabel, Val
FROM UNPIVOTED)
SELECT *
FROM COMBINED PIVOT ( SUM(Val) FOR NewLabel IN ({#pivot_cols}) ) AS pvt
ORDER BY ID ;' ;
SET #template = REPLACE(#template, '{#pivot_cols}', #pivot_cols) ;
EXEC (#template) ;