Is it possible to query for all dates in the future that are an increment of x days?
i.e.
SELECT *
FROM bookings
WHERE date >= CURDATE()
AND
(
date = CURDATE() + INTERVAL 6 DAY
OR date = CURDATE() + INTERVAL 12 DAY
OR date = CURDATE() + INTERVAL 18 DAY
etc.
)
Something like:
SELECT
*
FROM table
WHERE
date >= CURDATE()
AND
DATEDIFF(CURDATE(), date) % 6 = 0
Datediff returns the number of days difference, and % 6 says return the remainder when divided by six.
Yes.
Your logic is flawed, though. You probably meant
SELECT *
FROM table
WHERE
date = CURDATE() + INTERVAL 6 DAY
OR date = CURDATE() + INTERVAL 12 DAY
OR date = CURDATE() + INTERVAL 18 DAY
And don't use table names like "table" and field names like "date" (i.e. reserved words).
Related
I am selecting all records between NOW() and specific X day interval and came across this odd behavior that I don't understand.
I am checking 24 hours into the future and 24 hours into the past:
select * from table where date between NOW() and NOW() + 1 interval day; //works
select * from table where date between NOW() and NOW() - 1 interval day; //no records
But if I reverse the between call:
select * from table where date between NOW() + 1 interval day AND NOW(); //no records
select * from table where date between NOW() - 1 interval day AND NOW(); //works
Why does one call into the future work, but the same call into the past not work?...and if I reverse between parameters, the opposite behavior happens - does not work 24 hours into the future but does work 24 hours into the past.
======================
Adding #TimBiegeleisen explanation below here written out:
date = '2018-05-30' ;
select * from table where date between NOW() and NOW() + 1 interval day;
= date >= '2018-05-30' AND 'date <= 2018-05-31'; //true
select * from table where date between NOW() and NOW() - 1 interval day; records
= date >= '2018-05-30' AND 'date <= 2018-05-29'; //false
AND
select * from table where date between NOW() + 1 interval day AND NOW();
= date >= '2018-05-31' AND date <= '2018-05-30' //false
select * from table where date between NOW() - 1 interval day AND NOW();
= date >= '2018-05-29' and date <= '2018-05-30'; //true
The BETWEEN operator is interpreted a certain way:
WHERE date BETWEEN a AND b
means this:
WHERE date >= a AND date <= b
So the following two queries are equivalent:
select * from table where date between NOW() and NOW() - interval 1 day;
select * from table where date >= NOW() and date <= NOW() - interval 1 day;
Hopefully you can see that in your second query the WHERE condition can never be true, because a date cannot simutaneously be greater than or equal to now and less than now minus one at the same time.
simply put,
For SQL:
WHERE x between a and b
meaning
x >= a
and
x <= b
therefore, we have a <= x <= b or a <= b
PS: it's just about math :)
CREATE TABLE `sport_data` (
`id` int(255) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`sport` varchar(255) NOT NULL,
`musclePlan` varchar(255) NOT NULL,
`sport_time` varchar(255) NOT NULL,
`kcal` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
How can i get all data from this table from the last week (from Monday to Sunday)?
I have tried:
WHERE date >= curdate() - INTERVAL DAYOFWEEK(curdate())+5 DAY AND date < curdate() - INTERVAL DAYOFWEEK(curdate())-2 DAY
I don't know if this is correct that way?
Thanks in advance.
The >= and < pattern is what we usually use. That part looks right.
I think the question is about the expressions that returning the range start and end values.
I suggest that we test those expressions for a variety of date values, not just CURDATE(). We can use a value in place of CURDATE(), and check the results, and do that for a series of date values.
Conveniently, those expressions will evaluate the same in a SELECT list as they do in a WHERE clause. So we can run a SELECT statement, and check the results.
For example:
SELECT t.dt AS dt
, t.dt - INTERVAL DAYOFWEEK(t.dt)+5 DAY AS _ge
, t.dt - INTERVAL DAYOFWEEK(t.dt)-2 DAY AS _lt
FROM (
SELECT CURDATE() + INTERVAL 0 DAY AS dt
UNION ALL SELECT CURDATE() + INTERVAL -1 DAY
UNION ALL SELECT CURDATE() + INTERVAL -2 DAY
UNION ALL SELECT CURDATE() + INTERVAL -3 DAY
UNION ALL SELECT CURDATE() + INTERVAL -4 DAY
UNION ALL SELECT CURDATE() + INTERVAL -5 DAY
UNION ALL SELECT CURDATE() + INTERVAL -6 DAY
UNION ALL SELECT CURDATE() + INTERVAL -7 DAY
UNION ALL SELECT CURDATE() + INTERVAL -8 DAY
UNION ALL SELECT CURDATE() + INTERVAL -9 DAY
UNION ALL SELECT CURDATE() + INTERVAL -10 DAY
) t
If the expressions are returning the values we expect, in accordance with the specification, for each possible date value, then the expressions are right.
If the expressions are returning values that don't meet the spec, then we need to make adjustments. Note that an expression that "works" on a Wednesday date might not "work" on a Sunday date.)
DEMO: Showing 3 approaches and why current doesn't work.
If we assume by "last week" you mean the last full week Monday - Sunday of a week prior to the day you're presently on...
So if today was 20180422, you'd want 20180409-20180415
SELECT *
FROM SO50026532_sport_data
CROSS JOIN (SELECT #Today:=curdate()) z
WHERE date >= #today - interval (6 + case when dayofweek(#today)=1 then 7 else dayofWeek(#today)-1 end) day
and date <=#today - interval (case when dayofweek(#today)=1 then 7 else dayofWeek(#today)-1 end) day;
Or if your a fan of the >= and < then
SELECT *
FROM SO50026532_sport_data
CROSS JOIN (SELECT #Today:=curdate()) z
WHERE date >= #today - interval (6 + case when dayofweek(#today)=1 then 7 else dayofWeek(#today)-1 end) day
and date <#today - interval (case when dayofweek(#today)=1 then 7 else dayofWeek(#today)-1 end-1) day;
in the 2nd example we had to subtract by 1 since dayofweek isn't a 0 based. Of course I could have just date shifted everything down 2 and set sunday to 6... then I wouldn't' need to subtract by 1. and then we'd be adding 7 instead of 6 on the 1st part of the where. (demo has these 3 and your initial example showing what happens on 4/22.
Dayofweek starts on Sunday being 1. So I use a case statement to shift 1 to 7 and and all the others down 1 giving us Monday = 1 and sunday = 7
The cross join to derived table z was so I could control the curdate() easier and test. You could replace the variable with curdate() if you want and eliminate the cross join and derived table.
The first where clause subtracts 6 days (1 week and then the # of days from current date back to monday. This ensures we always start 1 week back from current date and on a monday. then we only get dates to the Sunday of that week.
There are a method with SQL to SELECT from one database the date records where the date is today and the date is multiple of two years.
For example, i have a table call "list". That table have two column, 'ID' and 'last_date'. One of this record is: ID = '1' and date = '17-03-2015'
I need to select all record where the date is the date on the table + 2 year. For example today the query will return the ID 1.
Thanks to all.
Use DATE_SUB() to subtract 2 years from today's date, and compare that to the column.
SELECT id
FROM list
WHERE last_date = DATE_SUB(CURDATE(), INTERVAL 2 YEAR);
This is a little better than #Teja's solution because it only has to do the date arithmetic once, rather than for every row in the table. And if there's an index on the last_date column, it will be able to use it to find the rows quickly.
We can write an expression that returns a date value that is exactly two days before today's date:
SELECT DATE(NOW()) + INTERVAL -2 YEAR
We can use an expression in the WHERE clause of a query. If the column in the table we want to check is defined as DATE datatype:
SELECT t.id
FROM mytable t
WHERE t.mydatecol = DATE(NOW()) + INTERVAL -2 YEAR
If it's defined as a DATETIME, the normal pattern would be range check
SELECT t.id
FROM mytable t
WHERE t.mydatecol >= DATE(NOW()) + INTERVAL -2 YEAR
AND t.mydatecol < DATE(NOW()) + INTERVAL -2 YEAR + INTERVAL 1 DAY
If the column is stored as a VARCHAR in a non-canonical format e.g. DD-MM-YYYY then we could either attempt to convert that to a DATE using STR_TO_DATE (which we don't like to do because the query can't make effective use of a index), or we could convert our generated date value into the required string format for an equality comparison:
SELECT t.id
FROM mytable t
WHERE t.ddmmyyyy = DATE_FORMAT(DATE(NOW()) + INTERVAL -2 YEAR,'%d-%m-%Y')
That would get us exact match to '17-03-2015', but not to '17-3-2015'. And we have to do equality test or IN list, we can't do range check, because the value stored in the column isn't canonical.
If we need to look for multiple dates... today, two years ago, four years ago, six years ago, ... we can generate a list of dates and perform a join operation. (Assuming that mydatecol is defined as DATETIME...)
SELECT t.id
FROM ( SELECT DATE(NOW()) + INTERVAL 0 YEAR AS dt
UNION ALL SELECT DATE(NOW()) + INTERVAL -2 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -4 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -6 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -8 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -10 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -12 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -14 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -16 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -18 YEAR
UNION ALL SELECT DATE(NOW()) + INTERVAL -20 YEAR
) l
JOIN mytable t
WHERE t.mydatecol >= l.dt + INTERVAL 0 DAY
AND t.mydatecol < l.dt + INTERVAL 1 DAY
I have a subscriptions table with an associated feed_id and creation timestamp. A feed has N subscriptions.
It's easy enough to show the most popular feeds using a group query to count the number of records with each feed_id. But I want to calculate momentum to show most trending feeds.
A simplified algorithm would be:
momentum of feed_id =
10 * (count of subscriptions with created_at in past day)
+ 5 * (count of subscriptions with created_at from 2-7 days ago)
+ 1 * (count of subscriptions with created_at from 7-28 days ago)
How can something like this be done in a single (My)SQL query instead of doing it with 3 queries and programmatically summing the results?
You can use conditional aggregation for this. MySQL treats booleans as integers, with true being "1", so you can just sum the expression for time.
I am guessing it looks something like this:
select feedid,
(10 * sum(createdat >= date_sub(now(), interval 1 day)) +
5 * sum(createdat >= date_sub(now(), interval 7 day) and
createdat < date_sub(now(), interval 1 day)) +
1 * sum(createdat >= date_sub(now(), interval 28 day) and
createdat < date_sub(now(), interval 7 day))
) as momentum
from subscriptions
group by feedid
SELECT 10*COUNT(IF(created_at >= CURDATE(), 1, 0)) +
5*COUNT(IF(created_at BETWEEN DATE_ADD(CURDATE(), - INTERVAL 7 days) AND DATE_ADD(CURDATE(), - INTERVAL 1 day), 1, 0) +
1*COUNT(IF(created_at BETWEEN DATE_ADD(CURDATE(), - INTERVAL 28 days) AND DATE_ADD(CURDATE(), - INTERVAL 8 day), 1, 0)
FROM ...
I'm not 100% sure I've caught the edge conditions (yesterday or 8 days ago) to get exactly the right count. You'll want to test that.
If you're interested in 24-hour periods then just substitute NOW() for CURDATE() and everything will go to DATETIME.
Say i have an expiration date field, called expires_at, and lets say i have 1 row with 1 value whitch is 10 days from today.
How do i query all rows where expires_at is no more then 14 days from now or before that?
Something like this i asume
SELECT * FROM column WHERE CURDATE() +14? >= expires_at
Can i add 14 days to the current date and just get all the days before CURDATE() + 14?
I am not awesome at SQL
SELECT * FROM your_gtable
WHERE expires_at <= CURDATE() + interval 14 day
... WHERE expires_at < DATE_ADD( NOW(), INTERVAL 14 DAY)