I have some sample data as follows;
col_1 | col_2 | val_1 | val_2
----------------------------
TPEB| SMB | 12.0 | 12.7
FEWB | ENT | 13 | 10
The goal is to get output as follows;
Expected Output
dimension | dimension_value | val_1 | val_2
[col_1,col_2] | [TPEB,SMB] | 12.0 | 12.7
[col_1,col_2] | [FEWB,ENT] | 13 | 10
As we can see, we need to get column names as values as well as concatenated here.
In my knowledge some sort of unpivoting may help. Here is my attempt.
select *
from table
unpivot (slice_value for slice_name in (col_1, col_2));
This will give following output as expected;
slice_name | slice_value | val_1 | val_2
col_1 | TPEB | 12.0 | 12.7
col_2 | SMB | 12.0 | 12.7
col_1 | FEWB | 13 | 10
col_2 | ENT | 13 | 10
Can I please get some help on how to implement the concatenation as we're looking for in snowflake dialect?
Fixed Answer:
So the example you show is not, unpivot, as the 2 value column width is still preserved.
it's just this SQL:
select
'[col_1,col_2]' as dimension,
'['||col_1||','||col_2||']' as dimension_value ,
val_1, val_2
from data as d
order by 1;
thus with data:
with data(col_1, col_2, val_1, val_2) as (
select * from values
('TPEB', 'SMB', 12.0, 12.7),
('FEWB', 'ENT', 13 , 10)
)
gives:
DIMENSION
DIMENSION_VALUE
VAL_1
VAL_2
[col_1,col_2]
[TPEB,SMB]
12
12.7
[col_1,col_2]
[FEWB,ENT]
13
10
Or using ARRAY_CONSTRUCT:
select
array_construct('col_1','col_2') as dimension,
array_construct(col_1,col_2) as dimension_value ,
val_1, val_2
from data as d
order by 1;
gives:
DIMENSION
DIMENSION_VALUE
VAL_1
VAL_2
[ "col_1", "col_2" ]
[ "TPEB", "SMB" ]
12
12.7
[ "col_1", "col_2" ]
[ "FEWB", "ENT" ]
13
10
And if you want to use UNPIVOT as your base, ARRAY_AGG:
with data(col_1, col_2, val_1, val_2) as (
select * from values
('TPEB', 'SMB', 12.0, 12.7),
('FEWB', 'ENT', 13 , 10)
)
select
array_agg(slice_name) as dimension
,array_agg(slice_value) as dimension_value
,val_1
,val_2
from data
unpivot (slice_value for slice_name in (col_1, col_2))
group by 3,4
order by 1;
gives:
DIMENSION
DIMENSION_VALUE
VAL_1
VAL_2
[ "COL_1", "COL_2" ]
[ "TPEB", "SMB" ]
12
12.7
[ "COL_1", "COL_2" ]
[ "FEWB", "ENT" ]
13
10
and if you want those arrays as strings ARRAY_TO_STRING:
select
array_to_string(array_agg(slice_name), ',') as dimension
,array_to_string(array_agg(slice_value), ',') as dimension_value
,val_1
,val_2
from data
unpivot (slice_value for slice_name in (col_1, col_2))
group by 3,4
order by 1;
DIMENSION
DIMENSION_VALUE
VAL_1 VAL_2
COL_1,COL_2
TPEB,SMB
12
COL_1,COL_2
FEWB,ENT
13
Or you can directly transform in string space with LISTAGG
select
LISTAGG(slice_name, ',') as dimension
,LISTAGG(slice_value, ',') as dimension_value
,val_1
,val_2
from data
unpivot (slice_value for slice_name in (col_1, col_2))
group by 3,4
order by 1,2;
If you're willing to hardcode column names, isn't it easier done with union all?
select 'col_1' as slice_name, col_1 as slice_value, val_1, val_2
from t
union all
select 'col_2', col_2, val_1, val_2
from t
Related
What is the most efficient method to combine multiple rows of values with the same ID in SQL Server?
Original data table dbo.ProductCategory:
+-----------+----------+------+
| ProductID | CATID | AA |
+-----------+----------+------+
| 1 | 123 | A |
| 1 | 412 | B |
| 2 | 567 | C |
| 2 | 521 | A |
| 3 | 2 | D |
| 3 | 5 | A |
| 4 | 6 | C |
| 4 | 8 | E |
| 4 | 123 | A |
+----+------+----------+------+
And I'm trying to achieve the following result
+-----------+----------+------+
| ProductID | CATID | AA |
+-----------+----------+------+
| 1 | 123,412 | A,B |
| 2 | 567,521 | C,A |
| 3 | 2,5 | D,A |
| 4 | 6,8,123 | C,E,A|
+----+------+----------+------+
In SQL Server 2017+, you can use STRING_AGG
select ProductId, STRING_AGG(CATID, ',') as CATID, STRING_AGG(AA, ',') AA
from PC
GROUP BY ProductID
Sample Data
DECLARE #Temp AS TABLE (ProductID INT, CATID INT, AA CHAR(2))
INSERT INTO #Temp
SELECT 1 , 123 , 'A' UNION ALL
SELECT 1 , 412 , 'B' UNION ALL
SELECT 2 , 567 , 'C' UNION ALL
SELECT 2 , 521 , 'A' UNION ALL
SELECT 3 , 2 , 'D' UNION ALL
SELECT 3 , 5 , 'A' UNION ALL
SELECT 4 , 6 , 'C' UNION ALL
SELECT 4 , 8 , 'E' UNION ALL
SELECT 4 , 123 , 'A'
Using STUFF() In sql server
SELECT ProductID,STUFF((SELECT CONCAT(', ', CATID)
FROM #Temp i
WHERE i.ProductID = o.ProductID
FOR XML PATH ('')),1,1,'') AS CATID
,STUFF((SELECT CONCAT(', ', AA)
FROM #Temp i
WHERE i.ProductID = o.ProductID
FOR XML PATH ('')),1,1,'') AS AA
FROM #Temp o
GROUP BY ProductID
Result
ProductID CATID AA
------------------------------------
1 123, 412 A , B
2 567, 521 C , A
3 2, 5 D , A
4 6, 8, 123 C , E , A
I have a string that consists of a name and in most cases it has a postfix with one or two numbers at the end. This number-postfix should be cut off from the name. One number represents a status and should be extracted. If there are two numbers it is the seconde from the right, if there is one number it is the first from the right. These numbers are seperated by an underscore. Underscores can also be used within the name.
The result should be a column with the clearname and the extracted status.
I tried to solve the problem with the standard string functions like Substring, Charindex, Patindex, LEN and son on. But my approach became very bulky quickly and hard to maintain. I wonder if there is an elegant solution with the usual SQl-Server capabilities (if possible without installing extras for regex).
SELECT _data.myStr
-- , ... AS clearname /*String cleaned from number_postfixes*/
-- , ... AS Status /*second number from the right*/
FROM (
SELECT 'tree_leafs_offer_2_1' AS myStr --clearname: tree_leafs_offer; cut off: _2_1; extracted status: 2
UNION
SELECT 'tree_leafs_offer_2_10' AS myStr --clearname: tree_leafs_offer_2_10; cut off: _2_10; extracted status: 2
UNION
SELECT 'tree_leafs_offer_2_2' AS myStr --clearname: tree_leafs_offer; cut off: _2_2; extracted status: 2
UNION
SELECT 'tree_leafs_offer_1150_1' AS myStr --clearname: tree_leafs_offer; cut off: _1150_1; extracted status: 1150
UNION
SELECT 'tree_leafs_offer_1150_10' AS myStr --clearname: tree_leafs_offer; cut off: _1150_10; extracted status: 1150
UNION
SELECT 'builder_bundle_less_xl_1' AS myStr --clearname: builder_bundle_less_xl; cut off: _1; extracted status: 1
UNION
SELECT 'builder_bundle_less_xl_10' AS myStr --clearname: builder_bundle_less_xl; cut off: _10; extracted status: 10
UNION
SELECT 'static_components_wolves_10_4' AS myStr --clearname: static_components_wolves; cut off: _10_4; extracted status: 4
UNION
SELECT 'coke_0_boring_components_bundle_grant_1' AS myStr --clearname: oke_0_boring_components_bundle_grant; cut off: _1; extracted status: 1
UNION
SELECT 'coke_0_soccer18_end_1_4h_101' AS myStr --clearname: coke_0_soccer18_end_1_4h; cut off: _101; extracted status: 101
UNION
SELECT 'coke_0_late_downsell_bundle_high_114' AS myStr --clearname: coke_0_late_downsell_bundle_high; cut off: _114; extracted status: 114
UNION
SELECT 'itembundle_mine_bundle_small' AS myStr --clearname: itembundle_mine_bundle_small; cut off: <nothing>; extracted status: NULL
) AS _data
As-Is Result:
-----------------
myStr:
---------------------------------------
builder_bundle_less_xl_1
builder_bundle_less_xl_10
coke_0_boring_components_bundle_grant_1
coke_0_late_downsell_bundle_high_114
coke_0_soccer18_end_1_4h_101
itembundle_mine_bundle_small
static_components_wolves_10_4
tree_leafs_offer_1150_1
tree_leafs_offer_1150_10
tree_leafs_offer_2_1
tree_leafs_offer_2_10
tree_leafs_offer_2_2
To-Be Result (two new columns):
-------------------
clearname: |Status
----------------------------------------------
builder_bundle_less_xl | 1
builder_bundle_less_xl | 10
coke_0_boring_components_bundle_grant | 1
coke_0_late_downsell_bundle_high | 114
coke_0_soccer18_end_1_4h | 101
itembundle_mine_bundle_small |NULL
static_components_wolves | 10
tree_leafs_offer |1150
tree_leafs_offer |1150
tree_leafs_offer | 2
tree_leafs_offer | 2
tree_leafs_offer | 2
To be honest: this format is awful! If this is not a one-time-action you really should try to change this before you have to deal with it.
But - if you have to stick with this - you might give this a try:
EDIT: resolved a bad computation of the status position...
DECLARE #tbl TABLE(ID INT IDENTITY,myStr VARCHAR(1000));
INSERT INTO #tbl VALUES
('tree_leafs_offer_2_1')
,('tree_leafs_offer_2_10')
,('tree_leafs_offer_2_2')
,('tree_leafs_offer_1150_1')
,('tree_leafs_offer_1150_10')
,('builder_bundle_less_xl_1')
,('builder_bundle_less_xl_10')
,('static_components_wolves_10_4')
,('coke_0_boring_components_bundle_grant_1')
,('coke_0_soccer18_end_1_4h_101')
,('coke_0_late_downsell_bundle_high_114')
,('itembundle_mine_bundle_small');
The query
WITH cte AS
(
SELECT t.ID
,t.myStr
,A.[key] AS Position
,A.[value] AS WordFragment
,B.CastedToInt
FROM #tbl t
CROSS APPLY OPENJSON(N'["' + REPLACE(t.myStr,'_','","') + '"]') A
CROSS APPLY(SELECT TRY_CAST(A.[value] AS INT)) B(CastedToInt)
)
SELECT ID
,myStr
,STUFF(
(SELECT CONCAT('_',cte2.WordFragment)
FROM cte cte2
WHERE cte2.ID=cte.ID
AND cte2.Position<=A.PositionHighestNonInt
ORDER BY cte2.Position
FOR XML PATH('')
),1,1,'') AS ClearName
,(SELECT cte3.CastedToInt FROM cte cte3 WHERE cte3.ID=cte.ID AND cte3.Position=A.PositionHighestNonInt+1) AS [Status]
FROM cte
CROSS APPLY (
SELECT ISNULL(MAX(x.Position),1000)
FROM cte x
WHERE x.ID=cte.ID AND x.CastedToInt IS NULL
) A(PositionHighestNonInt)
GROUP BY ID,myStr,PositionHighestNonInt;
The result
+----+---------------------------------------+--------+
| ID | ClearName | Status |
+----+---------------------------------------+--------+
| 1 | tree_leafs_offer | 2 |
+----+---------------------------------------+--------+
| 2 | tree_leafs_offer | 2 |
+----+---------------------------------------+--------+
| 3 | tree_leafs_offer | 2 |
+----+---------------------------------------+--------+
| 4 | tree_leafs_offer | 1150 |
+----+---------------------------------------+--------+
| 5 | tree_leafs_offer | 1150 |
+----+---------------------------------------+--------+
| 6 | builder_bundle_less_xl | 1 |
+----+---------------------------------------+--------+
| 7 | builder_bundle_less_xl | 10 |
+----+---------------------------------------+--------+
| 8 | static_components_wolves | 10 |
+----+---------------------------------------+--------+
| 9 | coke_0_boring_components_bundle_grant | 1 |
+----+---------------------------------------+--------+
| 10 | coke_0_soccer18_end_1_4h | 101 |
+----+---------------------------------------+--------+
| 11 | coke_0_late_downsell_bundle_high | 114 |
+----+---------------------------------------+--------+
| 12 | itembundle_mine_bundle_small | NULL |
+----+---------------------------------------+--------+
The idea:
Provide your data in a mockup table
Use a trick with OPENJSON to get the string split and find parts which can be cast to INT.
Find the highest non-int fragment. The Status will be the next index
With v2017 you could use STRING_AGG, but with v2016 we have to use a XML-based trick to concatenate all fragments before the [Status].
One possible approach is to use string replacement and JSON capabilities of SQL Server 2016+. Each row is reversed and transformed into a valid JSON array ('tree_leafs_offer_2_1' is transformed into '["1","2","reffo","sfael","eert"]' for example). Then you can easily check if the first and the second items are valid numbers using JSON_VALUE(<json_array>, '$[0]'), JSON_VALUE(<json_array>, '$[1]') and TRY_CONVERT(). This will work if you have maximum two numbers from the right.
Input:
CREATE TABLE #Data (
myStr varchar(max)
)
INSERT INTO #Data
(MyStr)
VALUES
('tree_leafs_offer_2_1'),
('tree_leafs_offer_2_10'),
('tree_leafs_offer_2_2'),
('tree_leafs_offer_1150_1'),
('tree_leafs_offer_1150_10'),
('builder_bundle_less_xl_1'),
('builder_bundle_less_xl_10'),
('static_components_wolves_10_4'),
('coke_0_boring_components_bundle_grant_1'),
('coke_0_soccer18_end_1_4h_101'),
('coke_0_late_downsell_bundle_high_114'),
('itembundle_mine_bundle_small')
T-SQL:
SELECT
LEFT(myStr, LEN(myStr) - CHARINDEX('_', REVERSE(myStr))) as ClearName,
REVERSE(LEFT(REVERSE(myStr), CHARINDEX('_', REVERSE(myStr)) - 1)) AS Status
FROM (
SELECT
CASE
WHEN
TRY_CONVERT(int, REVERSE(JSON_VALUE(CONCAT('["', REPLACE(STRING_ESCAPE(REVERSE(MyStr), 'json'), '_', '","'), '"]'), '$[1]'))) IS NULL AND
TRY_CONVERT(int, REVERSE(JSON_VALUE(CONCAT('["', REPLACE(STRING_ESCAPE(REVERSE(MyStr), 'json'), '_', '","'), '"]'), '$[0]'))) IS NULL
THEN CONCAT(myStr, '_0')
WHEN
TRY_CONVERT(int, REVERSE(JSON_VALUE(CONCAT('["', REPLACE(STRING_ESCAPE(REVERSE(MyStr), 'json'), '_', '","'), '"]'), '$[1]'))) IS NULL AND
TRY_CONVERT(int, REVERSE(JSON_VALUE(CONCAT('["', REPLACE(STRING_ESCAPE(REVERSE(MyStr), 'json'), '_', '","'), '"]'), '$[0]'))) IS NOT NULL
THEN MyStr
ELSE LEFT(myStr, LEN(myStr) - CHARINDEX('_', REVERSE(myStr)))
END AS myStr
FROM #Data
) fixed
ORDER BY MyStr
Output:
----------------------------------------------
ClearName Status
----------------------------------------------
builder_bundle_less_xl 1
builder_bundle_less_xl 10
coke_0_boring_components_bundle_grant 1
coke_0_late_downsell_bundle_high 114
coke_0_soccer18_end_1_4h 101
itembundle_mine_bundle_small 0
static_components_wolves 10
tree_leafs_offer 1150
tree_leafs_offer 1150
tree_leafs_offer 2
tree_leafs_offer 2
tree_leafs_offer 2
I cannot summarize numbers in the table (SQL-Server) after pivoting and I will be very grateful for your advice.
Better if I explain the problem on the example:
Existing table:
+-------+-----------+-----------+-------------------+
| # | $$$$$ | Fire | Water |
+-------+-----------+-----------+-------------------+
| 1 | 5 | 1 | 5 |
| 1 | 4 | 1 | 5 |
| 1 | 10 | 1 | 5 |
| 2 | 3 | 3 | 8 |
| 2 | 4 | 3 | 8 |
+-------+-----------+-----------+-------------------+
Desired output:
+-------+-----------+-----------+-------------------+
| # | $$$$$ | Fire | Water |
+-------+-----------+-----------+-------------------+
| 1 | 19 | 1 | 5 |
| 2 | 7 | 3 | 8 |
+-------+-----------+-----------+-------------------+
I tend to believe that I already tried all the solutions I found with summarizing and grouping by, but it was not solved, so I rely on you. Thanks in advance. The code I used to create the table:
WITH Enerc AS
(
SELECT
a1.[#],
a1.[$$$$$],
a2.[cause_of_loss]
FROM
data1 AS a1
LEFT JOIN
data2 AS a2 ON a1.[id] = a2.[id]
)
SELECT *
FROM Enerc
PIVOT
(SUM(gross_claim) FOR [cause_of_loss] IN ([Fire], [Water])) AS PivotTable;
No need to pivot. Your desired result should be got by grouping and using SUM:
SELECT
a1.[#],
SUM(a1.[$$$$$]),
a1.[Fire]
a1.[Water]
from data1 as a1
group by a1.[#], a1.[Fire], a1.[Water]
Let me show an example:
DECLARE #Hello TABLE
(
[#] INT,
[$$$$$] INT,
[Fire] INT,
[Water] INT
)
INSERT INTO #Hello
(
#,
[$$$$$],
Fire,
Water
)
VALUES
( 1, -- # - int
5, -- $$$$$ - int
1, -- Fire - int
5 -- Water - int
)
, (1, 4, 1, 5)
, (1, 10, 1, 5)
, (2, 3, 3, 8)
, (2, 4, 3, 8)
SELECT
h.#,
SUM(h.[$$$$$]),
h.Fire,
h.Water
FROM #Hello h
GROUP BY h.#, h.Fire, h.Water
try group by after the pivot.
With Enerc as
(SELECT
a1.[#],
a1.[$$$$$],
a2.[cause_of_loss]
from data1 as a1
left join data2 as a2
on a1.[id] = a2.[id]
)
select *
into tmp
from Enerc
PIVOT
(sum(gross_claim)
FOR [cause_of_loss] in (
[Fire], [Water]))
as PivotTable
select [#], sum([$$$$$])as [$$$$$], Fire, Water
from #tmp
group by [#],Fire, Water
EDIT: in case of permission denied:
With Enerc as
(SELECT
a1.[#],
a1.[$$$$$],
a2.[cause_of_loss]
from data1 as a1
left join data2 as a2
on a1.[id] = a2.[id]
),phase2 as(
select *
from Enerc
PIVOT
(sum(gross_claim)
FOR [cause_of_loss] in (
[Fire], [Water]))
as PivotTable)
select [#], sum([$$$$$])as [$$$$$], Fire, Water
from phase2
group by [#],Fire, Water
I have a table with the following format
YEAR, MONTH, ITEM, REQ_QTY1, REQ_QTY2 , ....REQ_QTY31 ,CONVERTED1, CONVERTED2 ....CONVERTED31
Where the suffix of each column is the day of the month.
I need to convert it to the following format, where Day_of_month is the numeric suffix of each column
YEAR, MONTH, DAY_OF_MONTH, ITEM, REQ_QTY, CONVERTED
I thought of using CROSS APPLY to retrieve the data, but I can't use CROSS APPLY to get the "Day of Month"
SELECT A.YEAR, A.MONTH, A.ITEM, B.REQ_QTY, B.CONVERTED
FROM TEST A
CROSS APPLY
(VALUES
(REQ_QTY1, CONVERTED1),
(REQ_QTY2, CONVERTED2),
(REQ_QTY3, CONVERTED3),
......
(REQ_QTY31, CONVERTED31)
)B (REQ_QTY, CONVERTED)
The only way I found is to use a nested select with inner join
SELECT A.YEAR, A.MONTH, A.DAY_OF_MONTH, A.ITEM,A.REQ_QTY, D.CONVERTED FROM
(SELECT YEAR, MONTH, ITEM, SUBSTRING(DAY_OF_MONTH,8,2) AS DAY_OF_MONTH, REQ_QTY FROM TEST
UNPIVOT
(REQ_QTY FOR DAY_OF_MONTH IN ([REQ_QTY1],[REQ_QTY2],[REQ_QTY3],......[REQ_QTY30],[REQ_QTY31])
) B
) A
INNER JOIN (SELECT YEAR, MONTH, ITEM, SUBSTRING(DAY_OF_MONTH,10,2) AS DAY_OF_MONTH, CONVERTED FROM TEST
UNPIVOT
(CONVERTED FOR DAY_OF_MONTH IN ([CONVERTED1],[CONVERTED2],[CONVERTED3],....[CONVERTED30],[CONVERTED31])
) C
) D
ON D.YEAR = A.YEAR AND D.MONTH = A.MONTH AND D.ITEM = A.ITEM AND D.DAY_OF_MONTH = A.DAY_OF_MONTH
Is there a way to use CROSS APPLY and yet get the DAY_OF_MONTH out?
This is not a solution with CROSS APPLY but it will definitely make it a bit faster as it uses a bit simpler approach and simpler execution plan.
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE Test_Table([YEAR] INT, [MONTH] INT, [ITEM] INT, REQ_QTY1 INT
, REQ_QTY2 INT ,REQ_QTY3 INT , CONVERTED1 INT, CONVERTED2 INT, CONVERTED3 INT)
INSERT INTO Test_Table VALUES
( 2015 , 1 , 1 , 10 , 20 , 30 , 100 , 200 , 300),
( 2015 , 2 , 1 , 10 , 20 , 30 , 100 , 200 , 300),
( 2015 , 3 , 1 , 10 , 20 , 30 , 100 , 200 , 300)
Query 1:
SELECT *
FROM
(
SELECT [YEAR]
,[MONTH]
,ITEM
,Vals
,CASE WHEN LEFT(N,3) = 'REQ' THEN SUBSTRING(N,8 ,2)
WHEN LEFT(N,3) = 'CON' THEN SUBSTRING(N,10,2)
END AS Day_Of_Month
,CASE WHEN LEFT(N,3) = 'REQ' THEN LEFT(N,7)
WHEN LEFT(N,3) = 'CON' THEN LEFT(N,9)
END AS Tran_Type
FROM Test_Table t
UNPIVOT (Vals FOR N IN ([REQ_QTY1],[REQ_QTY2],[REQ_QTY3],
[CONVERTED1],[CONVERTED2],[CONVERTED3]))up
)t2
PIVOT (SUM(Vals)
FOR Tran_Type
IN (REQ_QTY, CONVERTED))p
Results:
| YEAR | MONTH | ITEM | Day_Of_Month | REQ_QTY | CONVERTED |
|------|-------|------|--------------|---------|-----------|
| 2015 | 1 | 1 | 1 | 10 | 100 |
| 2015 | 1 | 1 | 2 | 20 | 200 |
| 2015 | 1 | 1 | 3 | 30 | 300 |
| 2015 | 2 | 1 | 1 | 10 | 100 |
| 2015 | 2 | 1 | 2 | 20 | 200 |
| 2015 | 2 | 1 | 3 | 30 | 300 |
| 2015 | 3 | 1 | 1 | 10 | 100 |
| 2015 | 3 | 1 | 2 | 20 | 200 |
| 2015 | 3 | 1 | 3 | 30 | 300 |
Well, I found a way using CROSS APPLY, but instead of taking a substring, I'm basically hardcoding the days. Works well enough so...
SELECT A.YEAR, A.MONTH, A.ITEM, B.DAY_OF_MONTH, B.REQ_QTY, B.CONVERTED
FROM TEST A
CROSS APPLY
(
VALUES
('01', REQ_QTY1, CONVERTED1),
('02', REQ_QTY2, CONVERTED2),
('03', REQ_QTY3, CONVERTED3),
('04', REQ_QTY4, CONVERTED4),
......
('31', REQ_QTY31, CONVERTED31)
) B (DAY_OF_MONTH, REQ_QTY, CONVERTED)
I can't seem to get my head around this problem where I think I need a combination of pivot and unpivot in SQL Server 2008:
I have a table as follows:
Sale | Month | Count | Budgeted | Actual
------------------------------------------------
NewSale | 1 | 120 | 45.23 | 50.10
NewSale | 2 | 30 | 3.10 | 1.2
NewSale | 3 | 70 | 45.00 | 100.32
I need to pivot so that the months are as columns, but unpivot so I get the Count, Budgeted, Actual as rows, so it is like so...
Type | 1 | 2 | 3
-----------------------------------
Count | 120 | 30 | 70
Budgeted | 45.23 | 3.10 | 45.00
Actual | 50.10 | 1.2 | 100.32
I've tried this so far, but I can't work out how to put the pivot in there:
select
*
from YTD
pivot
(
sum([Count]), sum([Budgeted]), sum([Actual])
for [Month] in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
)
as figures
This gives me a syntax error as you can't have more than one calculation in the pivot (as far as what I understood from the error.
Help!!!
declare #T table
(
Sale varchar(10),
[Month] int,
[Count] int,
Budgeted money,
Actual money
)
insert into #T values
('NewSale', 1, 120, 45.23, 50.10),
('NewSale', 2, 30, 3.10, 1.2),
('NewSale', 3, 70, 45.00, 100.32)
select [Type], [1], [2], [3]
from
(
select [Month],
cast([Count] as money) as [Count],
Budgeted,
Actual
from #T
) as T
unpivot
(
Value for [Type] in ([Count], Budgeted, Actual)
) as U
pivot
(
sum(Value) for [Month] in ([1], [2], [3])
) as P
Try on SE-Data.
You need to do 3 selects and union the result to get a table that looks like that.
For example
Select 'Count' as [Type], 120 AS 1, 40 AS 2, 70 AS 3
UNION ALL
Select 'Budgeted' as [Type], 45.23 AS 1, 3.10 AS 2, 45.00 AS 3
UNION ALL
Select 'Actual' as [Type], 50.1 AS 1, 1.2 AS 2, 100.32 AS 3
Will look like your example
So just replace each of those selects with a piviot that returns the row you want and you GTG