staircase behavior with pivoted data - sql

Hail to the fellow programmers and query writers,
I have this beautiful query
SELECT ID, [1] AS coL1, [15] AS coL2, [2] AS coL3, [16] AS coL4, [12] AS coL5
FROM MY_TABLE
PIVOT (sum(INT_VALUE) FOR FUND_CODE IN ([1],[2],[15],[16],[12])) AS p
--GROUP BY ID, [1] , [15] , [2] , [16] , [12]
ORDER BY ID ASC
That returns me data like this:
10001 182 NULL NULL NULL
10001 NULL 81 NULL NULL
10001 NULL NULL 182 NULL
10001 NULL NULL NULL 81
10002 165 NULL NULL NULL
10002 NULL 73 NULL NULL
10002 NULL NULL 165 NULL
10002 NULL NULL NULL 73
The 10001 and 10002 are two primary keys, and I'd like to show my data like this:
10001 182 81 182 81
10002 165 73 165 73
I tried this commented GROUP BY to no avail.
Any hints? Does it involve COALESCE?

SELECT ID
,SUM(1) AS 'col1'
,SUM(15) AS 'col2'
,SUM(2) AS 'col3'
,SUM(16) AS 'col4'
,SUM(12) AS 'col5'
FROM Table GROUP BY ID

Just in CASE...
SELECT ID,
SUM(CASE WHEN FUND_CODE = 1 THEN VR_MOVIMENTACAO_QUOTA ELSE 0 END) coL1,
SUM(CASE WHEN FUND_CODE = 15 THEN VR_MOVIMENTACAO_QUOTA ELSE 0 END) coL2,
SUM(CASE WHEN FUND_CODE = 2 THEN VR_MOVIMENTACAO_QUOTA ELSE 0 END) coL3,
SUM(CASE WHEN FUND_CODE = 16 THEN VR_MOVIMENTACAO_QUOTA ELSE 0 END) coL4,
SUM(CASE WHEN FUND_CODE = 12 THEN VR_MOVIMENTACAO_QUOTA ELSE 0 END) coL5
FROM MY_TABLE
GROUP BY ID

Related

Convert Rows to columns with variable number [duplicate]

This question already has answers here:
Group by column and multiple Rows into One Row multiple columns
(2 answers)
Closed 6 months ago.
I have read stuff on pivot tables and I am still having problems getting this correct.
I have a table where column 1 is a Productnr, and column 2 is LHS, column 3 is another Productnr and lastly column 4 is RHS. Also the number of entries of Productnr2 (belonging to Productnr) is variable between 1 and 5. For example, if there are only 3 associated Productnr2 (see article no = 060013 in Productnr) then the last two columns should remain empty.
Productnr LHS Productnr2 RHS
060009 411 099088 5
060013 228 194139 25
060013 228 194141 17
060013 228 175823 75
060022 951 147071 90
060034 424 099088 14
060034 424 102704 88
060034 424 080034 82
060034 424 108436 87
060034 424 108437 58
I would like it to come out as a pivot table, like this:
Productnr | LHS | 1 | RHS | 2 | RHS | 3 | RHS | 4 | RHS | 5 | RHS |
-----
060009 411 099088 5
060013 228 194139 25 194141 17 175823 75
060022 951 147071 90
060034 424 099088 14 102704 88 080034 82 108436 87 108437 58
This can achieve by the following query. But this will work only for five different columns only, if more columns needed then need to increase the case count, but this is not recommended. Better try some dynamic queries for more columns.
CREATE TABLE #temp(Productnr INT, LHS INT, Productnr2 INT, RHS INT)
INSERT INTO #temp VALUES (060009,411,099088,5 )
INSERT INTO #temp VALUES (060013,228,194139,25)
INSERT INTO #temp VALUES (060013,228,194141,17)
INSERT INTO #temp VALUES (060013,228,175823,75)
INSERT INTO #temp VALUES (060022,951,147071,90)
INSERT INTO #temp VALUES (060034,424,099088,14)
INSERT INTO #temp VALUES (060034,424,102704,88)
INSERT INTO #temp VALUES (060034,424,080034,82)
INSERT INTO #temp VALUES (060034,424,108436,87)
INSERT INTO #temp VALUES (060034,424,108437,58)
;WITH CTE AS(
SELECT *
,ROW_NUMBER() OVER(PARTITION BY Productnr ORDER BY Productnr)RN
FROM #temp
)
SELECT Productnr,LHS
,MAX(CASE WHEN RN=1 THEN Productnr2 END) [1]
,MAX(CASE WHEN RN=1 THEN RHS END) [RHS]
,MAX(CASE WHEN RN=2 THEN Productnr2 END) [2]
,MAX(CASE WHEN RN=2 THEN RHS END) [RHS]
,MAX(CASE WHEN RN=3 THEN Productnr2 END) [3]
,MAX(CASE WHEN RN=3 THEN RHS END) [RHS]
,MAX(CASE WHEN RN=4 THEN Productnr2 END) [4]
,MAX(CASE WHEN RN=4 THEN RHS END) [RHS]
,MAX(CASE WHEN RN=5 THEN Productnr2 END) [5]
,MAX(CASE WHEN RN=5 THEN RHS END) [RHS]
FROM CTE
GROUP BY Productnr,LHS
DROP TABLE #temp
Output:
Productnr LHS 1 RHS 2 RHS 3 RHS 4 RHS 5 RHS
----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
60009 411 99088 5 NULL NULL NULL NULL NULL NULL NULL NULL
60013 228 194139 25 194141 17 175823 75 NULL NULL NULL NULL
60022 951 147071 90 NULL NULL NULL NULL NULL NULL NULL NULL
60034 424 99088 14 102704 88 80034 82 108436 87 108437 58

