Select current week, starts from Monday instead of Sunday - mysql

I've managed to select the data from the current week but the week itself starts from Sunday which is not the right format for me, it should starts from Monday. I'm using MySQL to query the data.
SELECT IFNULL(SUM(rendeles_dbszam),0) as eladott_pizzak_szama
FROM rendeles
WHERE WEEK(rendeles_idopont) = WEEK(CURRENT_DATE())

'Week' in mysql has 2 inputs: date and week type. By default it's equal 0. That means week starts from sunday. Try this code:
SELECT IFNULL(SUM(rendeles_dbszam),0) as eladott_pizzak_szama FROM rendeles WHERE WEEK(rendeles_idopont) = WEEK(CURRENT_DATE(),1)

You can use this little formula to get the Monday starting the week of any given DATE, DATETIME, or TIMESTAMP object.
FROM_DAYS(TO_DAYS(datestamp) -MOD(TO_DAYS(datestamp) -2, 7))
I like to use it in a stored function named TRUNC_MONDAY(datestamp) defined like this.
DELIMITER $$
DROP FUNCTION IF EXISTS TRUNC_MONDAY$$
CREATE
FUNCTION TRUNC_MONDAY(datestamp DATETIME)
RETURNS DATE DETERMINISTIC NO SQL
COMMENT 'preceding Monday'
RETURN FROM_DAYS(TO_DAYS(datestamp) -MOD(TO_DAYS(datestamp) -2, 7))$$
DELIMITER ;
Then you can do stuff like this
SELECT IFNULL(SUM(rendeles_dbszam),0) as eladott_pizzak_szama
FROM rendeles
WHERE TRUNC_MONDAY(rendeles_idopont) = TRUNC_MONDAY(CURRENT_DATE())
or even this to get a report covering eight previous weeks and the current week.
SELECT SUM(rendeles_dbszam) as eladott_pizzak_szama,
TRUNC_MONDAY(rendeles_idopont) as week_beginning
FROM rendeles
WHERE rendeles_idopont >= TRUNC_MONDAY(CURDATE()) - INTERVAL 8 WEEK
AND rendeles_idopoint < TRUNC_MONDAY(CURDATE()) + INTERVAL 1 WEEK
GROUP BY TRUNC_MONDAY(rendeles_idopont)
I particularly like this TRUNC_MONDAY() approach because it works unambiguously even for calendar weeks that contain New Years' Days.
(If you want TRUNC_SUNDAY() change the -2 in the formula to -1.)

Related

How to get start and end week date using week number in mysql?

I can easily get the start date and end of week like below.
SELECT
COUNT(*) AS reports_in_week,
DATE_ADD(mydate, INTERVAL(1-DAYOFWEEK(mydate)) DAY),
DATE_ADD(mydate, INTERVAL(7-DAYOFWEEK(mydate)) DAY)
FROM mytable
where WEEK(mydate,1) = '29'
GROUP BY WEEK(mydate,1)
but the problem is that case indexing of column date is not working, if i pass date range between indexing will work, i try to get the start date and end date of week using week number;
I am starter in mysql please help.
If you want to filter on a given week and year, then one option is to use str_to_date() to generate a date range from a year and week number:
where
mydate >= str_to_date('2020-29 Monday', '%Y-%u %W')
and mydate < str_to_date('2020-29 Monday', '%Y-%u %W') + interval 7 day
The %u specifier represents a week number, with Monday being the first day of the week (so this is like WEEK() in mode 1, which your query uses).
The above where predicate would take advantage of an index on mydate - which seems to be your purpose here.

MySQL-Select start and end of week along with average of a column (week-by-week)

