UNION ALL IS NOT WORKING WITH GROUP BY IN SQL - sql

I have to create a query that shows whether the employees has taken what kind of leave on time card or if they have taken any leave "Vacation".
The output should look like:
SELECT person_number,
Sum(
CASE
WHEN element = 'Overtime' THEN measure
END) AS overtime_measure_hours,
Sum(
CASE
WHEN elements LIKE 'Regular Pay' THEN measure
END) AS regular_measure_hours,
Sum(
CASE
WHEN elements IN ( 'Double_Time' ) THEN measure
END) AS Other_amount,
Max(
CASE
WHEN elements IN ( 'Double_Time' ) THEN 'Double'
END) AS Other_code
(
SELECT papf.person_number,
atrb.attribute_category element,
atrb.measure measure_hours,
rec.start_date,
rec.end_date
FROM per_all_people_f papf,
hwm_tm_rec rec,
fusion.hwm_tm_rep_atrbs atrb,
fusion.hwm_tm_rep_atrb_usages ausage,
hwm_tm_statuses status
WHERE 1=1
AND atrb.tm_rep_atrb_id = ausage.tm_rep_atrb_id
AND ausage.usages_source_id = rec.tm_rec_id
AND ausage.usages_source_version = rec.tm_rec_version
AND status.tm_bldg_blk_id = rec.tm_rec_id
AND status.tm_bldg_blk_version = rec.tm_rec_version
AND rec.tm_rec_type IN ( 'RANGE',
'MEASURE' )
AND papf.person_number = '101928'
AND trunc (status.date_to) = to_date ('31/12/4712', 'DD/MM/YYYY')
--and atrb.attribute_category in( 'Overtime','Regular Pay', 'Double_Time')
AND trunc (sh21.start_time) BETWEEN trunc(:P_From_Date) AND trunc(:P_To_Date) )
GROUP BY person_number
UNION ALL
SELECT person_number,
sum(
CASE
WHEN element = 'Overtime' THEN measure
END) AS overtime_measure_hours,
sum(
CASE
WHEN elements LIKE 'Regular Pay' THEN measure
END) AS regular_measure_hours,
sum(
CASE
WHEN absence_name IN ( 'Vacation' ) THEN abs_duration
END) AS Other_amount,
max(
CASE
WHEN absence_name IN ( 'Vacation' ) THEN absence_name
END) AS Other_code
(
SELECT papf.person_number,
atrb.attribute_category element,
atrb.measure measure_hours,
rec.start_date,
rec.end_date,
abs.NAME absence_name,
abs.duration abs_duration
FROM per_all_people_f papf,
hwm_tm_rec rec,
fusion.hwm_tm_rep_atrbs atrb,
fusion.hwm_tm_rep_atrb_usages ausage,
hwm_tm_statuses status,
anc_absence_types_vl abs
WHERE 1=1
AND atrb.tm_rep_atrb_id = ausage.tm_rep_atrb_id
AND ausage.usages_source_id = rec.tm_rec_id
AND ausage.usages_source_version = rec.tm_rec_version
AND status.tm_bldg_blk_id = rec.tm_rec_id
AND status.tm_bldg_blk_version = rec.tm_rec_version
AND rec.tm_rec_type IN ( 'RANGE',
'MEASURE' )
AND papf.person_number = '101928'
AND trunc (status.date_to) = to_date ('31/12/4712', 'DD/MM/YYYY')
--and atrb.attribute_category in( 'Overtime','Regular Pay', 'Double_Time')
AND trunc (sh21.start_time) BETWEEN trunc(:P_From_Date) AND trunc(:P_To_Date)
AND abs.absence_type_id = atrb.absence_type_id )
GROUP BY person_number
Although these queries are working separately it is not working with group by on each subquery.
If I merge the two queries, the issue I am having is with Other_code & other_amount. These columns have values from two different tables.
How can I solve this?
Output should be returned for the two dates p_from_date- 01-Jan-2021 and p_to_date- 31-Jul-2021 as:
Person_Number Overtime_measure_hours Regular_Measure_hours Other_code Other_amount
101928 18 15 Double_Time 34
101928 18 15 Vacation 1
i.e. Overtime_measure_hours, Regular_Measure_hours and Other_amount should have the sum of these values.