Get custom product selection upon dynamic ID in SQL

I have below table structure and I would like to obtain the result in the following form:
First, this is my item table output:
orderID code action id level description Price solvedChoice
--------------------------------------------------------------------------
321 622 RECIPE 0 0 SPICM1 15.5 NULL
321 10 RECIPE 0 1 SPICKN 17 NULL
321 7091 RECIPE 0 1 RFRY 8.5 NULL
321 521 CHOICE 0 1 R-COKE 7.5 10000003
321 612 RECIPE 1 0 BIGTM1 20.5 NULL
321 13 RECIPE 1 1 BTASTY 21 NULL
321 7091 RECIPE 1 1 RFRY 8.5 NULL
321 522 CHOICE 1 1 R-FANT 7.5 10000003
321 608 RECIPE 2 0 ROYAL1 18.5 NULL
321 11 RECIPE 2 1 MCROYA 18 NULL
321 7091 RECIPE 2 1 RFRY 8.5 NULL
321 411 CHOICE 2 1 ARWA 7.5 10000003
321 612 RECIPE 3 0 BIGTM1 20.5 NULL
321 13 RECIPE 3 1 BTASTY 21 NULL
321 7091 RECIPE 3 1 RFRY 8.5 NULL
321 524 CHOICE 3 1 R-SPRT 7.5 10000003
I want to get what select under each meal, for example id = 0, represent one meal with their sub-level (components) and we can see the choice made was R-Coke while for id =1 , the choice made is R-FANT.
The output should be like this:
R-COKE R-FANT ARWA R-SPRT
--------------------------------------
SPICM1 1 0 0 0
BIGTM1 0 1 0 1
ROYAL1 0 0 1 0
This looks like two levels of aggregation to me:
select col1,
sum(r_coke) as r_coke,
sum(r_fant) as r_fant,
sum(arwa) as arwa,
sum(r_sprt) as r_sprt
from (select max(case when level = 0 then description end) as col1,
sum(case when description = 'R-COKE' then 1 else 0 end) as r_coke,
sum(case when description = 'R-FANT' then 1 else 0 end) as r_fant,
sum(case when description = 'ARWA' then 1 else 0 end) as arwa,
sum(case when description = 'R-SPRT' then 1 else 0 end) as r_sprt
from t
group by id
) x
group by col1;
Or, perhaps more simply, using window functions:
select col1,
sum(case when description = 'R-COKE' then 1 else 0 end) as r_coke,
sum(case when description = 'R-FANT' then 1 else 0 end) as r_fant,
sum(case when description = 'ARWA' then 1 else 0 end) as arwa,
sum(case when description = 'R-SPRT' then 1 else 0 end) as r_sprt
from (select t.*,
max(case when level = 0 then description end) over (partition by id) as col1
from t
) t
group by col1;
Just following input and output provided
select orderID, x, [R-COKE], [R-FANT], [ARWA], [R-SPRT]
from (
select orderID, id
, max(case when level = 0 then description end) x
, max(case when level = 1 and solvedChoice is not null then description end) y
from mytable
group by orderID, id
) t
pivot (count(id) for y in ([R-COKE], [R-FANT], [ARWA], [R-SPRT]) ) pvt;
You could join the table to itself. Something like this
drop TABLE if exists #MyItemTable;
go
CREATE TABLE #MyItemTable
(
orderID INT,
code int,
action char(6),
id int,
level int,
description varchar(10),
price money,
solvedChoice int
)
INSERT INTO #MyItemTable (orderID, code, action, id , level, description, Price, solvedChoice)
VALUES
(321, 622 ,'RECIPE',0,0,'SPICM1',15.5 ,NULL)
,(321, 10 ,'RECIPE',0,1,'SPICKN',17 ,NULL )
,(321, 7091,'RECIPE',0,1,'RFRY ',8.5 ,NULL )
,(321, 521 ,'CHOICE',0,1,'R-COKE',7.5 ,10000003)
,(321, 612 ,'RECIPE',1,0,'BIGTM1',20.5 ,NULL )
,(321, 13 ,'RECIPE',1,1,'BTASTY',21 ,NULL )
,(321, 7091,'RECIPE',1,1,'RFRY ',8.5 ,NULL )
,(321, 522 ,'CHOICE',1,1,'R-FANT',7.5 ,10000003)
,(321, 608 ,'RECIPE',2,0,'ROYAL1',18.5 ,NULL )
,(321, 11 ,'RECIPE',2,1,'MCROYA',18 ,NULL )
,(321, 7091,'RECIPE',2,1,'RFRY ',8.5 ,NULL )
,(321, 411 ,'CHOICE',2,1,'ARWA ',7.5 ,10000003)
,(321, 612 ,'RECIPE',3,0,'BIGTM1',20.5 ,NULL )
,(321, 13 ,'RECIPE',3,1,'BTASTY',21 ,NULL )
,(321, 7091,'RECIPE',3,1,'RFRY ',8.5 ,NULL )
,(321, 524 ,'CHOICE',3,1,'R-SPRT',7.5 ,10000003);
select i.[description],
sum(case when i2.[description] = 'R-COKE' then 1 else 0 end) as r_coke,
sum(case when i2.[description] = 'R-FANT' then 1 else 0 end) as r_fant,
sum(case when i2.[description] = 'ARWA' then 1 else 0 end) as arwa,
sum(case when i2.[description] = 'R-SPRT' then 1 else 0 end) as r_sprt
from #MyItemTable i
left join #MyItemTable i2 on i.id=i2.id
and i2.[action]='CHOICE'
where i.[level]=0
group by i.[description];
description r_coke r_fant arwa r_sprt
BIGTM1 0 1 0 1
ROYAL1 0 0 1 0
SPICM1 1 0 0 0
The aim is to get 1 result for each type of order, that is represented by level=0, id is the order identifier.
You need to first normalize the results by querying the orders and the CHOICE items separately, then you can correlate them with a join.
Once you have identified the spearate order and item records, then we can easily target them with aggregates, in this case a simple COUNT
COUNT works well in this context because it will exclude NULL values.
SELECT [order].description
, COUNT(DISTINCT [order].id) as [Orders]
, COUNT(CASE WHEN item.description = 'R-COKE' THEN 1 END) as [R-COKE]
, COUNT(CASE WHEN item.description = 'R-FANT' THEN 1 END) as [R-FANT]
, COUNT(CASE WHEN item.description = 'ARWA' THEN 1 END) as [ARWA]
, COUNT(CASE WHEN item.description = 'R-SPRT' THEN 1 END) as [R-SPRT]
FROM tblOrders [order]
INNER JOIN tblOrders item ON item.id = [order].id AND item.level = 1
WHERE [order].level = 0
GROUP BY [order].description
Try it out in this fiddle: http://sqlfiddle.com/#!18/81ec5/1
To further highlight the groupings, I have included a count of the separate orders, seeing we are counting the drinks as well.