I am trying to get average of a column player_count week-by-week over the past 6 weeks. But the problem is that I also want the start and the end of the week date which corresponds to a specific average.
What I have tried:
SELECT AVG(player_count) as average,
updated_at,
updated_at + INTERVAL WEEKDAY(updated_at) + 7 DAY as EndDate
FROM `gtan_servers`
WHERE server_short_name = 'FiveRP'
GROUP BY WEEK(updated_at)
ORDER BY updated_at DESC
LIMIT 6
The updated_at column is intended to be taken as start of the week and EndDate is going to be taken as end of the week in which a specific average of the player count is provided.
But this query is not working correctly regarding the week dates. I can fetch the average yes but the week dates are not being fetched correctly. Any help would be highly appreciated.
You need an expression that truncates an arbitrary date to the first day of the week in which it occurs. That is, it returns 2017-05-21 (Sunday) if you give it 2017-05-24
This expression does that, assuming your weeks start on Sundays. Here's an explanation.
FROM_DAYS(TO_DAYS(datestamp) -MOD(TO_DAYS(datestamp) -1, 7))
Then you need to use that as a GROUP BY expression and a WHERE expression.
SELECT AVG(player_count) as average,
FROM_DAYS(TO_DAYS(updated_at) -MOD(TO_DAYS(updated_at) -1, 7)) week_beginning,
FROM_DAYS(TO_DAYS(updated_at) -MOD(TO_DAYS(updated_at) -1, 7)) + INTERVAL 6 DAY week_ending
FROM `gtan_servers`
WHERE server_short_name = 'FiveRP'
AND updated_at >= FROM_DAYS(TO_DAYS(NOW()) -MOD(TO_DAYS(NOW()) -1, 7)) - INTERVAL 6 WEEK
GROUP BY FROM_DAYS(TO_DAYS(updated_at) -MOD(TO_DAYS(updated_at) -1, 7))
ORDER BY 2 DESC
LIMIT 6
The WHERE automatically filters out records from your table that are too old for your report.
This query gets a little repetitive, but it works nicely.
You could create a stored function like this:
DELIMITER $$
DROP FUNCTION IF EXISTS TRUNC_SUNDAY$$
CREATE
FUNCTION TRUNC_SUNDAY(datestamp DATETIME)
RETURNS DATE DETERMINISTIC NO SQL
COMMENT 'returns preceding Sunday'
RETURN FROM_DAYS(TO_DAYS(datestamp) -MOD(TO_DAYS(datestamp) -1, 7))$$
DELIMITER ;
Then your query becomes more readable:
SELECT AVG(player_count) as average,
TRUNC_SUNDAY(updated_at) week_beginning,
TRUNC_SUNDAY(updated_at) + INTERVAL 6 DAY week_ending
FROM `gtan_servers`
WHERE server_short_name = 'FiveRP'
AND updated_at >= TRUNC_SUNDAY(NOW()) - INTERVAL 6 WEEK
GROUP BY TRUNC_SUNDAY(updated_at)
ORDER BY TRUNC_SUNDAY(updated_at) DESC
LIMIT 6
If your weeks start on Mondays change the -1 to a -2.

MySQL DAYOFWEEK() in reverse?

