Limiting MySQL results to prior days of the week - mysql

I have a table like so:
id | gallons_used | date
----------------------
1 2 157263300
2 5 157262000
...
I want to get a result set containing only records that took place on X day of the week (Monday or Tuesday or Wednesday, etc etc)

Use DAYNAME() in your WHERE clause
WHERE DAYNAME(FROM_UNIXTIME(`date`)) = 'Monday' <-- by day of the week
AND `date` < INTERVAL CURRENT_DATE - 7 DAY <-- within the last week
You can use DAYOFWEEK() as well but this is more readable.

Something that would check for Wednesday as an example given that your date column is a timestamp:
DAYOFWEEK(date) = 4
Reference to documentation: http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#function_dayofweek
SQLFiddle: http://www.sqlfiddle.com/#!2/12762/3
I had a FROM_UNIXTIME() call around date as well but I don't think it is required(not 100% sure). http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_from-unixtime

Since you're using a Unix timestamp, you can use the following:
SELECT id, UNIX_TIMESTAMP(`date`)
FROM ...
WHERE DAYNAME(FROM_UNIXTIME(`date`)) = 'Monday'
AND `date` > UNIX_TIMESTAMP() - 604800
See the demo

Related

Dynamic due date finder in a single query

id start_date interval period
1 2018-01-22 2 month
2 2018-02-25 3 week
3 2017-11-24 3 day
4 2017-07-22 1 year
5 2018-02-25 2 week
the above is my table data sample. start_dates will be expired based on interval and period(i.e id-1 will have due date after 2 months from the start_date, id-2 will have due after 3 weeks vice versa). period is enum of (day,week,month,year). requirement is, Client can give any period of dates. let's say 25-06-2026 to 13-07-2026 like that.. I have to return the ids whose due dates falls under that period.I hope i made my question clear.
I am using mysql 5.7. I found a way to achieve this with recursive CTE's.(not available in mysql 5.7). and there is a way to achieve this by populating virtual records by using inline sub queries along with unions but its a performance killer and we can't do populate virtual records every time a client request comes.(like given in the link Generating a series of dates) I have reached a point to get results for a single date which is very easy. Below is my query.
SELECT b.*
FROM (SELECT a.*,
CASE
WHEN period = 'week' THEN MOD(Datediff('2018-07-22', start_date), 7 * intervals)
WHEN period = 'month'
AND Day('2018-07-22') = Day(start_date)
AND MOD(Period_diff(201807, Extract(YEAR_MONTH FROM start_date)), intervals) = 0 THEN 0
WHEN period = 'year'
AND Day('2018-07-22') = Day(start_date)
AND MOD(Period_diff(201807, Extract(
YEAR_MONTH FROM start_date)) / 12,
intervals) = 0 THEN 0
WHEN period = 'day' THEN MOD(Datediff('2018-07-22', start_date) , intervals)
end filters
FROM kml_subs a)b
WHERE b.filters = 0;
But I need to do this for a period of dates not a single date. Any suggestions or solutions will be much appreciated.
My desired result shoud be like..
if i give two dates.say 2030-05-21 & 2030-05-27. due dates falls under those 6 dates between(2030-05-21 & 2030-05-27) will be shown in the result.
id
1
4
My question is different from Using DATE_ADD with a Column Name as the Interval Value . I am expecting a dynamic way to check due dates based on start_date
Thanks, Kannan
In MySQL, it would seem that a query along these lines would suffice. (Almost) everything else could and should be handled in application level code...
SELECT *
, CASE my_period WHEN 'day' THEN start_date + INTERVAL my_interval DAY
WHEN 'week' THEN start_date + INTERVAL my_interval WEEK
WHEN 'month' THEN start_date + INTERVAL my_interval MONTH
WHEN 'year' THEN start_date + INTERVAL my_interval YEAR
END due_date
FROM my_table;

SQL - Last Day of Month