Related

Sum of distinct values after grouping explodes a metric

I am using
with t1 as
(
SELECT
DATE_TRUNC(PARSE_DATE("%Y%m%d", date), MONTH) as month,
fullVisitorId,
product.productSKU,
product.v2ProductName,
case when hits.ecommerceaction.action_type = '2' then 1 else 0 end as pdp_visitor,
count(case when hits.ecommerceaction.action_type = '2' then fullvisitorid else null end) AS views_pdp,
count(case when hits.ecommerceaction.action_type = '3' then fullvisitorid else null end) AS add_cart,
count(case when hits.ecommerceaction.action_type = '6' then hits.transaction.transactionid else null end) AS conversions,
count(distinct(hits.transaction.transactionId)) as transaction_id_cnt,
FROM `table` AS nr,
UNNEST(hits) hits,
UNNEST(product) product
GROUP BY 1,2,3,4,5
)
select
month,
sum(views_pdp) as pdp
,sum(add_cart) as add_cart
,sum(conversions) as conversions
,sum(transaction_id_cnt)
from t1
group by 1
order by 1 desc;
Which returns
month pdp add_cart conversions f0_
2021-02-01 500 100 20 10
2021-01-01 600 200 30 20
I know that f0_ ( count(distinct(hits.transaction.transactionId)) ) is bad here because of product.productSKU and product.v2ProductName grouping.
In general, when user makes an order with 3 items in his basket, I want to count this as one order, whereas now it is counted as 3.
This count(distinct(hits.transaction.transactionId)) as transaction_id_cnt results in the correct output if I comment out product.productSKU and product.v2ProductName.
Running this query:
with t1 as
(
SELECT
DATE_TRUNC(PARSE_DATE("%Y%m%d", date), MONTH) as month,
fullVisitorId,
-- product.productSKU, # commented out
-- product.v2ProductName, # commented out
case when hits.ecommerceaction.action_type = '2' then 1 else 0 end as pdp_visitor,
count(case when hits.ecommerceaction.action_type = '2' then fullvisitorid else null end) AS views_pdp,
count(case when hits.ecommerceaction.action_type = '3' then fullvisitorid else null end) AS add_cart,
count(case when hits.ecommerceaction.action_type = '6' then hits.transaction.transactionid else null end) AS conversions,
count(distinct(hits.transaction.transactionId)) as transaction_id_cnt,
FROM `table` AS nr,
UNNEST(hits) hits,
UNNEST(product) product
GROUP BY 1,2,3,4,5
)
select
month,
sum(views_pdp) as pdp
,sum(add_cart) as add_cart
,sum(conversions) as conversions
,sum(transaction_id_cnt)
from t1
group by 1
order by 1 desc;
Returns what is expected, but now I don't have productSKU and v2ProductName which I need. I suspect that the problem is that each order is a new line in google big query and when I ask to to select it by product name and SKU, I count the uniques and then sum it.
How can I achieve the correct summation of count(distinct(hits.transaction.transactionId)) without losing the grouping by product.productSKU and product.v2ProductName which explodes this metric?
On the group by Query you could cherry pick them as array(so you don't group by them):
ARRAY_AGG(DISTINCT product.productSKU IGNORE NULLS) AS productSKU_list,
ARRAY_AGG(DISTINCT product.v2ProductName IGNORE NULLS) AS productName_list,
Update per your below comment: If you want to use them in further group by just save them as string instead of array.
STRING_AGG(DISTINCT product.productSKU, ',') AS productSKU_list,
STRING_AGG(DISTINCT product.v2ProductName, ',') AS productName_list,

How to do a union with where clause

I am still learning to write it and below query is not giving me accurate results plus it is also not optimized.
So one of the main things that I am trying to do is create 3 date types:
sales_shift,
refund,
sales_reg
in my data sets.
To achieve this I am doing a union.
All 3 data sets are querying the same source sales_main. The problem is in my 2nd data set with ‘Refund’ as date_type, it is not pulling the actual rows because of ColumnA = ‘B’ condition.
I would like this set to look at only those records that were pulled in 1st data set (i.e ‘Sales_shift’ as date_type) and then apply the condition ColumnA = ‘B’. How do I do that?
My 3rd data set with ‘sales_reg’ as date_type should be same as 1st set except with transaction_date not shifted. How do I do that. I was thinking of where exists but do not know how to apply it.
Any help would be awesome. Thanks much
create table sales_refund as select * from (
with table1 as (select 'Sales_shift' as date_type,
add_months(date_trunc('month',transaction_date),1) as event_date,
sku,
sum(sales) as Sales_total,
sum(refund) as Refund_total,
case when region in ('US','EU') then 'type A' else 'type B' end as Flag_field1
from sales_main where transaction_date >= add_months(current_date(),-6)
group by sku,
'Sales_shift'
add_months(date_trunc('month',transaction_date),1),
Flag_field1),
table2 as (select sku,
date_type,
event_date,
Sales_total,
Refund_total,
Flag_field1,
case when Flag_field1 = 'type B' or (Flag_field1 = 'type A' and Sales_total > 20000) then 'Yes' else 'No' end as Flag_field2
from table1 )
Select sku,
date_type,
event_date,
Sales_total,
Refund_total,
Flag_field1
fromm table2 where Flag_field2 = 'Yes' )
union all
select sku,
'Refund' as date_type,
date_trunc('month',refund_date) as event_date,
sum(sales) as Sales_total,
sum(refund) as Refund_total,
'X' as Flag_field1
from sales_main where transaction_date >= add_months(current_date(),-6) and ColumnA = 'B'
group by sku,
'Refund'
date_trunc('month',refund_date),
'X'
union all
select sku,
'Sales_Reg' as date_type,
date_trunc('month',transaction_date) as event_date,
sum(sales) as Sales_total,
sum(refund) as Refund_total,
'Y' as Flag_field1
from sales_main where transaction_date >= add_months(current_date(),-6)
group by sku,
'Refund'
date_trunc('month',transaction_date),
'Y'

Sum all rows that are sum of a column sql 2012

I want to get a total sum of the results of my "total tested" "failed" and "passed" colums. I would usually handle these aggregates in SSRS, but I don't have that option at this time.
My current query:
select s.school_code, s.name, count(cd.Test_ID) as [Tested],
sum(case when cd.result = 'fail' then 1 Else 0 End) as 'Failed'
,sum(case when cd.result = 'pass' then 1 Else 0 End) as 'Passed'
FROM
[psi_db_8amSnapshot].[dbo].[Candidate_Data] cd
join [psi_db_8amSnapshot].[dbo].account_school s on s.school_id = cd.school_id
where s.School_code in
(
'1001',
'1002',
'1003' ,
'1004' ,
'1005' ,
'1006' ,
'1007' ,
'1008' ,
'1016' ,
'1009' ,
'1010' ,
'1012' ,
'1013' ,
'1014' ,
'1015'
)
and cd.[date] between '01-01-2016' and '05-01-2017' and cd.TestName = 'MN Dental Assistant State Licensure Examination'
group by s.school_code, s.name, test_id
I am looking to get a total off all the values in my three aggregate columns. So a sum of Tested, which should = 640, sum of passed = 327, sum of failed = 313.
I think you are looking for group by grouping sets as below:
Just replace your group by as below:
group by grouping sets ((s.school_code), (s.name), (test_id))
I would probably use with statements:
with NumberOfFailedResults as
(
Select count(cd.result) as NumberOfFailedResults from [psi_db_8amSnapshot].[dbo].[Candidate_Data] as cd where cd.Result = 'Failed'
),
NumberOfPassedResults as
(
Select count(cd.result) as NumberOfPassedResults from [psi_db_8amSnapshot].[dbo].[Candidate_Data] as cd where cd.Result = 'Passed'
)
Select NumberOfFailedResults, NumberOfPassedResults, ...
This should work for you.
select Q.school_code, Q.name, SUM(Q.Tested), SUM(Q.Failed), SUM(Q.Passed) from (
select s.school_code, s.name, count(cd.Test_ID) as [Tested],
sum(case when cd.result = 'fail' then 1 Else 0 End) as 'Failed'
,sum(case when cd.result = 'pass' then 1 Else 0 End) as 'Passed'
FROM
[psi_db_8amSnapshot].[dbo].[Candidate_Data] cd
join [psi_db_8amSnapshot].[dbo].account_school s on s.school_id = cd.school_id
where s.School_code in
(
'1001',
'1002',
'1003' ,
'1004' ,
'1005' ,
'1006' ,
'1007' ,
'1008' ,
'1016' ,
'1009' ,
'1010' ,
'1012' ,
'1013' ,
'1014' ,
'1015'
)
and cd.[date] between '01-01-2016' and '05-01-2017' and cd.TestName = 'MN Dental Assistant State Licensure Examination'
group by s.school_code, s.name, test_id)Q
GROUP BY Q.School_Code, Q.Name

ORACLE SQL: Fill in missing dates

I have the following code which gives me production dates and production volumes for a thirty day period.
select
(case when trunc(so.revised_due_date) <= trunc(sysdate)
then trunc(sysdate) else trunc(so.revised_due_date) end) due_date,
(case
when (case when sp.pr_typ in ('VV','VD') then 'DVD' when sp.pr_typ in ('RD','CD')
then 'CD' end) = 'CD'
and (case when so.tec_criteria in ('PI','MC')
then 'XX' else so.tec_criteria end) = 'OF'
then sum(so.revised_qty_due)
end) CD_OF_VOLUME
from shop_order so
left join scm_prodtyp sp
on so.prodtyp = sp.prodtyp
where so.order_type = 'MD'
and so.plant = 'W'
and so.status_code between '4' and '8'
and trunc(so.revised_due_date) <= trunc(sysdate)+30
group by trunc(so.revised_due_date), so.tec_criteria, sp.pr_typ
order by trunc(so.revised_due_date)
The problem I have is where there is a date with no production planned, the date wont appear on the report. Is there a way of filling in the missing dates.
i.e. the current report shows the following ...
DUE_DATE CD_OF_VOLUME
14/04/2015 35,267.00
15/04/2015 71,744.00
16/04/2015 20,268.00
17/04/2015 35,156.00
18/04/2015 74,395.00
19/04/2015 3,636.00
21/04/2015 5,522.00
22/04/2015 15,502.00
04/05/2015 10,082.00
Note: missing dates (20/04/2015, 23/04/2015 to 03/05/2015)
Range is always for a thirty day period from sysdate.
How do you fill in the missing dates?
Do you need some kind of calendar table?
Thanks
You can get the 30-day period from SYSDATE as follows (I assume you want to include SYSDATE?):
WITH mydates AS (
SELECT TRUNC(SYSDATE) - 1 + LEVEL AS due_date FROM dual
CONNECT BY LEVEL <= 31
)
Then use the above to do a LEFT JOIN with your query (perhaps not a bad idea to put your query in a CTE as well):
WITH mydates AS (
SELECT TRUNC(SYSDATE) - 1 + LEVEL AS due_date FROM dual
CONNECT BY LEVEL <= 31
), myorders AS (
select
(case when trunc(so.revised_due_date) <= trunc(sysdate)
then trunc(sysdate) else trunc(so.revised_due_date) end) due_date,
(case
when (case when sp.pr_typ in ('VV','VD') then 'DVD' when sp.pr_typ in ('RD','CD')
then 'CD' end) = 'CD'
and (case when so.tec_criteria in ('PI','MC')
then 'XX' else so.tec_criteria end) = 'OF'
then sum(so.revised_qty_due)
end) CD_OF_VOLUME
from shop_order so
left join scm_prodtyp sp
on so.prodtyp = sp.prodtyp
where so.order_type = 'MD'
and so.plant = 'W'
and so.status_code between '4' and '8'
and trunc(so.revised_due_date) <= trunc(sysdate)+30
group by trunc(so.revised_due_date), so.tec_criteria, sp.pr_typ
order by trunc(so.revised_due_date)
)
SELECT mydates.due_date, myorders.cd_of_volume
FROM mydates LEFT JOIN myorders
ON mydates.due_date = myorders.due_date;
If you want to show a zero on "missing" dates instead of a NULL, use COALESCE(myorders.cd_of_volume, 0) AS cd_of_volume above.
what you can do is this :
creating a new table with all the days you need .
WITH DAYS AS
(SELECT TRUNC(SYSDATE) - ROWNUM DDD
FROM ALL_OBJECTS
WHERE ROWNUM < 365)
SELECT
DAYS.DDD
FROM
DAYS;
then full outer join between thoes table :
select DUE_DATE , CD_OF_VOLUME , DDD
from (
select
(case when trunc(so.revised_due_date) <= trunc(sysdate)
then trunc(sysdate) else trunc(so.revised_due_date) end) due_date,
(case
when (case when sp.pr_typ in ('VV','VD') then 'DVD' when sp.pr_typ in ('RD','CD')
then 'CD' end) = 'CD'
and (case when so.tec_criteria in ('PI','MC')
then 'XX' else so.tec_criteria end) = 'OF'
then sum(so.revised_qty_due)
end) CD_OF_VOLUME
from shop_order so
left join scm_prodtyp sp
on so.prodtyp = sp.prodtyp
where so.order_type = 'MD'
and so.plant = 'W'
and so.status_code between '4' and '8'
and trunc(so.revised_due_date) <= trunc(sysdate)+30
group by trunc(so.revised_due_date), so.tec_criteria, sp.pr_typ
order by trunc(so.revised_due_date)
) full outer join NEW_TABLE new on ( new .DDD = DUE_DATE )
where new .DDD between /* */ AND /* */ /* pick your own limit) */
you can get the gaps by using connect by and a left join:
assuming your schema is:
create table tbl(DUE_DATE date, CD_OF_VOLUME float);
insert into tbl values(to_date('14/04/2015','DD/MM/YYYY'),35267.00);
insert into tbl values(to_date('15/04/2015','DD/MM/YYYY'),71744.00);
insert into tbl values(to_date('16/04/2015','DD/MM/YYYY'),20268.00);
insert into tbl values(to_date('17/04/2015','DD/MM/YYYY'),35156.00);
insert into tbl values(to_date('18/04/2015','DD/MM/YYYY'),74395.00);
insert into tbl values(to_date('19/04/2015','DD/MM/YYYY'),3636.00);
insert into tbl values(to_date('21/04/2015','DD/MM/YYYY'),5522.00);
insert into tbl values(to_date('22/04/2015','DD/MM/YYYY'),15502.00);
insert into tbl values(to_date('04/05/2015','DD/MM/YYYY'),10082.00);
you can say:
with cte as
(
select (select min(DUE_DATE)-1 from tbl)+ level as dt
from dual
connect by level <= (select max(DUE_DATE)-min(DUE_DATE) from tbl)
)
select to_char(c.dt,'DD/MM/YYYY') gap,null volume
from cte c
left join tbl t on c.dt=t.DUE_DATE
where t.DUE_DATE is null
order by c.dt
Result:
GAP VOLUME
20/04/2015 (null)
23/04/2015 (null)
24/04/2015 (null)
25/04/2015 (null)
26/04/2015 (null)
27/04/2015 (null)
28/04/2015 (null)
29/04/2015 (null)
30/04/2015 (null)
01/05/2015 (null)
02/05/2015 (null)
03/05/2015 (null)
Notice: you can implement this in your original query, one simplest way is to wrap your query and use it as a subquery instead of tbl in above code snippet.

column headers in select Union query

I have to select query like the following example :
Select name,
SUM(DECODE(TO_CHAR(Datee,'MM'),'01',PRICE)) JAN_12,
SUM(DECODE(TO_CHAR(Datee,'MM'),'02',PRICE)) FEB_12
from price_list_LastYear
UNION ALL
Select name,
SUM(DECODE(TO_CHAR(Datee,'MM'),'01',PRICE)) JAN_11,
SUM(DECODE(TO_CHAR(Datee,'MM'),'02',PRICE)) FEB_11
from price_list_TwoLastYear.
When I execute the query, In my column header I get name, JAN_12, FEB_12.
I want to combine my results like : name, JAN_11, JAN_12, FEB_11,FEB_12.
Try this:
SELECT P1.name,
SUM(DECODE(TO_CHAR(P1.Datee,'MM'),'01',P1.PRICE)) JAN_12,
SUM(DECODE(TO_CHAR(P1.Datee,'MM'),'02',P1.PRICE)) FEB_12,
SUM(DECODE(TO_CHAR(P2.Datee,'MM'),'01',P2.PRICE)) JAN_11,
SUM(DECODE(TO_CHAR(P2.Datee,'MM'),'02',P2.PRICE)) FEB_11
FROM price_list_LastYear P1
JOIN price_list_TwoLastYear P2
ON P1.nmae = P2.nmae
GROUP BY P1.nmae
If same name doesn't exists in both tables try this:
SELECT N.name,
SUM(DECODE(TO_CHAR(P1.Datee,'MM'),'01',P1.PRICE)) JAN_12,
SUM(DECODE(TO_CHAR(P1.Datee,'MM'),'02',P1.PRICE)) FEB_12,
SUM(DECODE(TO_CHAR(P2.Datee,'MM'),'01',P2.PRICE)) JAN_11,
SUM(DECODE(TO_CHAR(P2.Datee,'MM'),'02',P2.PRICE)) FEB_11
FROM
(
SELECT name FROM price_list_LastYear
UNION
SELECT name FROM price_list_TwoLastYear
) N
LEFT JOIN price_list_LastYear P1
ON N.nmae = P1.name
LEFT JOIN price_list_TwoLastYear P2
ON N.nmae = P2.name
GROUP BY N.name
Try this
SELECT A.*, B,JAN_11, B.FEB_11 FROM (
Select name,
SUM(DECODE(TO_CHAR(Datee,'MM'),'01',PRICE)) JAN_12,
SUM(DECODE(TO_CHAR(Datee,'MM'),'02',PRICE)) FEB_12
from price_list_LastYear
Group By Name) A
LEFT OUTER JOIN (
Select name,
SUM(DECODE(TO_CHAR(Datee,'MM'),'01',PRICE)) JAN_11,
SUM(DECODE(TO_CHAR(Datee,'MM'),'02',PRICE)) FEB_11
from price_list_TwoLastYear
Group By Name) B ON A.name = B.Name
Or
Select name,
SUM(CASE WHEN Yr = '11' THEN DECODE(Mnth,'01',PRICE) ELSE NULL END) JAN_11,
SUM(CASE WHEN Yr = '12' THEN DECODE(Mnth,'01',PRICE) ELSE NULL END) JAN_12,
SUM(CASE WHEN Yr = '11' THEN DECODE(Mnth,'02',PRICE) ELSE NULL END) FEB_11,
SUM(CASE WHEN Yr = '12' THEN DECODE(Mnth,'02',PRICE) ELSE NULL END) FEB_12
from
(
SELECT '12' As yr, name, TO_CHAR(Datee,'MM') Mnth, Price
FROM price_list_LastYear
UNION ALL
SELECT '11' As yr, name, TO_CHAR(Datee,'MM') Mnth, Price
FROM price_list_TwoLastYear
)
GROUP BY Name
If the name does not exist in both tables, then it might be difficult to use a JOIN. So here is a version using UNION ALL and then applying an aggregate function with a CASE expression to transform the data to columns:
SELECT name,
sum(case when Month = 'JAN_12' then price else 0 end) JAN_12,
sum(case when Month = 'FEB_12' then price else 0 end) FEB_12,
sum(case when Month = 'JAN_11' then price else 0 end) JAN_11,
sum(case when Month = 'FEB_11' then price else 0 end) FEB_11
FROM
(
Select name,
PRICE,
case
when TO_CHAR(Datee,'MM') = '01' Then 'JAN_12'
when TO_CHAR(Datee,'MM') = '02' Then 'FEB_12' End Month
from price_list_LastYear
WHERE TO_CHAR(Datee,'MM') in ('01', '02')
UNION ALL
Select name,
PRICE,
case
when TO_CHAR(Datee,'MM') = '01' Then 'JAN_11'
when TO_CHAR(Datee,'MM') = '02' Then 'FEB_11' End Month
from price_list_TwoLastYear
WHERE TO_CHAR(Datee,'MM') in ('01', '02')
) src
GROUP BY name