I'm looking for a way in MySQL to convert an integer (0-6) into a day of the week, something like:
EXAMPLE_FUNCTION(3) = Wednesday.
The DAYOFWEEK(date) function takes a date and gives you a number 0-6 which corresponds to the day of the week (0 = Sunday, 6 = Saturday), so I'm kind of looking for the reverse of this.
DROP FUNCTION IF EXISTS DAYNUMBER;
CREATE FUNCTION DAYNUMBER(s INT) RETURNS VARCHAR(10)
RETURN elt(s+1, 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
Test:
SELECT DAYNUMBER(1)
outputs 'Monday'.
The DAYOFWEEK function should be helpful here: https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_dayname
The only downside is that it expects a date as input, and not a day number. But that should be easily remedied. Just start with an arbitrary date of which you know it falls on a Sunday (like 2016-01-03). Then ADDDATE your day number to it. Now you have a date that falls on the same day as your day number, so you can just run that trough the DAYOFWEEK function.
DAYNAME(ADDDATE("2016-01-03", :day))
See for yourself by running the following samples:
SELECT DAYNAME(ADDDATE("2016-01-03", "3")) # Wednesday
SELECT DAYNAME(ADDDATE("2016-01-03", "0")) # Sunday

How to filter the current week as a range of dates

Hi I have a MySQL database which on I am setting up a table for a Study Calendar, fields are as follows:
SELECT
studycalendarpk,
studytopic,
`module`,
startdate,
enddate,
syllabusoutline
FROM studycalendar
What I am trying to do is to create a query so that for a dashboard php page it has a query that dispays the current weeks study programme. Can someone please tell me how to setup query to filter it so that it is selected if the current date is between the startdate and enddate, thank you
You have a startdate and an enddate for each row in your table, and if I understand your requirement correctly, you want to display all rows that meet these criteria.
WHERE enddate >= start of week
AND startdate < start of next week
You already have startdate and enddate in your table. This answer assumes that each row's enddate is constrained to be greater than or equal to the starttdate. If it isn't you'll get strange results.
You need a MySQL expression to compute the first day of the present week. Here's how you do that.
FROM_DAYS(TO_DAYS(CURDATE()) -MOD(TO_DAYS(CURDATE()) -1, 7))
This expression yields the Sunday immediately preceding CURDATE(). If your weeks are considered to start on Monday, use this instead (notice the -2).
FROM_DAYS(TO_DAYS(CURDATE()) -MOD(TO_DAYS(CURDATE()) -2, 7))
These are very useful expressions because they yield actual dates. Those dates can then be manipulated by date arithmetic such as somedate + INTERVAL 7 DAY which conveniently gives you the date a week later. This sort of arithmetic even works for the last week, and the first week, of a calendar year.
Putting it all together, here's what you do to select the records you want.
WHERE enddate >= FROM_DAYS(TO_DAYS(CURDATE())-MOD(TO_DAYS(CURDATE())-1,7))
AND startdate < FROM_DAYS(TO_DAYS(CURDATE())-MOD(TO_DAYS(CURDATE())-1,7))
+ INTERVAL 7 DAY
This will get the records from your table relevant to the current week.
SELECT *
FROM studycalendar
where curdate() between startdate and enddate
Can you try it? We can gett week no of use by this week() method
SELECT
`studycalendarpk`,
`studytopic`,
`module`,
`startdate`,
`enddate`,
CAST(week(now()) AS UNSIGNED)
syllabusoutline
FROM studycalendar WHERE CAST(week(now()) AS UNSIGNED) between CAST(week('2014-09-01') AS UNSIGNED) and CAST(week('2014-09-07') AS UNSIGNED)

Show next date based on criteria

In perl I have the following database query:
my $list = $db->SelectARef("SELECT p.*, u.usr_login, u.usr_money, u.usr_email, u.usr_pay_email, u.usr_pay_type
FROM Payments p, Users u
WHERE status='PENDING'
AND p.usr_id=u.usr_id
ORDER BY u.usr_pay_type");
Within the array result there is a field named "created".
What I want to do is add another element to the array for each row as "next payment".
Payments are processed after 30 full days from the datetime value but only on the 6th day of every month. Basically I want each result to have a "next payment" element stating which day and month they should get paid on.
e.g created = 2013-07-29 18:55:37
30 days from this is the 28th August 2013
Therefore the next payment date would be the 6th September
I have no idea where to start with this, any help anyone can provide would be greatly appreciated!
Thanks
The following shows the logic:
select (date(t) - interval (day(t) - 1) day) + interval 1 month + interval 5 day
from (select cast(now() as datetime) as t) t;
You can put this into your query as:
SELECT p.*, u.usr_login, u.usr_money, u.usr_email, u.usr_pay_email, u.usr_pay_typel,
created - interval (day(created) - 1) day) + interval 1 month + interval 5 day as nextpay
FROM Payments p join
Users u
on p.usr_id=u.usr_id
WHERE status='PENDING'
ORDER BY u.usr_pay_type;
The expression can be simplified to:
created - interval (day(created) + 4) day) + interval 1 month as nextpay
If I understand correctly, you want to compute a next_payment date which is the nearest 6th day of a month that is at least 30 days from the created date. Another way of saying that is that your due date is always the 6th of the month with at least a 30 day grace period from the close date.
Unfortunately, we can't do a simple rounding or stepping here, because the Gregorian calendar isn't quite a regular series. (It quite isn't a regular series?) So, we'll put conditional logic into a query. As this looks just awful, we'll hide it in a function:
DELIMITER //
CREATE FUNCTION next_payment(close_date DATE)
RETURNS DATE
DETERMINISTIC
READS SQL DATA
LANGUAGE SQL
BEGIN
DECLARE min_grace INT DEFAULT 30; -- minimum grace period of 30 days
DECLARE bill_dom INT DEFAULT 6; -- billing day of month is the 6th
DECLARE d DATE;
SET d = close_date + INTERVAL min_grace DAY;
IF DAY(d) > bill_dom THEN -- Did 30 days\' grace put us beyond the 6th?
SET d = d + INTERVAL 1 MONTH; -- If so, advance to next month.
END IF;
RETURN d + INTERVAL(bill_dom - DAY(d)) DAY; -- Now "round" to the 6th of the month
END
//
DELIMITER ;
How you use the logic is up to you. Adding SELECT next_payment(p.created) AS "next_payment", ... will give you the additional column you want. You could parameterize the above (e.g., CREATE FUNCTION next_payment(close_date DATE, min_grace INT, bill_dom INT)) for greater flexibility. You might rip the SET/IF logic out of the function and jam it into one unwieldy CASE/END statement in your SELECT. You could create a VIEW that automatically "appends" a next_payment column to the table, or ALTER TABLE and populate a new column, etc.