I got a Table which looks like this:
DATE | Number
01-01-16 00:00:00 10
02-01-16 00:00:00 10
03-01-16 00:00:00 11
04-01-16 00:00:00 12
05-01-16 00:00:00 13
....
31-01-16 00:00.00 15
........
29-02-16 00:00:00 18
I got this table for the last few months.
I now want to retrieve the value of the rows, which contain the last day of the previous month and the month before the last month. So for today I would like to retrieve the Value of the 31-1-16 and 29-2-16.
My result should look like:
lastmonth | lastmonth2
18-> Corresponding value to Date: 29-02-16 | 15 -> value for 31-01-16
Would appreciate any help.
Cheers
Here is logic for the last day of this month and the previous month:
select last_day(curdate()) as last_day_of_this_month,
last_day(date_sub(curdate(), interval 1 month)) as last_day_of_prev_month
You can get the last day of any month relative to the current month by changing the "1".
And, I have no idea what date "30-2-16". When describing dates, you should use ISO standard formats. The last day of February 2016 was 2016-02-29.
This is Gordon's code for determining the correct dates plus subqueries to fetch the Number values for those rows:
SELECT
(SELECT Number FROM cc_open_csi_view
WHERE last_day(date_sub(curdate(), interval 1 month)) = date(`DATE`)) as lastmonth,
(SELECT Number FROM cc_open_csi_view
WHERE last_day(date_sub(curdate(), interval 2 month)) = date(`DATE`)) as lastmonth2
FROM DUAL;
Hope that's what you wanted! Works for me in a simple example. I don't know if you need the date() part around DATE but it seemed safest.
SELECT CASE
WHEN last_day(curdate()) = `DATE` THEN number
END as number_last_month,
CASE
WHEN last_day(date_sub(curdate(), interval 1 month)) = `DATE`
THEN number
END as number_last_month2
FROM cc_open_csi_view
I can't test it right now on sqlfiddle.

MySQL: need to calculate the last Friday of a month

