Grouping COUNT by Time in MySql - mysql

I have a simple query that give me the count of application types; it looks something like this:
SELECT Application_Type, COUNT(*) FROM Loan_Applications GROUP BY Application_Type;
It returns something like this:
Home 3
Car 21
Commercial 16
There is a field in the database called Submission_Date (Of type Date)
How can I query and break up this data by week?
Type This week Last week 2 weeks ago
Home 1 1 1
Car 9 6 6
Commercial 10 0 3

You can try something like:
SELECT
Application_Type,
SUM(IF(Submission_Date BETWEEN CURRENT_DATE AND CURRENT_DATE - INTERVAL 1 WEEK, 1, 0)) AS 'This week',
SUM(IF(Submission_Date BETWEEN CURRENT_DATE- INTERVAL 1 WEEK AND CURRENT_DATE - INTERVAL 2 WEEK, 1, 0)) AS 'Last week',
SUM(IF(Submission_Date BETWEEN CURRENT_DATE- INTERVAL 2 WEEK AND CURRENT_DATE - INTERVAL 3 WEEK, 1, 0)) AS '2 weeks ago',
FROM Loan_Applications
GROUP BY Application_Type
;
Or:
SET #date1w = CURRENT_DATE - INTERVAL 1 WEEK;
SET #date2w = CURRENT_DATE - INTERVAL 2 WEEK;
SET #date3w = CURRENT_DATE - INTERVAL 3 WEEK;
SELECT
Application_Type,
SUM(IF(Submission_Date BETWEEN CURRENT_DATE AND #date1w, 1, 0)) AS 'This week',
SUM(IF(Submission_Date BETWEEN #date1w AND #date2w, 1, 0)) AS 'Last week',
SUM(IF(Submission_Date BETWEEN #date2w AND #date3w, 1, 0)) AS '2 weeks ago',
FROM Loan_Applications
GROUP BY Application_Type
;

You can make a SUMIF type of calculation. The following sums the number of rows where the submission date is within the last week.
SUM(CASE WHEN submission_date >= CURDATE() - 7 THEN 1 ELSE 0 END)
You could then repeat this for different ranges, to get any "bands" that you desire.

Try
SELECT
Application_Type,
SUM(WEEKOFYEAR(Submission_Date) = WEEKOFYEAR(NOW())) AS `This week`,
SUM(WEEKOFYEAR(Submission_Date) = WEEKOFYEAR(DATE_ADD(NOW(),INTERVAL -1 WEEK))) AS `Last week`,
SUM(WEEKOFYEAR(Submission_Date) = WEEKOFYEAR(DATE_ADD(NOW(),INTERVAL -2 WEEK))) AS `2 weeks ago`
FROM Loan_Applications GROUP BY Application_Type;
;
it is based on the fact that SUM of a boolean expression in the group by will count the cases when the expression is true

Related

how to get weeklytotal and yesterday record in mysql in one table

Hi Everyone i am trying to implement query to get weekly and yesterday data in same table,
dummy output i have shared below, if yesterday not exist as per employee_id it should we showing 0 also as per my table week start from monday and end at sunday.please help me out how to query this get weekly_total and yesterday record and one table.
Table name-dailydata-
Sample data
employee_id
date
total
20
2022-04-25
10
20
2022-04-26
20
20
2022-04-27
20
20
2022-04-28
10
20
2022-04-29
20
20
2022-04-30
30
20
2022-04-31
40
20
2022-05-01
50
40
2022-04-26
20
expected output
employee_id
weekly_total
yesterday_record
20
200
40
40
20
0
mysql query to get weekly data
select employee_id,sum(total) as week_total from dailydata where date between '2022-04-25' and '2022-05-01'
You can try to use the condition aggregate function to make it.
We might add non-aggregate columns in the group by when we are using aggregate functions.
select employee_id,
SUM(total) as week_total,
SUM(CASE WHEN DATEDIFF('2022-05-01',date) = 1 THEN total ELSE 0 END) yesterday_record
from dailydata t1
where date between '2022-04-25' and '2022-05-01'
GROUP BY employee_id
You can use a case in the query to get yesterdays data, as long as the where does not exclude it, which is the case in the second query.
Once you have understood the principal you can define the date range so that it is calculated dynamically when you run the script if what you want is to see yesterday's figure and the last 7 days total.
You can also get yesterday using SUBDATE(NOW(),1) which is shorter.
select
employee_id,
sum(total) as week_total ,
sum(case when date = DATE_SUB(CURDATE(), INTERVAL 1 DAY)
then total else 0 end as yesterday
from dailydata
where date between
DATE_SUB(CURDATE(), INTERVAL 1 WEEK)
and DATE_SUB(CURDATE(), INTERVAL 1 DAY) ;
select
employee_id,
sum(total) as week_total ,
sum(case when date = DATE_SUB(CURDATE(), INTERVAL 1 DAY)
then total else 0 end as yesterday
from dailydata
where date between '2022-04-25' and '2022-05-01';
Hope this may help you, You just need to use the aggregate function in the case of IFNULL.
DBFiddle URL: Click Here
For the start of the week
SELECT SUBDATE(CURDATE(), weekday(CURDATE())); --Start of week
For the end of the week
SELECT DATE(CURDATE() + INTERVAL (6 - WEEKDAY(CURDATE())) DAY); --End of week
Hereby SQL query for getting employe wise total and yesterday total. If yesterday's total doesn't exist so for that Have used IFNULL. Just used SUBDATE for getting the start and end of the week date by passing current date.
SELECT employee_id,
IFNULL(SUM(total),0) AS total,
IFNULL(SUM(CASE date WHEN subdate(CURDATE(), 1) THEN total ELSE 0 END),0) AS yesterday_total
FROM dailydata
WHERE date BETWEEN
SUBDATE(CURDATE(), weekday(CURDATE())) AND (CURDATE() + INTERVAL (6 - WEEKDAY(CURDATE())) DAY)
GROUP BY employee_id
Start of this week:
SELECT DATEADD(wk, DATEDIFF(wk, 0, GETDATE()), 0)
End of this week:
SELECT DATEADD(wk, DATEDIFF(wk, 0, GETDATE()), 6)
Yesterday:
select GETDATE() -1
Your query:
select
employee_id,
sum(total) as week_total,
(select sum(total) as week_total
from dailydata b
where [date] = convert(date, getdate() -1 )
and a.employee_id = b.employee_id) as yesterday_record
from
dailydata a
where
[date] between dateadd(wk, datediff(wk, 0, getdate()), 0) and dateadd(wk, datediff(wk, 0, getdate()), 6)
group by
employee_id

Converting a lookup over a week to a month?

I have a lookup that gets and groups results on a weekly basis:
SELECT
COUNT(IF(YEARWEEK(Submitted, 1) = YEARWEEK(NOW(), 1), 1, null)) AS Bookings,
COUNT(IF(YEARWEEK(Submitted, 1) = YEARWEEK(NOW()- INTERVAL 1 WEEK, 1), 1, null)) AS LastWeekBookings
FROM Bookings
Is there a month alternative to YEARWEEK that can get the year and month and previous month to count the bookings over a month instead?
You can use the function LAST_DAY() to determine the current or the previous month:
SELECT
SUM(LAST_DAY(Submitted) = LAST_DAY(NOW()) AS Bookings,
SUM(LAST_DAY(Submitted) = LAST_DAY(NOW()- INTERVAL 1 MONTH)) AS LastMonthBookings
FROM Bookings
There's no simple function that combines year and month the way YEARWEEK() combines year and week. So just compare both separately. And subtract INTERVAL 1 MONTH instead of INTERVAL 1 WEEK.
SELECT
COUNT(IF(YEAR(Submitted) = YEAR(NOW()) AND MONTH(Submitted) = MONTH(NOW()), 1, null)) AS Bookings,
COUNT(IF(YEAR(Submitted) = YEAR(NOW() - INTERVAL 1 MONTH) AND MONTH(Submitted) = MONTH(NOW() - INTERVAL 1 MONTH), 1, null)) AS LastMonthBookings
FROM Bookings

Percentage change from previous row when multiple rows have the same date?

I have a query that calculates ratios and returns them for each hour and server on a given day:
SELECT a.day,
a.hour,
Sum(a.gemspurchased),
Sum(b.gems),
Sum(b.shadowgems),
( Sum(b.gems) / Sum(a.gemspurchased) ) AS GemRatio,
( Sum(b.shadowgems) / Sum(a.gemspurchased) ) AS ShadowGemRatio
FROM (SELECT Date(Date_sub(createddate, INTERVAL 7 hour)) AS day,
Hour(Date_sub(createddate, INTERVAL 7 hour)) AS hour,
serverid,
Sum(gems) AS GemsPurchased
FROM dollartransactions
WHERE Date(Date_sub(createddate, INTERVAL 7 hour)) BETWEEN
Curdate() - INTERVAL 14 day AND Curdate()
GROUP BY 1,
2,
3) a,
/*Gems recorded from DollarTransactions Table after purchasing gem package*/
(SELECT Date(Date_sub(createddate, INTERVAL 7 hour)) AS day,
Hour(Date_sub(createddate, INTERVAL 7 hour)) AS hour,
serverid,
Sum(acceptedamount) AS Gems,
Sum(acceptedshadowamount) AS ShadowGems
FROM gemtransactions
WHERE Date(Date_sub(createddate, INTERVAL 7 hour)) BETWEEN
Curdate() - INTERVAL 14 day AND Curdate()
AND transactiontype IN ( 990, 2 )
AND fullfilled = 1
AND gemtransactionid >= 130000000
GROUP BY 1,
2,
3) b
/*Gems & Shadow Gems spent, recorded from GemTransactions Table */
WHERE a.day = b.day
AND a.serverid = b.serverid
GROUP BY 1,
2
This code returns the component parts of the ratios, as well as the ratios themselves (which are sometimes null):
day hour sum(a.GemsPurchased) sum(b.Gems) sum(b.ShadowGems) GemRatio ShadowGemRatio
9/5/2014 0 472875 465499 60766 0.9844 0.1285
9/5/2014 1 350960 371092 45408 1.0574 0.1294
9/5/2014 2 472985 509618 58329 1.0775 0.1233
9/5/2014 3 1023905 629310 71017 0.6146 0.0694
9/5/2014 4 1273170 628697 74896 0.4938 0.0588
9/5/2014 5 998920 637709 64145 0.6384 0.0642
9/5/2014 6 876470 651451 68977 0.7433 0.0787
9/5/2014 7 669100 667217 81599 0.9972 0.122
What I'd like to do is create an 8th and 9th column which calculate the % change from previous row for both GemRatio and ShadowGemRatio. I've seen other threads here on how to do this for specific queries, but I couldn't get it to work for my particular MySQL query...
Ok first create a view for that query. Let's call it v1:
CREATE VIEW v1 AS SELECT YOUR QUERY HERE;
Now here is the query to have the ratios. I assumed a day has 24 hours. The first row ratio change will be zero.
select now.*,
CASE
WHEN yesterday.gemRatio is null THEN 0
ELSE 100*(now.gemRatio-yesterday.gemRatio)/yesterday.gemRatio
END as gemChange,
CASE
WHEN yesterday.ShadowGemRatio is null THEN 0
ELSE 100*(now.ShadowGemRatio-yesterday.ShadowGemRatio)/yesterday.ShadowGemRatio
END as shadowGemChange
from v1 now left outer join v1 yesterday on
((now.day = yesterday.day && now.hour = yesterday.hour+1) ||
(DATEDIFF(now.day,yesterday.day) = 1 && now.hour = 0 && yesterday.hour=23))

Last date in quarter MySQL

I have a table with some dates. I need a query which will return the max (last) date from this table and last date of quarter this max date belongs to.
So for data i table
ID| EDATE
--+----------
1|2014-03-06
2|2014-10-12
this query should return 2014-10-12 and 2014-12-31.
As I understand you want the last day of the quarter, so 31 March, 30 June, 30 Sept, 31 Dec? So you can use the answer from Gordon Linoff and adjust it to do that.
You only need a case statement on month(date) and concat that with the year.
http://dev.mysql.com/doc/refman/5.1/de/control-flow-functions.html
str_to_date(
concat(
year(edate),
(case
when month(edate) in (1, 2, 3) then '-03-31'
when month(edate) in (4, 5, 6) then '-06-30'
when month(edate) in (7, 8, 9) then '-09-30'
else '-12-31'
end)
),
'%Y-%m-%d'
)
Getting the day of the last quarter for the date is a bit yucky, but possible. Here is a sort of brute force solution:
select edate,
str_to_date(concat(year(edate), '-', 1 + floor((month(edate) - 1)/ 3)) * 3, '-',
(case when month(edate) in (1, 2, 3, 10, 11, 12) then 31 else 30 end)),
'%Y-%m-%d'
)
from table t
order by edate desc
limit 1;
Here is a SQL Fiddle that demonstrates it.
You can use LAST_DAY to select the last day of a specific month depending on where your quarters end you may have to change the 3,6,9,12 to different months.
select t1.max_date,
(
case
when month(max_date) <= 3
then last_day(concat(year(max_date),'-3-1'))
when month(max_date) <= 6
then last_day(concat(year(max_date),'-6-1'))
when month(max_date) <= 9
then last_day(concat(year(max_date),'-9-1'))
else last_day(concat(year(max_date),'-12-1'))
end
) last_quarter_day
from (
select max(EDATE) max_date from myTable
) t1
I found the simplest answer:
SELECT MAKEDATE(YEAR(edate),1)
+ INTERVAL QUARTER(edate) QUARTER
- INTERVAL 1 DAY
This query takes the first day of year, adds quarters to it and subtracts 1 day to get the last day in wanted quarter. So the required query should look like:
SELECT MAX(edate),
MAKEDATE(YEAR(MAX(edate)),1)
+ INTERVAL QUARTER(MAX(edate)) QUARTER
- INTERVAL 1 DAY
FROM table

Changing start-date in MySQL for week

I found the following code to help in creating a weekly report based on a start date of Friday. The instructions say to replace ".$startWeekDay." with a 4. When I put '".$startDay."' as '2013-01-30', I get errors.
Also I get a report by day rather than week as I desire.
SELECT SUM(cost) AS total,
CONCAT(IF(date - INTERVAL 6 day < '".$startDay."',
'".$startDay."',
IF(WEEKDAY(date - INTERVAL 6 DAY) = ".$startWeekDay.",
date - INTERVAL 6 DAY,
date - INTERVAL ((WEEKDAY(date) - ".$startWeekDay.")) DAY)),
' - ', date) AS week,
IF((WEEKDAY(date) - ".$startWeekDay.") >= 0,
TO_DAYS(date) - (WEEKDAY(date) - ".$startWeekDay."),
TO_DAYS(date) - (7 - (".$startWeekDay." - WEEKDAY(date)))) AS sortDay
FROM daily_expense
WHERE date BETWEEN '".$startDay."' AND '".$endDay."'
GROUP BY sortDay;
The following code is what I am using
SELECT count(DISTINCT (
UserID)
) AS total, CONCAT(IF(date(LastModified) - INTERVAL 6 day < date(LastModified),
date(LastModified),
IF(WEEKDAY(date(LastModified) - INTERVAL 6 DAY) = 4,
date(LastModified) - INTERVAL 6 DAY,
date(LastModified) - INTERVAL ((WEEKDAY(date(LastModified)) - 4)) DAY)),
' - ', date(LastModified)) AS week
FROM `Purchase`
WHERE `OfferingID` =87
AND `Status`
IN ( 1, 4 )
GROUP BY week
The output I get is
total week
3 2013-01-30 - 2013-01-30
1 2013-01-31 - 2013-01-31
I'm not sure exactly how you want to display your week, the sql above is attempting to display date ranges. If this isn't a requirement, your query could be very simple, you can just offset your time by two days (since friday is two days away from the natural star of the week) and use the week function to get the week number.
The query would look like this:
select count(distinct (UserID)) as total
, year( LastModified + interval 2 day ) as year
, week( LastModified + interval 2 day ) as week_number
FROM `Purchase`
WHERE `OfferingID` =87
AND `Status`
IN ( 1, 4 )
group by year, week_number;