Selecting 'DATE' fields in mysql by month and day with comparison - mysql

Trying to select a closest previous and next holiday from the database. Say, New Year's Day is always at the 1st of January, and New Year's Eve is at the 31st of December. Current year is completely irrelevant, so I'm trying to select previous holiday by day and month (New Year's Eve) with the following MySQL query:
SELECT * FROM `calendar` WHERE DATE_FORMAT(`holidayDate`, "%m-%d") < "01-01"
It gives NULL. I was expecting that it would drop through and will look in the previous month, December, but...
Tried a lot of different ways of doing it, but still no success.
P.S.: Cannot use TIMESTAMP in this case...

The reason it's returning null is because there isn't anything less than '01-01'. The query doesn't wrap around to the beginning.
What I would do is write a case statement that checks to see if you are at the earliest holiday.
If you are the earliest holiday, then you can select the latest holiday (a way of wrapping around).
If you are not the earliest holiday, then you need to select the one before it. I did this by ordering them in descending date, and limiting it to 1. (Effectively grabbing the holiday occurring before the current date.)
Try this:
SELECT *
FROM calendar
WHERE
CASE WHEN DATE_FORMAT(CURDATE(), '%m-%d') = DATE_FORMAT((SELECT MIN(c.holidayDate) FROM calendar c), '%m-%d')
THEN holidayDate = (SELECT MAX(c.holidayDate) FROM calendar c)
ELSE
DATE_FORMAT(holidayDate, '%m-%d') < DATE_FORMAT(CURDATE(), '%m-%d')
END
ORDER BY holidayDate DESC
LIMIT 1;
Here is an SQL Fiddle example. I created two queries. One that uses the current date (seen above) and one that has Jan 1st hard coded to show that the case statement does work. I've only added certain holidays to test.

If two queries are acceptable for you:
SELECT max(holidayDate) as prev_holiday from calendar where holidayDate < now();
SELECT min(holidayDate) as next_holiday from calendar where holidayDate > now();

Related

Using BETWEEN Condition Without Including Two Dates

Is there a simple way of using BETWEEN but not including the two dates you want to check between? I noticed if you use BETWEEN it includes the start and end date itself. I've been working on a booking system and want to stop guests booking dates in between another booking or overlapping another booking.
E.g. if there's a booking for 20th May until the 25th May I don't want anyone to be able to book those dates regardless of the start and end date of the new booking. I do, however, want users to be able to have their end date on the same day as a different booking's start date or the start date on the same day as a different booking's end date.
Originally I had:
SELECT id
FROM table
WHERE (? BETWEEN arrive_date AND depart_date)
OR (? BETWEEN arrive_date AND depart_date)
The first ? is for the new arrive date and the second ? is for the new end date.
But when checking it included the start and end date then I tried to work out the correct formula and got this:
SELECT id FROM table
WHERE (? BETWEEN arrive_date - INTERVAL 1 DAY AND depart_date - INTERVAL 1 DAY)
OR (? BETWEEN arrive_date + INTERVAL 1 DAY AND depart_date - INTERVAL 1 DAY)
It seemed to be fine but then I noticed if I book, for example, 9th November and 10th November I can then also book 6th 15th November.
I thought what I had was correct and I am still working it all out but if someone can see where I am going wrong that would be helpful!
If there is a row in the table with arrive_date less than the queried departure date and depart_date greater than the queried arrival date then you will get as result 'booked', else you will get 'free':
SELECT CASE
WHEN EXISTS (
SELECT 1
FROM `table`
WHERE :depart_date > arrive_date AND :arrive_date < depart_date
) THEN 'booked'
ELSE 'free'
END result
Replace :arrive_date and :depart_date with the dates that you will pass as parameters.
See the demo.

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

Show week beginning date with week()

