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.
I've just got myself stuck with some SQL query and I'm quite new on this.
I'm using pivot in my query.
This is my SELECT query:
SELECT *
FROM
(SELECT lg.domainNameID AS [Domain ID], COUNT(lg.domainNameID) AS [Fix Count]
FROM tbl_ATT_Request r
INNER JOIN tbl_ATT_Login lg ON lg.workdayID = r.workdayID
WHERE r.requestCategoryID = 1
GROUP BY lg.domainNameID) slct
and this is the output:
Domain | Fix Count
-------+-----------
1 1
2 1
4 2
5 1
And this is my query with PIVOT.
SELECT *
FROM
(SELECT lg.domainNameID AS [Domain ID], COUNT(lg.domainNameID) AS [Fix Count]
FROM tbl_ATT_Request r
INNER JOIN tbl_ATT_Login lg ON lg.workdayID = r.workdayID
WHERE r.requestCategoryID = 1
GROUP BY lg.domainNameID) slct
PIVOT
(SUM(slct.[Fix Count])
FOR slct.[Domain ID] IN ([1],[2],[3],[4],[5])
) AS pvt
This is the output:
1 | 2 | 3 | 4 | 5
1 1 NULL 2 1
Now my problem is how can I replace the NULL values with 0.
Just use conditional aggregation:
SELECT SUM(CASE WHEN Domain_Id = 1 THEN Fix_Count ELSE 0 END) as d_1,
SUM(CASE WHEN Domain_Id = 2 THEN Fix_Count ELSE 0 END) as d_2,
SUM(CASE WHEN Domain_Id = 3 THEN Fix_Count ELSE 0 END) as d_3,
SUM(CASE WHEN Domain_Id = 4 THEN Fix_Count ELSE 0 END) as d_4,
SUM(CASE WHEN Domain_Id = 5 THEN Fix_Count ELSE 0 END) as d_5
FROM (SELECT lg.domainNameID AS Domain_ID, COUNT(*) AS Fix_Count
FROM tbl_ATT_Request r JOIN
tbl_ATT_Login lg
ON lg.workdayID = r.workdayID
WHERE r.requestCategoryID = 1
GROUP BY lg.domainNameID
) d
I have students, and these students have their meals, morning and evening. I want to print the number of meals each student eats in the morning and evening.
If the number of dishes that student eats in the morning is more than one, I want to print the number in the table and the ID of the food.
FoodType when 1(morning), and when 2(evening)
StudentId FoodId FoodType
3 1 1
3 2 1
3 3 1
3 4 2
4 3 1
4 1 2
4 2 2
4 4 2
5 4 2
5 1 1
6 1 1
6 2 1
6 3 2
6 4 2
Sample out;
StudentId MorningFoodCountOrId EveningFoodCountOrId
3 3 meals 4
4 3 3 meals
5 4 1
6 2 meals 2 meals
Use conditional aggregation. The logic that decides if we print the number of records or their value is not intuitive, but I would phrase it as follows:
select
studentId,
case when sum(case when foodtype = 1 then 1 else 0 end) = 1
then max(case when foodtype = 1 then foodId end)
else sum(case when foodtype = 1 then 1 else 0 end)
end MorningFoodCountOrId
case when sum(case when foodtype = 2 then 1 else 0 end) = 1
then max(case when foodtype = 2 then foodId end)
else sum(case when foodtype = 2 then 1 else 0 end)
end EveningFoodCountOrId
from mytable
group by studentId
You RDMBS should be able to optimize the query by not computing the conditional sums twice.
Note: you did not specify which RDMBS you are using. If this is MySQL, then it is possible to shorten the conditional sums a little, as follows:
select
studentId,
case when sum(foodtype = 1) = 1
then max(case when foodtype = 1 then foodId end)
else sum(foodtype = 1)
MorningFoodCountOrId
case when sum(foodtype = 2) = 1
then max(case when foodtype = 2 then foodId end)
else sum(foodtype = 2)
EveningFoodCountOrId
from mytable
group by studentId
Here's your query, select sum() and case.. will do this
select t1.studentid
, case when t1.m <= 1 then t2.FoodId else concat(t1.m, ' meals') end MorningFoodCountOrId
, case when t1.e <= 1 then t3.FoodId else concat(t1.e, ' meals') end EveningFoodCountOrId
from(
select studentid
, sum(case when FoodType = 1 then 1 else 0 end) as m
, sum(case when FoodType = 2 then 1 else 0 end) as e
from tableA
group by studentid) t1
left join tableA t2 on t2.studentId = t1.studentId and t1.m = 1 and t2.FoodType = 1
left join tableA t3 on t3.studentId = t1.studentId and t1.e = 1 and t3.FoodType = 2
order by t1.studentid
see dbfiddle
in postgresql
, case when t1.m <= 1 then t2.FoodId::text else concat(t1.m, ' meals') end MorningFoodCountOrId
, case when t1.e <= 1 then t3.FoodId::text else concat(t1.e, ' meals') end EveningFoodCountOrId
I have a next problem with query
SELECT
T.DETALLE_BECA_ANIO anio,
T.DETALLE_BECA_MES mes,
T.DETALLE_BECA_NIVEL_EDU_ID edu_id,
T.DETALLE_BECA_TRAMO_ID tr_id,
MAX(
CASE
WHEN T.DETALLE_BECA_TIPO_BENE_ID IS NULL
THEN NVL(DETALLE_BECA_VALOR,0)
ELSE 0
END) mant ,
MAX(
CASE
WHEN T.DETALLE_BECA_TIPO_BENE_ID = 1
THEN NVL(DETALLE_BECA_VALOR,0)
ELSE 0
END) tras
FROM
(SELECT DETALLE_BECA_NIVEL_EDU_ID,
DETALLE_BECA_BECA_ID,
DETALLE_BECA_TIPO_BENE_ID,
DETALLE_BECA_VALOR,
DETALLE_BECA_MES,
DETALLE_BECA_REGION_ID,
DETALLE_BECA_PROVINCIA_ID,
DETALLE_BECA_ANIO,
DETALLE_BECA_TRAMO_ID,
DETALLE_BECA_COMUNA_ID
FROM TBL_DETALLE_BECAS
WHERE (DETALLE_BECA_TIPO_BENE_ID = 1
OR DETALLE_BECA_TIPO_BENE_ID IS NULL)
and DETALLE_BECA_BECA_ID = 1
and detalle_beca_mes = 3
) T
GROUP BY T.DETALLE_BECA_BECA_ID,
T.DETALLE_BECA_TRAMO_ID,
T.DETALLE_BECA_REGION_ID,
T.DETALLE_BECA_PROVINCIA_ID,
T.DETALLE_BECA_ANIO,
T.DETALLE_BECA_MES,
T.DETALLE_BECA_NIVEL_EDU_ID,
T.DETALLE_BECA_COMUNA_ID
ORDER BY T.DETALLE_BECA_BECA_ID,
T.DETALLE_BECA_MES,
T.DETALLE_BECA_NIVEL_EDU_ID
output:
"ANIO" "MES" "EDU_ID" "TR_ID" "MANT" "TRAS"
2017 3 2 0.62 0 NULL
2017 3 3 1.24 6 NULL
2017 3 NULL 1.0 NULL 1
I need that sum value where EDU_ID is null with value 2,3 in TR_ID and replace value null in "tras" with value from EDU is null
"ANIO" "MES" "EDU_ID" "TR_ID" "MANT" "TRAS"
2017 3 2 1.62 0 1
2017 3 3 2.24 6 1
I writed query with min(edu_id) or max(edu_id ) but could not solve my problem.
The other thing that occurred to me is to make a join with the same table
First, this makes more sense as your query:
SELECT T.DETALLE_BECA_ANIO as anio, T.DETALLE_BECA_MES as mes,
T.DETALLE_BECA_NIVEL_EDU_ID as edu_id, T.DETALLE_BECA_TRAMO_ID as tr_id,
MAX(CASE WHEN T.DETALLE_BECA_TIPO_BENE_ID IS NULL
THEN NVL(DETALLE_BECA_VALOR, 0)
ELSE 0
END) as mant ,
MAX(CASE WHEN T.DETALLE_BECA_TIPO_BENE_ID = 1
THEN NVL(DETALLE_BECA_VALOR,0)
ELSE 0
END) tras
FROM TBL_DETALLE_BECAS
WHERE (DETALLE_BECA_TIPO_BENE_ID = 1 OR DETALLE_BECA_TIPO_BENE_ID IS NULL) AND
DETALLE_BECA_BECA_ID = 1 AND
detalle_beca_mes = 3
GROUP BY T.DETALLE_BECA_ANIO, T.DETALLE_BECA_MES,
T.DETALLE_BECA_NIVEL_EDU_ID, T.DETALLE_BECA_TRAMO_ID
ORDER BY T.DETALLE_BECA_BECA_ID, T.DETALLE_BECA_MES, T.DETALLE_BECA_NIVEL_EDU_ID;
This eliminates the subquery (unnecessary) and only aggregates by the columns being returned. A proper query might fix your problem.
But, you seem to want to use NULL to be "all" for the other columns. If so, something like this will work:
WITH t as (
SELECT T.DETALLE_BECA_ANIO as anio, T.DETALLE_BECA_MES as mes,
T.DETALLE_BECA_NIVEL_EDU_ID as edu_id, T.DETALLE_BECA_TRAMO_ID as tr_id,
MAX(CASE WHEN T.DETALLE_BECA_TIPO_BENE_ID IS NULL
THEN NVL(DETALLE_BECA_VALOR, 0)
ELSE 0
END) as mant ,
MAX(CASE WHEN T.DETALLE_BECA_TIPO_BENE_ID = 1
THEN NVL(DETALLE_BECA_VALOR,0)
ELSE 0
END) tras
FROM TBL_DETALLE_BECAS
WHERE (DETALLE_BECA_TIPO_BENE_ID = 1 OR DETALLE_BECA_TIPO_BENE_ID IS NULL) AND
DETALLE_BECA_BECA_ID = 1 AND
detalle_beca_mes = 3
GROUP BY T.DETALLE_BECA_ANIO, T.DETALLE_BECA_MES,
T.DETALLE_BECA_NIVEL_EDU_ID, T.DETALLE_BECA_TRAMO_ID
)
SELECT t.ANIO, t.MES, t.EDU_ID,
COALESCE(t.TR_ID, 0) + COALESCE(tnull.TR_ID, 0) as TR_ID,
t.MANT,
COALESCE(t.TRAS, 0) + COALESCE(tnull.TRAS, 0) as TRAS
FROM t LEFT JOIN
(SELECT t.*
FROM t
WHERE t.edu_id IS NULL
) tnull
ON tnull.ANIO = t.ANIO AND tnull.MES = t.MES
WHERE t.edu_id IS NOT NULL
ORDER BY T.DETALLE_BECA_BECA_ID, T.DETALLE_BECA_MES, T.DETALLE_BECA_NIVEL_EDU_ID;
If I have a table
AgentID | IsNew | TeamID
1 N 1
2 Y 2
3 Y 2
4 N 2
5 Y 1
I want to return the following from a query:
Team | CountIsNew = N | CountIsNew = Y
1 1 1
2 1 2
Is there a way I can do this?
Using Oracle 10
SELECT team, SUM(DECODE(IsNew, 'N', 1, 0)), SUM(DECODE(IsNew, 'Y', 1, 0))
FROM mytable
GROUP BY
team
SELECT TeamId
, SUM(CASE WHEN IsNew = 'N' THEN 1 ELSE 0 END) AS CountIsNotNew
, SUM(CASE WHEN IsNew = 'Y' THEN 1 ELSE 0 END) AS CountIsNew
FROM Agent
GROUP BY TeamId
Yet another way - COUNT doesn't count NULLs (except for COUNT(*)):
SELECT TeamId,
COUNT(DECODE(IsNew,'N',1)) CountIsNotNew,
COUNT(DECODE(IsNew,'Y',1)) CountIsNew
FROM Agent
GROUP BY TeamId;
Or, if you prefer CASE:
SELECT TeamId,
COUNT(CASE IsNew WHEN 'N' THEN 1 END) CountIsNotNew,
COUNT(CASE IsNew WHEN 'Y' THEN 1 END) CountIsNew
FROM Agent
GROUP BY TeamId;
(note: the "1"s could be any literal value)