Sql Group by on subquery rows - sql

I have this table :
ArretProductionJournee(Id, DateArret,HeureDebut,HeureFin,EnumArret)
Example :
DateArret ||HeureDebut ||HeureFin ||EnumArret
2020-11-30 ||2020-11-30 14:00:00.000 ||2020-11-30 15:00:00.000 ||PS
2020-11-30 ||2020-11-30 16:00:00.000 ||2020-11-30 17:00:00.000 ||HI
i want to sum the datediff(HeureDebut,HeureFin) in columns for each EnumArret
so i run this query :
SELECT ArretProductionJournee.DateArret,
(select
sum (datediff(minute,ArretProductionJournee.HeureDebut,
ArretProductionJournee.HeureFin))
where ArretProductionJournee.EnumArret Like 'HI')as HI,
(select
sum (datediff(minute,ArretProductionJournee.HeureDebut,
ArretProductionJournee.HeureFin))
where ArretProductionJournee.EnumArret Like 'PS') as PS
FROM dbo.ArretProductionJournee
where ArretProductionJournee.EnumArret Like 'HI'OR
ArretProductionJournee.EnumArret Like 'PS'
group by ArretProductionJournee.EnumArret, dbo.ArretProductionJournee.DateArret
Result :
DateArret ||HI || PS
2020-10-30 ||12 || NULL
2020-11-30 ||60 || NULL
2020-11-30 ||NULL || 60
The result i want is Grouping the sum by the date:
DateArret ||HI || PS
2020-10-30 ||12 || 0
2020-11-30 ||60 || 60

I think you want conditional aggregation:
select datearret,
sum(case when enumarret = 'PS' then datediff(minute, heuredebut, heurefin) else 0 end) ps,
sum(case when enumarret = 'HI' then datediff(minute, heuredebut, heurefin) else 0 end) hi
from dbo.arretproductionjournee
where enumarret in ('PS', 'HI')
group by datearret

Related

Count average with multiple conditions

I'm trying to create a query which allows to categorize the average percentage for specific data per month.
Here's how my dataset presents itself:
Date
Name
Group
Percent
2022-01-21
name1
gr1
5.2
2022-01-22
name1
gr1
6.1
2022-01-26
name1
gr1
4.9
2022-02-01
name1
gr1
3.2
2022-02-03
name1
gr1
8.1
2022-01-22
name2
gr1
36.1
2022-01-25
name2
gr1
32.1
2022-02-10
name2
gr1
35.8
...
...
...
...
And here's what I want to obtain with my query (based on what I showed of the table):
Month
<=25%
25<_<=50%
50<_<=75%
75<_<=100%
01
1
1
0
0
02
1
1
0
0
...
...
...
...
...
The result needs to:
Be ordered by month
Have the average use for each name counted and categorized
So far I know how to get the average of the Percent value per Name:
SELECT Name,
AVG(Percent)
from `table`
where Group = 'gr1'
group by Name
and how to count iterations of Percent in the categories created for the query:
SELECT EXTRACT(MONTH FROM Date) as Month,
COUNT(CASE WHEN Percent <= 25 AND Group = 'gr1' THEN Name END) `_25`,
COUNT(CASE WHEN Percent > 25 AND Percent <= 50 AND Group = 'gr1' THEN Name END) `_50`,
COUNT(CASE WHEN Percent > 50 AND Percent <= 75 AND Group = 'gr1' THEN Name END) `_75`,
COUNT(CASE WHEN Percent > 75 AND Percent <= 100 AND Group = 'gr1' THEN Name END) `_100`,
FROM `table`
GROUP BY Month
ORDER BY Month
but this counts all iterations of every name where I want the average of those values.
I've been struggling to figure out how to combine the two queries or to create a new one that answers my need.
I'm working with the BigQuery service from Google Cloud
This query produces the needed result, based on your example. So basically this combines your 2 queries using subquery, where the subquery is responsible to calculate AVG grouped by Name, Month and Group, and the outer query is for COUNT and "categorization"
SELECT
Month,
COUNT(CASE
WHEN avg <= 25 THEN Name
END) AS _25,
COUNT(CASE
WHEN avg > 25
AND avg <= 50 THEN Name
END) AS _50,
COUNT(CASE
WHEN avg > 50
AND avg <= 75 THEN Name
END) AS _75,
COUNT(CASE
WHEN avg > 75
AND avg <= 100 THEN Name
END) AS _100
FROM
(
SELECT
EXTRACT(MONTH from Date) AS Month,
Name,
AVG(Percent) AS avg
FROM
table1
GROUP BY Month, Name, Group
HAVING Group = 'gr1'
) AS namegr
GROUP BY Month
This is the result:
Month
_25
_50
_75
_100
1
1
1
0
0
2
1
1
0
0
See also Fiddle (BUT on MySql) - http://sqlfiddle.com/#!9/16c5882/9
You can use this query to Group By Month and each Name
SELECT CONCAT(EXTRACT(MONTH FROM Date), ', ', Name) AS DateAndName,
CASE
WHEN AVG(Percent) <= 25 THEN '1'
ELSE '0'
END AS '<=25%',
CASE
WHEN AVG(Percent) > 25 AND AVG(Percent) <= 50 THEN '1'
ELSE '0'
END AS '25<_<=50%',
CASE
WHEN AVG(Percent) > 50 AND AVG(Percent) <= 75 THEN '1'
ELSE '0'
END AS '50<_<=75%',
CASE
WHEN AVG(Percent) > 75 AND AVG(Percent) <= 100 THEN '1'
ELSE '0'
END AS '75<_<=100%'
from DataTable /*change to your table name*/
group by EXTRACT(MONTH FROM Date), Name
order by DateAndName
It gives the following result:
DateAndName
<=25%
25<_<=50%
50<_<=75%
75<_<=100%
1, name1
1
0
0
0
1, name2
0
1
0
0
2, name1
1
0
0
0
2, name2
0
1
0
0