I am using the week function like so:
SELECT
sub.id AS ARID,
WEEK(my.data) AS Week,
Is it possible to add the week beginning date that the week corresponds to?
Something like:
SELECT
sub.id AS ARID,
WEEK(my.data) AS Week,
MIN(my.data) AS WKBeginning
Using MIN in this way I remove a lot of data unintentionally - it should be divorced fromt he data even. Put another way, I'd like to display Week as a date rather than a number that is along the lines 'Monday-2014-09-04'
Is that possible?
My first answer turned out to be incorrect if the source table didn't include the full range of dates for the week (specifically the first day of the week).
The correct way is to use ADDDATE():
ADDDATE(my.data, INTERVAL 1-DAYOFWEEK(my.data) DAY) AS CorrectWKBeginning,
A correlated sub-query should does not work when the first day of the week is not included in the data:
SELECT
id,
WEEK(d) AS Week,
ADDDATE(d, INTERVAL 1-DAYOFWEEK(d) DAY) AS CorrectWKBeginning,
(SELECT MIN(d) FROM t WHERE WEEK(d) = WEEK(t2.d)) as IncorrectWKBeginning
FROM t t2
Sample SQL Fiddle
You might have to use week() with parameters to set the start day of the week and if it counts from 0-53 or 1-53, see the MySQL manual for reference.

Grabbing date records that are exactly a month or more away

I put together a query for determining whether the time difference between the current date and a record from a database is exactly a month or more apart. I am comparing now() to a created_at column, which is a timestamp.
EX:
6-12-2014,
7-12-2014
AND
5-12-2014,
7-12-2014
Should be considered to be a desirable results.
SELECT count(*) FROM `subscriptions` WHERE
DATE_ADD(CAST(created_at as DATE),INTERVAL TIMESTAMPDIFF(MONTH, created_at, now()) MONTH) = CAST(now() as DATE);
However the query appears to not return all desired results. It returns 2-28-2014 and 7-28-2014, however it does not pull up 6-28-2014. Is there a better way of doing this than the solution I came up with?
Are you looking to count dates that are on the same day of the month as the current date? If so, try the DAYOFMONTH function:
SELECT COUNT(*)
FROM subscriptions
WHERE DAYOFMONTH(created_at) = DAYOFMONTH(NOW())

finding events from previous Sunday to next Sunday

How can you find MySQL data for the current week plus the following Sunday?
Given a date (e.g. Wednesday 5/18/11), it would show events from the previous Sunday to the next Sunday. 5/15/11 through 5/22/11.
The trick would be to find the 'previous' Sunday to a given date.
How can this be done?
SELECT *
FROM events
WHERE Yearweek(`eventdate`) = Yearweek(NOW())
OR ( Weekday(NOW()) = 6
AND Yearweek(`eventdate`) = Yearweek(
DATE_SUB(NOW(), INTERVAL 1 DAY)) )
Taking from Pentium's answer, with some adjustments...
SELECT
*
FROM
Events
WHERE
YEARWEEK(`eventdate`) = YEARWEEK(NOW()) OR
(
WEEKDAY(`eventdate`) = 6 AND
YEARWEEK(`eventdate`) = YEARWEEK(NOW()) + 1
)
This may need to be adjusted depending on the values for WEEKDAY (is 6 Sunday?).
Also, while this should work, my guess is that mySQL won't be able to use any indexes on the eventdate column with this method. It's probably better to find the actual dates themselves for the bordering Sundays and then do a BETWEEN or <= >=. This should allow the use of an index on the eventdate. Even if you don't have an index on it now, you might want to use one in the future.
Using a calendar table . . .
select cal_date
from calendar
where cal_date between
(select max(cal_date) from calendar
where cal_date <= '2011-05-15' and day_of_week = 'Sun') and
(select min(cal_date) from calendar
where cal_date > '2011-05-15' and day_of_week = 'Sun')
It's not clear what you want if the given date is a Sunday. This previous query returns 15 rows given a date that falls on Sunday. It returns 8 rows for all other days. You can tweak the comparison operators in the WHERE clause to get the behavior you want.
I posted code for a calendar table earlier on SO. It's for PostgreSQL, but you should be able to adapt it to MySQL without much trouble.