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
Related
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.)
I am new to SQL and learning at the moment. I am using MySQL installed on Ubuntu 18.04.
I have the following table:
CREATE TABLE IF NOT EXISTS product(name varchar(255) NOT NULL,
availability date NOT NULL);
I want to insert the following record in the table:
INSERT INTO `product` (`name`, `availability`)
VALUES ('Title 1', last Wednesday);
when executing I get the following error:
ERROR 1064 (42000) at line 21: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the
right syntax to use near 'Wednesday)'
I understand that this format ('last Wednesday', 'next week',..) is not a standard date format. I wanted to know if it is possible to create user-defined types in MySQL to be able to process these bespoke date records.
So far what I have found on the web deals with dates that still contain more or less a standard date format, not as bespoke as those mentioned above (use cast, parse,..).
What you have are functions like NOW(), CURRENT_TIMESTAMP() and CURRENT_DATE(). For anything else like LAST_WEDNESDAY() you can write your own stored functions.
create function last_wednesday() returns date no sql
return current_date() - interval (weekday(current_date()) + 4)%7+1 day;
Or use the same expression inline in your queries.
Update
As asked by Strawberry - Here is something "more scalable":
create function human_to_date(str text, date date) returns date no sql
return case
when str = 'last monday' then date - interval (weekday(date) + 6-0)%7+1 day
when str = 'last tuesday' then date - interval (weekday(date) + 6-1)%7+1 day
when str = 'last wednesday' then date - interval (weekday(date) + 6-2)%7+1 day
when str = 'last thursday' then date - interval (weekday(date) + 6-3)%7+1 day
when str = 'last friday' then date - interval (weekday(date) + 6-4)%7+1 day
when str = 'last saturday' then date - interval (weekday(date) + 6-5)%7+1 day
when str = 'last sunday' then date - interval (weekday(date) + 6-6)%7+1 day
end
;
Use it as
select human_to_date('last wednesday', now())
or for any date as reference
select human_to_date('last sunday', '2019-10-01')
This will return the last sunday in this month (sept. 2019)
See demo
I've tried to remove code duplication, but ended with this:
delimiter //
create function human_to_date(str text, date date) returns date no sql
begin
declare day_of_week int default null;
if str rlike '^last (monday|tuesday|wednesday|thursday|friday|saturday|sunday)$' then
set day_of_week = case substring_index(str, ' ', -1)
when 'monday' then 0
when 'tuesday' then 1
when 'wednesday' then 2
when 'thursday' then 3
when 'friday' then 4
when 'saturday' then 5
when 'sunday' then 6
end;
return date - interval (weekday(date) + 6-day_of_week)%7+1 day;
end if;
return null;
end //
delimiter ;
db-fiddle
When it comes to dates, the natural language capabilities of some application languages is so good that I'd be tempted to handle the logic there instead.
For instance, here's some PHP:
<?php
echo(date(DATE_RFC850,strtotime( date('Y-m-01', strtotime('next month')).' last wednesday')));
?>
Today is Thursday 26th September. This echoes Wednesday, 25-Sep-19 00:00:00 BST
When storing in a db, you need information that make sense. a value "last Wednesday" for a product, does not give any reasonable availability info. For example, last Wednesday from which date? If someone asks for all available products on last Wednesday but 2 months later than today, what will a query looking for "last Wednesday" return? Definitely invalid results. So, if you want to store a date, then use a date/datetime datatype. You can add any custom description you want by using an additional column with varchar datatype, but i wouldn't use this as a primary info source.
Here is code to insert last Wednesday's date into your table:
INSERT INTO product(name, availability)
SELECT
'Title 1',
CASE WHEN WEEKDAY(CURDATE()) >= 2
THEN TIMESTAMPADD(DAY, 2 - WEEKDAY(CURDATE()), CURDATE())
ELSE TIMESTAMPADD(DAY, 2 - WEEKDAY(CURDATE()) - 7, CURDATE()) END;
Notes: It would be hard to pull this off using a select with a VALUES clause, unless perhaps we define a UDF, so I am using an INSERT INTO ... SELECT. The CASE expression checks if the current date is a Wednesday (2) through Sunday (6). If so, then we offset the current date by the difference, to shift it back to Wednesday. Similar logic applies for Monday (0) and Tuesday (1).
Why are the YEARWEEKs of the both following dates different?
Both dates (2018-12-29 AND 2018-12-30) are in the same week?
SELECT YEARWEEK('2018-12-29 20:10:00'); = 201851
SELECT CURDATE(); = 2018-12-30
SELECT YEARWEEK(CURDATE()); = 201852
The default mode of operation of YEARWEEK and WEEK is set by the default_week_format system variable, which defaults to 0, in which mode weeks are assumed to start on Sunday. To do your computation based on weeks starting on Monday (so that 2018-12-29 and 2018-12-30 are in the same week), use one of the modes described in the manual which supports that (1, 3, 5 and 7). So for example
SELECT YEARWEEK('2018-12-29 20:10:00', 1), YEARWEEK('2018-12-30', 1)
Output:
201852 201852
Consider
SELECT YEARWEEK('2018-01-06'); returns 201753 -- saturday
SELECT YEARWEEK('2018-01-07'); returns 201801 -- sunday
while 2018-01-06 seems to return 201801.
returns the year and week number (a number from 0 to 53) for a given date, looks for whole(completed) weeks which end with each saturdays. Iterates to the next value at upcoming sundays
I have an Oracle SQL Query, which I am trying to re-write in MySQL.
PS : The dates are just arbitrary here, in the actual scenario I use this custom query inside Tableau where it accepts user defined Dates.The "Reference Start Date" is being compared to "Start Date".
Part of the Oracle SQL query:
CASE WHEN psr.dt_orgn IS NULL THEN NULL
ELSE
CASE WHEN CAST('2017-05-22' AS DATE) >= CAST('2017-06-22' AS DATE) THEN TRUNC(psr.dt_orgn,'IW')
ELSE TRUNC(psr.dt_orgn + ((CAST('2017-06-22' AS DATE)-CAST('2017-05-22' AS DATE))*(INTERVAL '1' DAY)),'IW')
END
END) week
The above uses an existing Calender table in a Database to convert dates into 'Week Start Dates' i.e Monday Date of that Week
MySQL version:
CASE WHEN psr.originated IS NULL THEN NULL
ELSE
CASE WHEN CAST('2017-05-22' AS DATE) >= CAST('2017-06-22' AS DATE) THEN DATE_ADD(psr.originated,
INTERVAL - WEEKDAY(psr.originated) DAY)
ELSE DATE_ADD(psr.originated + ((CAST('2017-06-22'AS DATE) - CAST('2017-05-22' AS DATE)) * (INTERVAL '1' DAY))
END
END) week
I am using a solution I found to get 'Week Start Date' in MySQL as follows:
DATE_ADD(mydate, INTERVAL(1-DAYOFWEEK(mydate)) DAY)
And I am getting error while doing this.
My question is how do I apply the same to the 2nd else condition with the '1 day Interval' in the MySQL query?
Or is there an easier solution to get week start date in MySQL?
I guess you're asking how to take any arbitrary DATE value and return the DATE value of the most recent Monday. In Oracle you can use TRUNC(datestamp, 'W') to do that.
Here's one way to do it in MySQL:
FROM_DAYS(TO_DAYS(datestamp) -MOD(TO_DAYS(datestamp) -2, 7))
If you wanted the Sunday, you would use
FROM_DAYS(TO_DAYS(datestamp) -MOD(TO_DAYS(datestamp) -1, 7))
I wrote it up here. http://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/
You can get the day of a date using the function on MySQL called dayname(), for example dayname("2006-04-24") will return you Monday. In this case you only need to put the row that contains your date into the function. After that you can easily compare two dates.
I'd like to have the week number and year, for a given date, from MySQL with the following rules:
If the date is at the end of the year, but in the first week of the next year, I need to return 1 as the week number.
If the date is at the beginning of the year, but in the last week of the previous year, I need to return 52 (or 53) as the week number.
I've read the week function in MySQL but I can't get the result I want.
Date and Time Functions: WEEK(date[,mode])
I am on the french calendar, so I have to begin the week on Monday and week 1 is the first week with more than 3 days this year.
Therefore I can only use options 1 and 3.
When I write the following queries:
select week ('2012-12-31', 3), the result is 1
select week ('2012-12-31', 1), the result is 53
When I test on the 1st Jan 2016:
select week ('2016-1-1', 3), the result is 53
select week ('2016-1-1', 1), the result is 0
Option 1 can't be used, because I can't detect that 2012-12-31 is in the next year.
Option 3 can be used, but I have the add two pieces of logic: if weeknumber = 1 and month = 12, year + 1 and if weekumber = 53 and month = 1 then year - 1
Does someone have a better solution?
Regards
Ok, I think I get what you're trying to do now.
As the documentation says:
We decided to return 0 instead because we want the function to return
“the week number in the given year.”
If you want the week number for the year that the week is in, they suggest using the YEARWEEK() function, which takes the same mode arguments as WEEK():
If you would prefer the result to be evaluated with respect to the
year that contains the first day of the week for the given date...
use the YEARWEEK() function:
mysql> SELECT YEARWEEK('2000-01-01');
-> 199952
mysql> SELECT MID(YEARWEEK('2000-01-01'),5,2);
-> '52'
So some examples of what you'd use:
mysql> SELECT MID(YEARWEEK('2012-1-1',3),5,2)
-> '52'
mysql> SELECT MID(YEARWEEK('2012-12-31',3),5,2)
-> '01'