Multiple SUM in one query with multiple where

I'm trying to write a SQL query that produces a table with summarized values for each year and month.
I have a table that looks something like this:
TABLENAME: TIME
id cID cDate cTime
1 254 2019-10-11 5
2 259 2019-10-13 4
3 268 2020-01-17 6
4 268 2020-01-18 9
5 271 2020-01-21 4
6 267 2020-02-19 8
And another table that looks like this:
TABLENAME: CASE
id name invoice status
254 Acme Yes finish
259 Tex NoFakt finish
268 Rex C Yes *Null*
267 Hydro *Null* open
271 Corp Yes finish
I want to have a query that returns the sum for each month like this:
Year Month RegTime Invoiced ToBeInvoiced
2019 10 5 5 0
2019 11 0 0 0
2019 12 0 0 0
2020 1 19 4 15
2020 2 8 0 8
Explanation of the output:
Year and Month are obvious
RegTime should be the sum of all TIME.cTime WHERE CASE.invoice <> 'NoFakt'
Invoiced should be the sum of all TIME.cTIME WHERE CASE.invoice = 'Yes' AND CASE.status = 'finish'
ToBeInvoiced should be the sum of all TIME.cTIME WHERE CASE.invoice = 'Yes' AND CASE.status <> 'finish'
I have tried this query, but with this i need to loop a predefined year and month value in my programming code instead of simply having a sql statement that are doing all the work. ThereĀ“s got to be a simpler way than this...
select (select sum(cTIME) from TIME inner join CASE on TIME.cID = CASE.id WHERE CASE.invoice <> 'NoFakt' AND DATEPART(yy, cDate) = '2019' AND DATEPART(mm, cDate) = '10') AS RegTime,
(select sum(cTIME) from TIME inner join CASE on TIME.cID = CASE.id WHERE CASE.invoice = 'Yes' AND CASE.status = 'finish' AND DATEPART(yy, cDate) = '2019' AND DATEPART(mm, cDate) = '10') AS Invoiced,
(select sum(cTIME) from TIME inner join CASE on TIME.cID = CASE.id WHERE CASE.invoice = 'Yes' AND CASE.status <> 'finish' AND DATEPART(yy, cDate) = '2019' AND DATEPART(mm, cDate) = '10') AS ToBeInvoiced
Use conditional aggregation :
SELECT YEAR(T.cDate) AS YR, MONTH(T.cDate) AS Mnth,
SUM(CASE WHEN C.invoice <> 'NoFakt' THEN C.cTIME ELSE 0 END) AS RegTime,
SUM(CASE WHEN C.invoice = 'Yes' AND C.status = 'finish' THEN C.cTIME ELSE 0 END) AS Invoiced,
SUM(CASE WHEN C.invoice = 'Yes' AND C.status <> 'finish' THEN C.cTIME ELSE 0 END) AS ToBeInvoiced
FROM TIME T INNER JOIN
CASE C
ON T.cID = C.id
GROUP BY YEAR(T.cDate), MONTH(T.cDate);
Note: Do not use reserved keyword as Object Name.

Calculating Percentages in Postgres

