MySQL ordering by enum on grouped data - mysql

I want to return the most recent action in the timetable that has taken place, grouped by channel- but ordered by enum. The timetable can have 'WEEKDAY' options, or specific days ('WED'). The specific days need to take precedence over the 'WEEKDAY' option.
CREATE TABLE `heatingtimetable` (
`id` int(11) NOT NULL,
`channel` enum('CENTRALHEATING','HOTWATER') NOT NULL,
`command` enum('ON','OFF') NOT NULL DEFAULT 'OFF',
`thetime` time NOT NULL,
`day` enum('SUN','MON','TUE','WED','THU','FRI','SAT','WEEKDAY','WEEKEND','HOLIDAY') NOT NULL
);
INSERT INTO `heatingtimetable` (`id`, `channel`, `command`, `thetime`, `day`) VALUES
(1, 'CENTRALHEATING', 'ON', '08:00:00', 'WEEKDAY'),
(2, 'CENTRALHEATING', 'OFF', '10:00:00', 'WEEKDAY'),
(13, 'CENTRALHEATING', 'ON', '07:00:00', 'WED'),
(14, 'CENTRALHEATING', 'OFF', '9:00:00', 'WED');
https://www.db-fiddle.com/#&togetherjs=NEuAL2we4r
I can get back the most recent- but not a custom/enum order as the group by happens first- the most recent time always comes up. Assuming that is it 10.15am on a Wednesday- this brings back WEEKDAY, but needs to bring back 'WED 9am' row 14.
SELECT h.channel, command, h.thetime, day FROM
(SELECT channel, MAX(thetime) as thetime
FROM `heatingtimetable`
where thetime < '10:15'
AND
(DAYOFWEEK(CURDATE()) >= 2 AND DAYOFWEEK(CURDATE()) <=6 AND day = 'WEEKDAY') || (DAYOFWEEK(CURDATE()) = day)
group by channel) as l
INNER JOIN heatingtimetable h on h.channel = l.channel and h.thetime = l.thetime```

Rethink structure if you can
I managed a solution here below, but wow it isn't pretty. I would really really recommend thinking about structuring this differently so that comparing current day/time to the entries is easier. Hopefully you have control of the table structure and such.
Think first about what query you would like to use. Then you can work from there to find the best table structure to suit such queries. A comparison of datetimes would be a lot friendlier since you can do math that includes both the date and the time. Also mixing different types like WED, FRI, WEEKDAY, WEEKEND and having them as enums with no natural way of ranking them is problematic. That's why this query below is gigantic. If you could get rid of the different types being mixed that would help. If you can't do that, you could perhaps add a new column that helps you rank WED higher than WEEKDAY.
We need a way to rank these
I understand about the WED vs WEEKDAY precedence now. In that case, we can do this by making our own ranking value. We want to rank a matching DAYOFWEEK as higher than a matching WEEKDAY/WEEKEND, etc. And then you also want to rank by time with lower priority than those. So we can order by these 3 different things in that order.
CASE WHEN/THEN/ELSE comes in handy for conditionals.
There are MANY situations to consider here
By the way, your query does not return the most recent like you said in some situations. If today is Saturday, then DAYOFWEEK(CURDATE()) will be 7 and you will have no rows returned. You probably want row 2 to be returned since it would be the most recent. Your query also didn't consider WEEKENDs in any way.
What if the current day matches the table entry's day, but the current time is after the table entry's time? We should not count that entry as matching the day. So we have to include a time check in these ranking values.
Adding on to that-
What if today is Friday and that doesn't match the day of any entries... but you have one entry for WEEKDAY and one for THU? Which would be preferred as the most recent? I assume you would want THU to be preferred to WEEKDAY like if it is the same day. And if the choice was between WED and WEEKDAY, then WEEKDAY would be preferred because Thursday is a more recent weekday than WED.
It gets quite complicated.
CURTIME()
Also, I noticed you specified the current day in SQL using CURDATE(), but for the time you just entered a constant value '10:15'. I'm not sure where that comes from, but if you want to do that in SQL also, it would just be - CURTIME(). You can also get both the date and time together with NOW().
Set up the scoring
I created the following ranking values:
day_score1 - This will be 1 if the day of the week matches exactly (like WED/Wednesday) and the table entry time is before the current time, otherwise 0.
day_score2 - This will be 1 if the current day matches WEEKDAY/WEEKEND and the table entry time is before the current time, otherwise 0
day_score3 - This value will be used to go backwards in days and the more recent the day, the higher the score. We have to use subraction here, and we also have to wrap around. A big problem here is that there is no way to get a weekday index number from your day values such as WED. DAYOFWEEK() will take a date and return the weekday index number, but there is no reverse. So we'll have to do a check on each possible day of the week. We won't need to consider the time in this one since we know we are going backwards at least one day.
And if we still want to have WED have higher precedence than WEEKDAY in this situation where we have to look backwards, there have to be even more lines for scoring.
thetime - And lastly I have ordering also by thetime descending because that way if we have to fall back on a previous day and there is more than one entry with that day, it will put the latest one first.
I see you have HOLIDAY there also but I ignored that. This is plenty complex already and I will not bite on that.
Here is my DB Fiddle- https://www.db-fiddle.com/f/wgSzEiWrDgAJuc88de1Fwq/0
CREATE TABLE and INSERTions below-
CREATE TABLE `heatingtimetable` (
`id` int(11) NOT NULL,
`channel` enum('CENTRALHEATING','HOTWATER') NOT NULL,
`command` enum('ON','OFF') NOT NULL DEFAULT 'OFF',
`thetime` time NOT NULL,
`day` enum('SUN','MON','TUE','WED','THU','FRI','SAT','WEEKDAY','WEEKEND','HOLIDAY') NOT NULL
);
INSERT INTO `heatingtimetable` (`id`, `channel`, `command`, `thetime`, `day`) VALUES
(1, 'CENTRALHEATING', 'ON', '08:00:00', 'WEEKDAY'),
(2, 'CENTRALHEATING', 'OFF', '10:00:00', 'WEEKDAY'),
(3, 'CENTRALHEATING', 'OFF', '22:00:00', 'WEEKDAY'),
(4, 'CENTRALHEATING', 'ON', '05:00:00', 'MON'),
(5, 'CENTRALHEATING', 'OFF', '16:00:00', 'TUE'),
(6, 'CENTRALHEATING', 'OFF', '23:00:00', 'THU'),
(7, 'CENTRALHEATING', 'OFF', '6:00:00', 'THU'),
(8, 'CENTRALHEATING', 'ON', '07:00:00', 'FRI'),
(9, 'CENTRALHEATING', 'OFF', '21:00:00', 'FRI'),
(13, 'CENTRALHEATING', 'ON', '07:00:00', 'WED'),
(14, 'CENTRALHEATING', 'OFF', '9:00:00', 'WED');
And this gigantic query-
SELECT
channel, command, thetime, day,
CASE WHEN (DAYOFWEEK(CURDATE()) = day AND thetime <= CURTIME()) THEN 1 ELSE 0 END AS day_score1,
CASE WHEN
(
(
(DAYOFWEEK(CURDATE()) >= 2 AND DAYOFWEEK(CURDATE()) <= 6 AND day = 'WEEKDAY')
OR
((DAYOFWEEK(CURDATE()) = 1 OR DAYOFWEEK(CURDATE()) = 7) AND day = 'WEEKEND')
)
AND thetime <= CURTIME()
) THEN 1 ELSE 0 END as day_score2,
CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 6 AND day = 'SAT' THEN 12 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 5 AND day = 'SUN' THEN 12 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 4 AND day = 'MON' THEN 12 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 3 AND day = 'TUE' THEN 12 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 2 AND day = 'WED' THEN 12 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 1 AND day = 'THU' THEN 12 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 0 AND day = 'FRI' THEN 12 ELSE 0 END
+
CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 6 AND day = 'FRI' THEN 10 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 5 AND day = 'SAT' THEN 10 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 4 AND day = 'SUN' THEN 10 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 3 AND day = 'MON' THEN 10 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 2 AND day = 'TUE' THEN 10 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 1 AND day = 'WED' THEN 10 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 0 AND day = 'THU' THEN 10 ELSE 0 END
+
CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 6 AND day = 'THU' THEN 8 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 5 AND day = 'FRI' THEN 8 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 4 AND day = 'SAT' THEN 8 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 3 AND day = 'SUN' THEN 8 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 2 AND day = 'MON' THEN 8 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 1 AND day = 'TUE' THEN 8 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 0 AND day = 'WED' THEN 8 ELSE 0 END
+
CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 6 AND day = 'WED' THEN 6 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 5 AND day = 'THU' THEN 6 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 4 AND day = 'FRI' THEN 6 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 3 AND day = 'SAT' THEN 6 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 2 AND day = 'SUN' THEN 6 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 1 AND day = 'MON' THEN 6 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 0 AND day = 'TUE' THEN 6 ELSE 0 END
+
CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 6 AND day = 'TUE' THEN 4 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 5 AND day = 'WED' THEN 4 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 4 AND day = 'THU' THEN 4 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 3 AND day = 'FRI' THEN 4 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 2 AND day = 'SAT' THEN 4 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 1 AND day = 'SUN' THEN 4 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 0 AND day = 'MON' THEN 4 ELSE 0 END
+
CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 6 AND day = 'MON' THEN 2 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 5 AND day = 'TUE' THEN 2 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 4 AND day = 'WED' THEN 2 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 3 AND day = 'THU' THEN 2 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 2 AND day = 'FRI' THEN 2 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 1 AND day = 'SAT' THEN 2 ELSE 0 END
+ CASE WHEN (7 - DAYOFWEEK(CURDATE())) = 0 AND day = 'SUN' THEN 2 ELSE 0 END
+
CASE
WHEN (7 - DAYOFWEEK(CURDATE())) <= 4 AND day = 'WEEKDAY' THEN 11
WHEN (7 - DAYOFWEEK(CURDATE())) >= 5 AND day = 'WEEKEND' THEN 11
WHEN (7 - DAYOFWEEK(CURDATE()) >= 6 OR 7 - DAYOFWEEK(CURDATE()) <= 3) AND day = 'WEEKDAY' THEN 9
WHEN (7 - DAYOFWEEK(CURDATE()) = 5 OR 7 - DAYOFWEEK(CURDATE()) = 4) AND day = 'WEEKEND' THEN 9
WHEN (7 - DAYOFWEEK(CURDATE()) >= 5 OR 7 - DAYOFWEEK(CURDATE()) <= 2) AND day = 'WEEKDAY' THEN 7
WHEN (7 - DAYOFWEEK(CURDATE()) = 4 OR 7 - DAYOFWEEK(CURDATE()) = 3) AND day = 'WEEKEND' THEN 7
WHEN (7 - DAYOFWEEK(CURDATE()) >= 4 OR 7 - DAYOFWEEK(CURDATE()) <= 1) AND day = 'WEEKDAY' THEN 5
WHEN (7 - DAYOFWEEK(CURDATE()) = 3 OR 7 - DAYOFWEEK(CURDATE()) = 2) AND day = 'WEEKEND' THEN 5
WHEN (7 - DAYOFWEEK(CURDATE()) >= 3 OR 7 - DAYOFWEEK(CURDATE()) <= 0) AND day = 'WEEKDAY' THEN 3
WHEN (7 - DAYOFWEEK(CURDATE()) = 2 OR 7 - DAYOFWEEK(CURDATE()) = 1) AND day = 'WEEKEND' THEN 3
WHEN (7 - DAYOFWEEK(CURDATE()) >= 2) AND day = 'WEEKDAY' THEN 1
WHEN (7 - DAYOFWEEK(CURDATE()) <= 1) AND day = 'WEEKEND' THEN 1
ELSE 0
END
AS day_score3
FROM heatingtimetable
ORDER BY day_score1 DESC, day_score2 DESC, day_score3 DESC, thetime DESC
My result right now is below. It's Friday and current time at DB-Fiddle is showing as 20:41:40.
channel
command
thetime
day
day_score1
day_score2
day_score3
CENTRALHEATING
ON
07:00:00
FRI
1
0
0
CENTRALHEATING
OFF
10:00:00
WEEKDAY
0
1
11
CENTRALHEATING
ON
08:00:00
WEEKDAY
0
1
11
CENTRALHEATING
OFF
23:00:00
THU
0
0
12
CENTRALHEATING
OFF
06:00:00
THU
0
0
12
CENTRALHEATING
OFF
22:00:00
WEEKDAY
0
0
11
CENTRALHEATING
OFF
09:00:00
WED
0
0
10
CENTRALHEATING
ON
07:00:00
WED
0
0
10
CENTRALHEATING
OFF
16:00:00
TUE
0
0
8
CENTRALHEATING
ON
05:00:00
MON
0
0
6
CENTRALHEATING
OFF
21:00:00
FRI
0
0
0

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;

In mysql How to find number of sundays in a month

In mysql how to find number of sundays in month by usnig month in where clause
Ex:
month(log_date)=month(now());
month(log_date) = 12;
output: 5 sundays
Possible way to do it which avoids using any tables. This finds the number of days in the month, and depending on that and what day of the week the last day is then it just returns a value
SELECT CASE DAYOFMONTH(LAST_DAY(NOW()))
WHEN 31 THEN
CASE DAYOFWEEK(LAST_DAY(NOW()))
WHEN 1 THEN 5
WHEN 2 THEN 5
WHEN 3 THEN 5
ELSE 4
END
WHEN 30 THEN
CASE DAYOFWEEK(LAST_DAY(NOW()))
WHEN 1 THEN 5
WHEN 2 THEN 5
ELSE 4
END
WHEN 29 THEN
CASE DAYOFWEEK(LAST_DAY(NOW()))
WHEN 1 THEN 5
ELSE 4
END
ELSE 4
END
SQL query for get total sunday in given month from DB
USE BETWEEN :- BETWEEN operator selects values within a given range.
Note :- DAYOFWEEK actually returns 1 for Sunday
SELECT count(*) AS total_sunday FROM `table` WHERE DAYOFWEEK(`date`) = 1 BETWEEN '2017-11-01' AND '2017-11-30';
In mysql just copy and paste the query given below. It will give you number of Sundays in current month.
WITH RECURSIVE offdays as(
SELECT
LAST_DAY(CURDATE()-INTERVAL 1 MONTH) + INTERVAL 1 DAY AS `Date`,
DAYNAME(LAST_DAY(CURDATE()-INTERVAL 1 MONTH) + INTERVAL 1 DAY) AS `DayName`
UNION ALL
SELECT `Date` + INTERVAL 1 DAY, DAYNAME(`Date` + INTERVAL 1 DAY)
FROM offdays WHERE `DATE` < LAST_DAY(CURDATE())
) SELECT count(*) FROM offdays where DAYNAME(DATE) = 'Sunday';
you will get number of sundays in current month. Just replace the CURDATE() with any date. The query will give you the number of Sundays of the month of the date supplied.
Try this function, you use like
count_days_in_month($date_month,$day_idx);
$day_idx is 1 - 7 where Sunday is 1, Saturday is 7
eg.
select count_days_in_month('2020-02-01',1);
delimiter //
create or replace function count_days_in_month(input_date DATE,dayindex INT)
returns INT
DETERMINISTIC
BEGIN
declare start_day_idx INT default (select dayofweek( date_sub(input_date,INTERVAL (DAYOFMONTH(input_date)-1) DAY )) from dual);
declare days_in_month INT default (SELECT dayofmonth(LAST_DAY(input_date)));
declare days_over_28 INT default (days_in_month-28);
if days_in_month > 28 then
if (days_over_28 > (dayindex-start_day_idx)) and ((dayindex-start_day_idx) >= 0) then
return 5;
else
return 4;
end if;
else
return 4;
end if;
END//
Eg to test the count of all days in a month:
select
count_days_in_month('2020-02-01',1) 'Sun',
count_days_in_month('2020-02-01',2) 'Mon',
count_days_in_month('2020-02-01',3) 'Tue',
count_days_in_month('2020-02-01',4) 'Wed',
count_days_in_month('2020-02-01',5) 'Thur',
count_days_in_month('2020-02-01',6) 'Fri',
count_days_in_month('2020-02-01',7) 'Sat'
from
dual;//

how to group by week start from friday

I have table sql like this:
This my query for count tgl:
SELECT count( tgl ) AS total, absen.id
FROM absen
WHERE absen.status = 'm'
GROUP BY absen.id
So I want group by absen.id and absen.tgl
How to group by week from Friday to Thursday?
2016-01-08 is friday and 2016-01-15 is thursday.
Bellow query can bring the result you want, but i think you defined the wrong end date, because in your example from 2015-01-08 up to 2015-01-15 its 8 day and one week has 7 days.
select
count( tgl ) AS total,
absen.id,
CASE WHEN (weekday(tgl)<=3) THEN date(tgl + INTERVAL (3-weekday(tgl)) DAY)
ELSE date(tgl + INTERVAL (3+7-weekday(tgl)) DAY)
END as week_days
FROM absen
WHERE status = 'm'
GROUP BY id,week_days
here is the fiddle fiddle
Query Description:
mysql weekday array numbers:
$weekArr = array(
'Monday' => 0,
'Tuesday' => 1,
'Wednesday' => 2,
'Thursday' => 3,
'Friday' => 4,
'Saturday' => 5,
'Sunday' => 6);
So now suppose today is Tuesday and date is 2016-01-12, now let's count from today towards the start date in our table which is 2016-01-07 and it match with Thursday of past week, so according to the weekday array number its weekday(2016-01-07) == 3 so it goes to the WHEN part of our query, and query will select something like this CASE WHEN (weekday('2016-01-07') <= 3) THEN date('2016-01-07' + INTERVAL(3-3)) that is equal to SELECT '2016-01-07' and so on for others.
I just found how to get this by trouble shooting on excel by using this WEEK('date' + INTERVAL 3 DAY, 3)

Grouping COUNT by Time in 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

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))