Get output column for each Key

I have a database with roughly this fields:
SELECT [UserId]
,[MissionId]
,[LevelId]
,[Key]
,[BooleanAnswer]
,[CreationDateTimeUtc]
,[QuestionId]
FROM [Bakman].[dbo].[LevelEntries]
WHERE LevelId = 2 AND QuestionId = 1 OR QuestionId = 2 OR QuestionId = 3 OR QuestionId = 4 OR QuestionId = 5 OR QuestionId = 6
Now I get this kind of output:
UserId MissionId LevelId Key BooleanAnswer CreationDateTimeUtc QuestionId
0 1 2 1 1 2017-10-07 11:39:26.350 1
0 1 2 2 1 2017-10-07 11:39:26.350 1
0 1 2 3 0 2017-10-07 11:39:26.350 1
0 1 2 4 1 2017-10-07 11:39:26.350 1
0 1 2 5 0 2017-10-07 11:39:26.350 1
0 1 2 6 1 2017-10-07 11:39:26.350 1
But now I want to get a column for each QuestionId (which are equal to the [key]).
Like this :
UserId MissionId LevelId Key1 Key2 Key3 Key4 Key5 Key6 CreationDateTimeUtc QuestionId
1 2 1 0 1 1 0 1 1 1 2017-10-07 11:39:26.350 1
Where Key[key] has the boolean awnser and the key belonging to that element.
Good to know is that the Userid + MissionId + LevelId + Key are the Composite key for this table.
EDIT:
Trying both given answers I now get something like this
UserId MissionId LevelId Key1 Key2 Key3 Key4 Key5 Key6
1 1 2 1 NULL NULL NULL NULL NULL
1 1 2 NULL 1 NULL NULL NULL NULL
1 1 2 NULL NULL 0 NULL NULL NULL
1 1 2 NULL NULL NULL 1 NULL NULL
1 1 2 NULL NULL NULL NULL 1 NULL
1 1 2 NULL NULL NULL NULL NULL 1
Now I want to combine those so I get the level result of the user.
Try the following query
SELECT
UserId,
MissionId,
LevelId,
MAX(CASE WHEN [Key]=1 THEN BooleanAnswer END) Key1,
MAX(CASE WHEN [Key]=2 THEN BooleanAnswer END) Key2,
MAX(CASE WHEN [Key]=3 THEN BooleanAnswer END) Key3,
MAX(CASE WHEN [Key]=4 THEN BooleanAnswer END) Key4,
MAX(CASE WHEN [Key]=5 THEN BooleanAnswer END) Key5,
MAX(CASE WHEN [Key]=6 THEN BooleanAnswer END) Key6,
CreationDateTimeUtc,
QuestionId
FROM LevelEntries
WHERE LevelId=2
AND QuestionId IN(1,2,3,4,5,6)
GROUP BY UserId,MissionId,LevelId,CreationDateTimeUtc,QuestionId
The second variant
SELECT
UserId,
MissionId,
LevelId,
MAX(CASE WHEN [Key]=1 THEN BooleanAnswer END) Key1,
MAX(CASE WHEN [Key]=2 THEN BooleanAnswer END) Key2,
MAX(CASE WHEN [Key]=3 THEN BooleanAnswer END) Key3,
MAX(CASE WHEN [Key]=4 THEN BooleanAnswer END) Key4,
MAX(CASE WHEN [Key]=5 THEN BooleanAnswer END) Key5,
MAX(CASE WHEN [Key]=6 THEN BooleanAnswer END) Key6,
MAX(CreationDateTimeUtc) MaxCreationDateTimeUtc,
QuestionId
FROM LevelEntries
WHERE LevelId=2
AND QuestionId IN(1,2,3,4,5,6)
GROUP BY UserId,MissionId,LevelId,QuestionId
You can use PIVOT for that purpose.
with Entries as
(
select UserId,
MissionId,
LevelId,
'Key' + cast([Key] as varchar) as [Key],
BooleanAnswer,
CreationDateTimeUtc,
QuestionId
from [Bakman].[dbo].[LevelEntries]
where LevelId = 2 and QuestionId in (1, 2, 3, 4, 5, 6)
)
select UserId,
MissionId,
LevelId,
Key1,
Key2,
Key3,
Key4,
Key5,
Key6,
CreationDateTimeUtc,
QuestionId
from Entries t
pivot
(
max(BooleanAnswer)
for [Key] in (Key1, Key2, Key3, Key4, Key5, Key6)
) p;