I'm trying to solve a task: I have a table containing information about ships' battles. Battle is made of name and date. The problem is to get the last friday of the month when the battle occurred.
WITH num(n) AS(
SELECT 0
UNION ALL
SELECT n+1 FROM num
WHERE n < 31),
dat AS (
SELECT DATEADD(dd, n, CAST(battles.date AS DATE)) AS day,
dateadd(dd, 0, cast(battles.date as date)) as fight,
name FROM num,battles)
SELECT name, fight, max(day) FROM dat WHERE DATENAME(dw, day) = 'friday'
I thought there must be a maximum of date or something, but my code is wrong.
The result should look like this:
Please, help!!
P.S. DATE_FORMAT is not available
Possible problem: as spencer7593 noticed - and as I should have done and didn't - your original query is not MySQL at all. If you're porting a query that's OK. Otherwise this answer will not be helpful, as it makes use of MySQL functions.
The day you want is number 4 (0 being Sunday in MySQL).
So you want the last day of the month if the last day of the month is a 4; if the day of the month is a 5 you want a date which is 1 day earlier; if the day of the month is a 3 you want a date which is 1 day later, but that's impossible (the month ends), so you really need a date six days earlier.
This means that if the daynumber difference is negative, you want it modulo seven.
You can then build this expression (#DATE is your date; I use a fake date for testing)
SET #DATE='2015-02-18';
DATE_SUB(LAST_DAY(#DATE), INTERVAL ((WEEKDAY(LAST_DAY(#DATE))+7-4))%7 DAY);
It takes the last day of the month (LASTDAY(#DATE)), then it computes its weekday, getting a number from 0 to 6. Adds seven to ensure positivity after subtracting; then subtract the desired daynumber, in this case 4 for Friday.
The result, modulo seven, is the difference (always positive) from the last day's daynumber to the wanted daynumber. Since DATE_SUB(date, 0) returns the argument date, we needn't use IF.
SET #DATE='1962-10-20';
SELECT DATE_SUB(LAST_DAY(#DATE), INTERVAL ((WEEKDAY(LAST_DAY(#DATE))+7-4))%7 DAY) AS friday;
+------------+
| friday |
+------------+
| 1962-10-26 |
+------------+
Your query then would become something like:
SELECT `name`, `date`,
DATE_SUB(LAST_DAY(`date`),
INTERVAL ((WEEKDAY(LAST_DAY(`date`))+7-4))%7 DAY) AS friday
FROM battles;

Subtract one week from current week of the year

I am trying to get one week earlier then current week of the year but my sql query is returning null. here is my query
select date_sub(yearweek('2014-01-01'),INTERVAL 1 week)
what is wrong with this query
If you want to get YEARWEEK of week prior to date, you can do this:
Note: YEARWEEK results in 6-digit number, first 4 digits are week year, trailing 2 digits are week number.
SELECT YEARWEEK('2014-01-01' - INTERVAL 1 WEEK)
If you need to get a date that is one week before a given date, then:
SELECT '2014-01-01' - INTERVAL 1 WEEK
Try this
select date_sub(date('2014-01-01'),INTERVAL 1 week)
Try this:-
DATE_SUB(date('2014-01-01'), INTERVAL 7 DAY)
or
SELECT '2014-01-01' - INTERVAL 1 WEEK
The problem is that DATE_SUB takes a date as the first arguement, but year week returns yyyyww i.e. not a date. So this:
SELECT yearweek('2014-01-01');
Returns 201352, this is then implicitly casted to a date, since it is not a date the result is null. You can replicate this by doing:
SELECT DATE(yearweek('2014-01-01'));
So if you subtract a week from NULL the result is also NULL.
The fix is to subtract the week first, then get the year week:
SELECT yearweek(date_sub('2014-01-01', INTERVAL 1 WEEK));
And the result is 201351.
Are you looking for week number??? If yes then plz try this if it will work for you
Select DatePart(Week, Date add(day,-7,convert(date time,'01-jan-2014')))
Pleas let me know if you are looking for something else.
SELECT * FROM [table] WHERE WEEKOFYEAR(date) = WEEKOFYEAR(NOW()) - 1;

How to check if date is in range regardless of the year

I'm wondering what would be the easiest way in MySQL to check if given date is in range regardless of the year.
In database table I have two DATE fields: start and finish stored in YYYY-mm-dd
if start = 2013-11-01 and finish = 2014-03-01 anything between 1st of November and 1st of March of any year should be accepted.
Valid dates:
2020-01-01 1980-02-28
Invalid dates:
2013-10-30 1968-07-30
There are almost certainly cleaner ways of doing it, however this should work:
((DAYOFYEAR(finish_date) > DAYOFYEAR(start_date)
AND (DAYOFYEAR(#date) >= DAYOFYEAR(start_date)
AND DAYOFYEAR(#date) <= DAYOFYEAR(finish_date)))
OR (DAYOFYEAR(finish_date) <= DAYOFYEAR(start_date)
AND (DAYOFYEAR(#date) >= DAYOFYEAR(start_date)
OR DAYOFYEAR(#date) <= DAYOFYEAR(finish_date))))
For a start date in Oct 2012 and end date in Nov 2020 this will return all dates in the Oct-Nov range. If in fact would want it to return all Dates when the range is greater than a year (and hence covers all dates of the year) you could add:
OR DATEDIFF(Day, start_date, finish_date) > 356
before the final bracket.
use DAYOFYEAR:
When the Start Date is earlier in the year than the Finished Date:
the tested Date should lye between Start Date and Finish Date (or on Start or Finish)
When the Finished Date is earlier in the year than the Start Date:
the tested Date should lye outside the Start Date and Finish Date (or on Start or Finish)
You can use some date extract function and then check your condition..
for example.
SELECT EXTRACT(MONTH FROM TIMESTAMP '2013-11-01 20:38:40');
this will give ouput start month as 11
SELECT EXTRACT(MONTH FROM TIMESTAMP '2014-03-01 20:38:40');
this will give ouput end month as 3
now you can check the condition from above two result..
SELECT * FROM tableWithDates t WHERE month(t.start) >= 11 AND month(t.finish) < 3
if you want the first of march it will go like this:
SELECT * FROM tableWithDates t WHERE month(t.start) >= 11 AND (month(t.finish) < 3 OR month(finish) <= 3 AND day(finish)<=1)
Depending on the size of the data you will run this at. You can get into performance problems, as MySQL can't use indexes of calculated columns.
If you run into this i suggest spitting the month AND/OR day into separate columns.
Edit:
Given an one parameter input as '2008-02-29'
SELECT * FROM tableWithDates t
WHERE
month(t.start) >= month('2008-02-29') AND day(t.start) >= day('2008-02-29')
AND month(t.finish) <= month('2008-02-29') AND day(t.finish) <= day('2008-02-29')