How to get 'Monday Date' in MySQL? - mysql

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.

Related

Select current week, starts from Monday instead of Sunday

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

How to deal with non standard date formats in SQL (mySQL)?

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

Find data of a whole month in sql

I have this query where I provide to-date & from date.
SELECT *
FROM sales
WHERE date between to-date AND from-date;
Now I want to execute this query with following parameters
to-date = Oct-2015
some-other-date = Oct-2015
That is I want records of the whole month.
How would I do that in a query where I have to and from dates provided it will work for both scenarios where months can be same and different as well.
Update:
dataType for column date is date
You can find the first day of the month containing any given timestamp with an expression like this. For example by using the timestamp NOW(), this finds the first day of the present month.
(DATE(NOW() - INTERVAL DAYOFMONTH(DATE(NOW()))
That's handy, because then you can use an expression like
(DATE(NOW() - INTERVAL DAYOFMONTH(DATE(NOW())) - INTERVAL 1 MONTH
to find the beginning of the previous month if you like. All sorts of date arithmetic become available.
Therefore, you can use an expression like the following to find all records with item_date in the month before the present month.
WHERE item_date>=(DATE(NOW()-INTERVAL DAYOFMONTH(DATE(NOW()))- INTERVAL 1 MONTH
AND item_date < (DATE(NOW()-INTERVAL DAYOFMONTH(DATE(NOW()))
Notice that we cast the end of a range of time as an inequality (<) to the moment just after then end of the range of time.
You may find this writeup useful. http://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/
It's often useful to create a stored function called TRUNC_MONTH() to perform the conversion of the arbitrary timestamp to the first day of the month. It makes your SQL statements easier to read.
select * from sales
where from-date >= 1-Oct-2015
and to-date <= 1-Nov-2015
Update
select * from sales
where date >= from-date
and date <= to-date
Here is SQLFIDDLE
You Can get month from your both to and from dates and find records of that month
SELECT * FROM sales
WHERE MONTH('2002-01-03') AND MONTH('2002-01-3')
SqlFiddle of Using Month Function

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)

MySQL select dependant on time of day

I want to select from a MySQL table and filter depending on the time of day:
if now > 10am select uploaded date where created date is today
if now < 10am select uploaded date where created date is yesterday
I think you must use Cron jobs for this.
Then, your sql will look like that:
WHERE tbl.TimeCreated = DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)
assuming this format of the field: DateTime(YYYY-MM-DD HH:MM:SS)
This should do what you need.
SELECT
`uploaded_date`
FROM
`table`
WHERE
`created_date` = CASE WHEN CURTIME() > 100000
THEN CURDATE()
ELSE CURDATE() - INTERVAL 1 DAY
END
You can see a similar example in this fiddle which should return a single row of "AM" in the morning, "Noon" at noon, and "PM" in the afternoon (and 2 empty result sets).