SUM subcategory into one

I am looking at add a date range to the below query. Any help would be fantastic thank you in advance.
select (case when col2 in ('Commercial', 'Non-commercial') then 'Commercial'
when col2 in ('OEM', 'CA-OEM') then 'OEM'
else 'col2'
end),
sum(col4) as col4
from t
group by (case when col2 in ('Commercial', 'Non-commercial') then 'Commercial'
when col2 in ('OEM', 'CA-OEM') then 'OEM'
else 'col2'
end);
The date is shown as below in SQL
SELECT Customer_type,TRX_DATE (FORMAT 'YYYY-MM') (CHAR(7)) AS BATCH_DATE_MONTH
WHERE CAST(TRX_DATE AS DATE FORMAT 'mm/dd/yyyy') >= '02-01-2016'
Group BY 1,2
ORDER BY 1
Customer_Type BATCH_DATE_MONTH Number_Invoices Billed_Amount
1 Commercial-Non-OEM 2016-02 48 382458.92
2 Commercial- Non-OEM 2016-05 77 7646263.67
5 Non-OEM 2016-05 81 11841927.23
6 Non-OEM 2016-02 25 1630832.81
9 OEM 2016-04 68 280264011.01
10 OEM 2016-03 74 277606302.23
13 CA-OEM 2016-03 23 947248.13
14 CA-OEM 2016-05 17 420363.61
17 US-OEM 2016-04 35 4627887.87
18 US-OEM 2016-03 40 6450226.49
19 US-OEM 2016-02 21 3267732.17
You can use an aggregation query with case:
select (case when col2 in ('Commercial', 'Non-commercial') then 'Commercial'
when col2 in ('OEM', 'CA-OEM') then 'OEM'
else 'col2'
end),
sum(col4) as col4
from t
group by (case when col2 in ('Commercial', 'Non-commercial') then 'Commercial'
when col2 in ('OEM', 'CA-OEM') then 'OEM'
else 'col2'
end);

