How to get count and sum with multiple parameter in case when - mysql

I have the following table in MySQL (Version - 5.7.18-log).
ID Old_Date Curr_Date Status Price items
ID-1 2021-07-14 2021-09-30 13:15:15 Done 1500 3
ID-1 2021-06-26 2021-09-30 13:15:15 Hold 3500 6
ID-1 2021-05-26 2021-09-30 13:15:15 In Progress 4500 1
ID-1 2021-03-04 2021-09-30 13:15:15 Done 5000 3
ID-1 2021-01-11 2021-09-30 13:15:15 Done 2800 2
From the above table, I need to fetch the count & sum of instances where status is Done and Hold in the last 1, 6, and 9-month intervals.
The interval needs to be calculated between Old_Date and Curr_Date.
Required Output-
ID 1_Month_Count 6_Month_Count 9_Month_Count 1_Month_Sum 6_Month_Sum 9_Month_Sum
ID-1 0 2 4 0 5000 12800
I have tried following query but It is not working.
SELECT ID,
SUM(CASE WHEN TIMESTAMPDIFF(month, Old_Date, Curr_Date) <= 12
WHEN (Status IN ('Done', 'Hold') THEN SUM(ID) ELSE 0 END) AS 12_Month_Done`,
FROM Table
Group BY ID;

If you want in the results only the IDs that match your conditions then use conditional aggregation after filtering the table:
SELECT ID,
COUNT(CASE WHEN Old_Date >= Curr_Date - INTERVAL 1 month THEN 1 END) AS `1_Month_Count`,
COUNT(CASE WHEN Old_Date >= Curr_Date - INTERVAL 6 month THEN 1 END) AS `6_Month_Count`,
COUNT(*) AS `9_Month_Count`,
SUM(CASE WHEN Old_Date >= Curr_Date - INTERVAL 1 month THEN Price ELSE 0 END) AS `1_Month_Sum`,
SUM(CASE WHEN Old_Date >= Curr_Date - INTERVAL 6 month THEN Price ELSE 0 END) AS `6_Month_Sum`,
SUM(Price) AS `9_Month_Sum`
FROM tablename
WHERE Status IN ('Done', 'Hold') AND Old_Date >= Curr_Date - INTERVAL 9 month
GROUP BY ID;
If you want all the IDs even if they don't match the conditions:
SELECT ID,
COUNT(CASE WHEN Old_Date >= Curr_Date - INTERVAL 1 month
AND Status IN ('Done', 'Hold') THEN 1 END) AS `1_Month_Count`,
COUNT(CASE WHEN Old_Date >= Curr_Date - INTERVAL 6 month
AND Status IN ('Done', 'Hold') THEN 1 END) AS `6_Month_Count`,
COUNT(CASE WHEN Old_Date >= Curr_Date - INTERVAL 9 month
AND Status IN ('Done', 'Hold') THEN 1 END) AS `9_Month_Count`,
SUM(CASE WHEN Old_Date >= Curr_Date - INTERVAL 1 month
AND Status IN ('Done', 'Hold') THEN Price ELSE 0 END) AS `1_Month_Sum`,
SUM(CASE WHEN Old_Date >= Curr_Date - INTERVAL 6 month
AND Status IN ('Done', 'Hold') THEN Price ELSE 0 END) AS `6_Month_Sum`,
SUM(CASE WHEN Old_Date >= Curr_Date - INTERVAL 9 month
AND Status IN ('Done', 'Hold') THEN Price ELSE 0 END) AS `9_Month_Sum`
FROM tablename
GROUP BY ID;
See the demo.

I think a stored procedure would be a way to achieve this.
In this procedure you will have to do 3 queries for 1, 6 and 9 months.
like
SELECT COUNT(ID) as cnt_id, SUM(price) as sum_price INTO 1_month_count, 1_month_sum WHERE status = 'Hold' OR status = 'Done' AND TIMESTAMPDIFF(MONTH, old_date, curr_date) >= 1 AND TIMESTAMPDIFF(MONTH, old_date, curr_date) < 6;
then you return your variables 1_month_count etc. by
SELECT #1_month_count, #1_month_sum; /*and all others*/
More information about store procedures with OUT parameters can be found here:
https://dev.mysql.com/doc/refman/8.0/en/create-procedure.html

Related

how to calculate mysql date diff between two dates excluding Fridays and Saturdays?

how to calculate mysql date diff between two dates excluding Fridays and Saturdays as Fridays and Saturdays are off days
i've tried
SELECT ((DATEDIFF('2022-01-02', '2021-12-30'))+1 - ((WEEK('2022-01-02') - WEEK('2021-12-30')) * 2) - (case when weekday('2022-01-02') = 5 then 1 else 0 end) - (case when weekday('2021-12-30') = 4 then 1 else 0 end)) as DifD
but it gives wrong count (105 days) and suppose to give 2 days
you need to use case expression to check if the day is Thursday then add -2
SELECT ((DATEDIFF('2014-10-25', '2014-10-15')) -
((WEEK('2014-10-25') - WEEK('2014-10-15')) * 2) -
(case when weekday('2014-10-25') = 5 then 1 else 0 end) -
(case when weekday('2014-10-15') = 4 then 1 else 0 end)) as DifD
// Total difference
SELECT ((DATEDIFF('2014-10-25', '2014-10-15'))
// calendar week(s) ---> not including the year
WEEK('2022-01-02') // = 1
WEEK('2021-12-30') // = 52
// get weekday, where 0 is monday and 6 is sunday
case when weekday('2022-01-02') = 4 // (or 5) subtract 1
If you want this to work on different years, like your example above u have to add 52 weeks for every year difference.
a working example would be:
SELECT ((DATEDIFF('2022-01-02', '2021-12-30'))+1 - ((WEEK('2022-01-02') - WEEK('2021-12-30') + 52) * 2) - (case when weekday('2022-01-02') = 5 then 1 else 0 end) - (case when weekday('2021-12-30') = 4 then 1 else 0 end)) as DifD
Thank you everyone for helping, i found the answer from here mysql-function to count days between 2 dates excluding weekends
CREATE FUNCTION TOTAL_WEEKDAYS(date1 DATE, date2 DATE) RETURNS INT RETURN ABS(DATEDIFF(date2, date1)) + 1 - ABS(DATEDIFF(ADDDATE(date2, INTERVAL 1 - DAYOFWEEK(date2) DAY), ADDDATE(date1, INTERVAL 1 - DAYOFWEEK(date1) DAY))) / 7 * 2 - (DAYOFWEEK(IF(date1 < date2, date1, date2)) = 6) - (DAYOFWEEK(IF(date1 > date2, date1, date2)) = 7);
sql query for any dates e.g. :
SELECT TOTAL_WEEKDAYS('2022-01-09', '2022-01-12') weekdays1;

count new users by each months in sql

i am trying to count new users recorded by each month of this year.
like
Need data month wise, which is registerd by month new users
JAn Feb Mar April May ..... Dec
1 2 4 2 5 ..... 1
through created_at date and user Id.
here is user_table
id created_at
1 2020-01-09 22:38:55
2 2020-02-09 22:38:55
3 2020-02-09 22:38:55
4 2020-03-09 22:38:55
5 2020-03-09 22:38:55
6 2020-03-09 22:38:55
7 2020-04-09 22:38:55
8 2020-04-09 22:38:55
9 2020-05-09 22:38:55
i am trying with this query
SELECT ut.id, Month(FROM_UNIXTIME(ut.created_at)), Count(*)
from $userTable ut
where FROM_UNIXTIME(ut.created_at) >= CURDATE() - INTERVAL 1 YEAR
GROUP BY Month(FROM_UNIXTIME(ut.created_at));
You can group by year and sum by month like this:
select YEAR(created_at) as year,
sum(case when Month(created_at) = 1 then 1 else 0 end) AS Jan,
sum(case when Month(created_at) = 2 then 1 else 0 end) AS Feb,
sum(case when Month(created_at) = 3 then 1 else 0 end) AS Mar,
sum(case when Month(created_at) = 4 then 1 else 0 end) AS Apr,
sum(case when Month(created_at) = 5 then 1 else 0 end) AS May,
sum(case when Month(created_at) = 6 then 1 else 0 end) AS Jun,
sum(case when Month(created_at) = 7 then 1 else 0 end) AS Jul,
sum(case when Month(created_at) = 8 then 1 else 0 end) AS Aug,
sum(case when Month(created_at) = 9 then 1 else 0 end) AS Sep,
sum(case when Month(created_at) = 10 then 1 else 0 end) AS Oct,
sum(case when Month(created_at) = 11 then 1 else 0 end) AS Nov,
sum(case when Month(created_at) = 12 then 1 else 0 end) AS Dec from ut group by YEAR(created_at)
all columns that being used in the select that are not an aggregated function need to be grouped, ut.id is not group and in your case should be removed from the select
Try
SELECT Month(FROM_UNIXTIME(ut.created_at)), Count(*) from $userTable ut
where FROM_UNIXTIME(ut.created_at) >= CURDATE() - INTERVAL 1 YEAR
GROUP BY Month(FROM_UNIXTIME(ut.created_at));
If you want to mix data from this year and last year for the past 12 months, you can use:
SELECT SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 1) AS Jan,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 2) AS Feb,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 3) AS Mar,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 4) AS Apr,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 5) AS May,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 6) AS Jun,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 7) AS Jul,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 8) AS Aug,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 9) AS Sep,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 10) AS Oct,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 11) AS Nov,
SUM(MONTH(FROM_UNIXTIME(ut.created_at)) = 12) AS Dec
FROM ut
WHERE FROM_UNIXTIME(ut.created_at) >= CURDATE() - INTERVAL 1 YEAR
Note: This assumes that FROM_UNIXTIME() is a actually necessary. It also uses a convenient MySQL shortcut for conditional aggreation.

MySQL - How to populate weekly data in a month

How to select data from following table group by weeks in a month
Date Project Value Week
+----------+--------------+-------+------+
2018-11-07 A 2 45
2018-11-08 B 4 45
2018-11-09 C 3 45
2018-11-12 B 6 46
2018-11-13 A 5 46
2018-11-14 C 6 46
(First week is end on sunday or week number in a month)
So my result should look like this.
Project 1st Week 2nd Week 3rd Week 4th Week 5th Week
+----------+--------+--------+--------+--------+--------
A 0 2 5 0 0
B 0 4 6 0 0
C 0 3 6 0 0
I try this one :
SELECT project, value, week, date
FROM module_progress
WHERE
created_at BETWEEN '2018-11-01 00:00:00' AND '2018-11-31
AND date > DATE_SUB(NOW(), INTERVAL 1 WEEK) 23:59:59'
GROUP BY week
Thank you
Just use a sub query to get first week no for the month, and sum case statements for each week:
select year(date) as y, month(date) as m, project,
sum(case when week=w0 then value else 0 end) as w1,
sum(case when week=w0+1 then value else 0 end) as w2,
sum(case when week=w0+2 then value else 0 end) as w3,
sum(case when week=w0+3 then value else 0 end) as w4,
sum(case when week=w0+4 then value else 0 end) as w5
from #date d
join (select year(date) as y, month(date) as m, min(week) as w0 from #date group by year(date), month(date))
as d0 on d0.y=year(date) and d0.m=month(date)
group by year(date), month(date), project

SELECT between 7am and 7am next day

i want to count how many values of 1 and 0 i have between 7am and 7am next day.
think here a bar that opens at 10am but closes next day at 7am, they want their 'report' to be for this specific day.
so all data before 7am needs to be added to the day before.
SELECT DATE(delivered), COUNT(*) total,
sum(case when isbag = '0' THEN 1 ELSE 0 END) CloakCount,
sum(case when isbag = '1' THEN 1 ELSE 0 END) BagCount
FROM Wardrobe_CloakTable GROUP BY DATE(delivered)
this will give me almost what i want, the problem is that i need to count all those data before 7am, to the day before.
Something like this should work:
SELECT
CASE WHEN HOUR(delivered) < 7
THEN CONCAT(DATE(DATE_ADD(delivered, INTERVAL -1 day)), ' 07:00:00')
ELSE CONCAT(DATE(delivered), ' 07:00:00')
END as startTime,
CASE WHEN HOUR(delivered) < 7
THEN CONCAT(DATE(delivered), ' 07:00:00')
ELSE CONCAT(DATE(DATE_ADD(delivered, INTERVAL 1 day)), ' 07:00:00')
END as endTime,
COUNT(*) total,
sum(case when isbag = '0' THEN 1 ELSE 0 END) CloakCount,
sum(case when isbag = '1' THEN 1 ELSE 0 END) BagCount
FROM Wardrobe_CloakTable GROUP BY startTime, endTime;

MySQL query error...it does not display the exact data values

I want to ask if what is wrong (and probably ask for suggestions on how to better do it) with my MySQL query? I'm trying to generate a daily report within a range of 5days... the problem is it does not display the exact datas, It fills up days that does not have data in it.
This is the case of the MySQL query example below:
In my database, monday, wed and thursday are with datas.. but if I will run the reports using this query, tuesday will have an existing data which it does not actually has in my database. Although the IT, NonIt, and Total table count is correct. I have errors in counting the datas in my days only. please help me... I don't know where the errors already.
To better explain what I mean, here is the screenshot of the output result of my query:
http://www.fileden.com/files/2011/7/27/3174077//daily.JPG
SELECT a.specialist_partner_ID, ss.first_name as SS, ssa.first_name as SSA
,count(CASE WHEN a.receivedDate BETWEEN '2011-09-5' AND '2011-09-9'
THEN a.job_order_number ELSE null END) As MON
,count(CASE WHEN a.receivedDate BETWEEN date_add('2011-09-5', INTERVAL 1 DAY)
AND DATE_ADD('2011-09-9', INTERVAL 1 DAY) THEN a.job_order_number ELSE null END) As TUE
,count(CASE WHEN a.receivedDate BETWEEN date_add('2011-09-5', INTERVAL 2 DAY)
AND DATE_ADD('2011-09-9', INTERVAL 2 DAY) THEN a.job_order_number ELSE null END) As WED
,count(CASE WHEN a.receivedDate BETWEEN date_add('2011-09-5', INTERVAL 3 DAY)
AND DATE_ADD('2011-09-9', INTERVAL 3 DAY) THEN a.job_order_number ELSE null END) As THU
,count(CASE WHEN a.receivedDate BETWEEN date_add('2011-09-5', INTERVAL 4 DAY)
AND DATE_ADD('2011-09-9', INTERVAL 4 DAY) THEN a.job_order_number ELSE null END) As FRI
,count(case WHEN (a.receivedDate between '2011-09-5 00:00:00' and '2011-09-9 23:59:59'
and jo.job_order_type LIKE 'IT') then a.job_order_number else null end) as IT
,count(case WHEN (a.receivedDate between '2011-09-5 00:00:00' and '2011-09-9 23:59:59'
and jo.job_order_type LIKE 'Non-IT') then a.job_order_number else null end) as NonIT
,count(a.job_order_number) As Total FROM jo_partner a
left join specialist_partner sp on a.specialist_Partner_ID = sp.specialistPartnerID
left join staffing_specialist_asst ssa on sp.SSA_ID = ssa.SSA_ID
left join staffing_specialist ss on sp.SS_ID = ss.SS_ID
left join job_order jo on a.job_order_number = jo.job_order_number
left join candidate_jo cjo on a.JO_partner_ID= cjo.jo_partner_ID
left join candidate can on cjo.candidate_jo_ID= can.candidate_ID
WHERE a.receivedDate BETWEEN '2011-09-5 00:00:00' AND '2011-09-9 23:59:59'
GROUP BY a.specialist_partner_ID
I think you have wrong dates. For every day column you are selecting data from 5 days, this has no sense.
So instead of:
count(CASE WHEN a.receivedDate BETWEEN date_add('2011-09-5', INTERVAL 1 DAY)
AND DATE_ADD('2011-09-9', INTERVAL 1 DAY) THEN a.job_order_number ELSE null END) As TUE
You should have:
count(CASE WHEN a.receivedDate BETWEEN date_add('2011-09-5', INTERVAL 1 DAY)
and DATE_ADD('2011-09-5', INTERVAL 2 DAY) THEN a.job_order_number ELSE null END) As TUE
Or even better:
count(CASE WHEN a.receivedDate >= date_add('2011-09-5', INTERVAL 1 DAY)
and a.receivedDate < DATE_ADD('2011-09-5', INTERVAL 2 DAY) THEN a.job_order_number ELSE null END) As TUE
The same for the rest of the days.