I'm completely new to PostgreSQL. I have the following table called my_table:
a b c date
1 0 good 2019-05-02
0 1 good 2019-05-02
1 1 bad 2019-05-02
1 1 good 2019-05-02
1 0 bad 2019-05-01
0 1 good 2019-05-01
1 1 bad 2019-05-01
0 0 bad 2019-05-01
I want to calculate the percentage of 'good' from column c for each date. I know how to get the number of 'good':
SELECT COUNT(c), date FROM my_table WHERE c != 'bad' GROUP BY date;
That returns:
count date
3 2019-05-02
1 2019-05-01
My goal is to get this:
date perc_good
2019-05-02 25
2019-05-01 75
So I tried the following:
SELECT date,
(SELECT COUNT(c)
FROM my_table
WHERE c != 'bad'
GROUP BY date) / COUNT(c) * 100 as perc_good
FROM my_table
GROUP BY date;
And I get an error saying
more than one row returned by a subquery used as an expression.
I found this answer but not sure how to or if it applies to my case:
Calculating percentage in PostgreSql
How do I go about calculating the percentage for multiple rows?
avg() is convenient for this purpose:
select date,
avg( (c = 'good')::int ) * 100 as percent_good
from t
group by date
order by date;
How does this work? c = 'good' is a boolean expression. The ::int converts it to a number, with 1 for true and 0 for false. The average is then the average of a bunch of 1s and 0s -- and is the ratio of the true values.
For this case you need to use conditional AVG():
SELECT
date,
100 * avg(case when c = 'good' then 1 else 0 end) perc_good
FROM my_table
GROUP BY date;
See the demo.
You could use a conditional sum for get the good value and count for total
below an exaustive code sample
select date
, count(c) total
, sum(case when c='good' then 1 else 0 end) total_good
, sum(case when c='bad' then 1 else 0 end) total_bad
, (sum(case when c='good' then 1 else 0 end) / count(c))* 100 perc_good
, (sum(case when c='bad' then 1 else 0 end) / count(c))* 100 perc_bad
from my_table
group by date
and for your result
select date
, (sum(case when c='good' then 1 else 0 end) / count(c))* 100 perc_good
from my_table
group by date
or as suggested by a_horse_with_no_name using count(*) filter()
select date
, ((count(*) filter(where c='good'))/count(*))* 100 perc_good
from my_table
group by date

Select query with multiple sub queries for counts (Netezza SQL)

I am trying to create a report that gets counts at 3 periods of time: the previous month, that month last year, and year to date.
I previously used 3 separate queries like below while toggling the where clauses, but I want be able to combine all 3 into one query.
I've tried with case statements but couldn't seem to get that to work. FYI app_date is YYYY-MM-DD
Select count(application_id)
from application_data a
where to_char(app_date, 'YYYYMM' = to_char(current_date, 'YYYYMM')-1
--where to_char(app_date, 'YYYYMM' = to_char(current_date, 'YYYYMM')-101
--where to_char(app_date, 'YYYY') = to_char(current_date, 'YYYY') and to_char(app_date, 'YYYYMM') <> to_char(current_date, 'YYYYMM')
Sample data:
App_ID App_date
123519 2018-02-17
123521 2018-02-18
123522 2018-02-19
123523 2018-02-23
123518 2019-01-15
123546 2019-02-21
123547 2019-02-22
123548 2019-02-15
123542 2019-02-02
Desired Result:
LastMonth YTD YoY
4 5 4
I think you want conditional aggregation:
Select sum(case when to_char(app_date, 'YYYYMM' = to_char(current_date, 'YYYYMM')-1 then 1 else 0 end),
sum(case to_char(app_date, 'YYYYMM' = to_char(current_date, 'YYYYMM')-101 when then 1 else 0 end),
sum(case when to_char(app_date, 'YYYY') = to_char(current_date, 'YYYY') and to_char(app_date, 'YYYYMM') <> to_char(current_date, 'YYYYMM') then 1 else 0 end)
from application_data a

Sql retrieve results

I have below order table,i want to retrieve records those are not in order status "processed" and cacel)status "cancelled" by today date and time(17:00 USA).Please help me to complete my issue.
order id ordername order_status cancel_status order_time cancel_time
==============================================================================================
1 Iphone processed cancelled 10/08/2012 16:00:00 10/08/2012 16:00:00
2 samsung notprocessed null null null
3 nokia processed cancelled 10/08/2012 16:00:00 10/08/2012 17:00:00
4 motorola notprocessed null null null
5 HTC processed null 10/08/2012 17:00:00 null
I tried below way but not returning any records.Please help me.
SELECT *
FROM
order
WHERE
to_char(order_time,'YYYYMMDD HH24:MI:SS')>To_char(sysdate,YYYYMMDD) || ' '|| '17:00:00'
and to_char(cancel_time,'YYYYMMDD HH24:MI:SS')>To_char(sysdate,YYYYMMDD) || ' '|| '17:00:00'
and order_time is null
and cancel_time is null
Select * from order
where
( to_char(order_time,'YYYYMMDD HH24:MI:SS')>To_char(sysdate,YYYYMMDD) || ' '|| '17:00:00'
or order_time is null )
and ( to_char(cancel_time,'YYYYMMDD HH24:MI:SS')>To_char(sysdate,YYYYMMDD) || ' '|| '17:00:00'
or cancel_time is null )
select *
from order o
where o.order_status != 'processed'
and o.cancel_status = 'cancelled'
and o.order_time < (trunc(sysdate) + 17/24)
and o.cancel_time < (trunc(sysdate) + 17/24)