How to pivot based on two column

i have a table as follows
and my expected output is as follows.
SQL Fiddle for this problem
In expected output ,it need to be pivoted by combination of id & date .
How can i solve this problem ?
There is not any PIVOT function in sql lite. Which the link that you have supplied leads to. But you could do this:
SELECT
yourtable.Id,
yourtable.Date,
MAX(CASE WHEN [Type]=1 THEN [Value] ELSE NULL END) AS [1],
MAX(CASE WHEN [Type]=2 THEN [Value] ELSE NULL END) AS [2],
MAX(CASE WHEN [Type]=3 THEN [Value] ELSE NULL END) AS [3]
FROM
yourtable
GROUP BY
yourtable.Id,
yourtable.Date
If you want to do it with an pivot and are using MSSQL 2012. Then you can do this:
SELECT
*
FROM
(
SELECT
yourtable.Id,
yourtable.Date,
yourtable.Type,
yourtable.Value
FROM
yourtable
) AS sourceTable
PIVOT
(
MAX(Value)
FOR Type IN([1],[2],[3],[4])
) AS pvt
This will result in this:
1 2014-04-01 00:00:00.000 23 NULL NULL NULL
2 2014-04-01 00:00:00.000 56 NULL NULL NULL
3 2014-04-01 00:00:00.000 12 78 NULL NULL
2 2014-07-01 00:00:00.000 56 NULL NULL NULL
3 2014-07-01 00:00:00.000 12 78 33 NULL