SELECT from database date where date is today and multiple - mysql

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

Related

Counting all rows in column with two different date conditions

I'm trying to turn two count queries with date conditions (the ones below) into one query.
SELECT COUNT(*) as yesterday FROM orders WHERE DATE(timedate) = DATE(NOW() - INTERVAL 1 DAY)
SELECT COUNT(*) as yesterday FROM orders WHERE DATE(timedate) = DATE(NOW() - INTERVAL 2 DAY)
Following the advice of another answer I created the following, but that doesn't seem to work syntax-wise, and I'm not quite sure why. Is there another way to do this? I can't find a similar question on this
SELECT
SUM(IF(DATE(timedate) = DATE(NOW() - INTERVAL 1 DAY))) AS testcount1,
SUM(IF(DATE(timedate) = DATE(NOW() - INTERVAL 2 DAY))) AS testcount2
FROM
orders
You're missing the output values for the IF expression. Also you should use CURRENT_DATE() so you don't need to convert to a DATE:
SELECT
SUM(IF(DATE(timedate) = CURRENT_DATE() - INTERVAL 1 DAY, 1, 0)) AS testcount1,
SUM(IF(DATE(timedate) = CURRENT_DATE() - INTERVAL 2 DAY, 1, 0)) AS testcount2
FROM
orders
Note that MySQL treats boolean expressions as 1 (true) or 0 (false) in a numeric context, so you can actually SUM the expression without needing the IF:
SELECT
SUM(DATE(timedate) = CURRENT_DATE() - INTERVAL 1 DAY) AS testcount1,
SUM(DATE(timedate) = CURRENT_DATE() - INTERVAL 2 DAY) AS testcount2
FROM
orders
You want conditional aggregation. I would phrase the query as follows:
SELECT
SUM(
timedate >= CURRENT_DATE - INTERVAL 1 DAY
and timedate < CURRENT_DATE
) AS testcount1,
SUM(
timedate >= CURRENT_DATE - INTERVAL 2 DAY
and timedate < CURRENT_DATE- INTERVAL 1 DAT
) AS testcount2
FROM orders
Details:
this uses a nice feature of MySQL, that evaluates false/true conditions as 0/1 in numeric context
no date functions are applied on the timedate column : instead, we do litteral date comparisons. This is much more efficient, since the database can possibly take advantage of an index on the datetime column
You might also want to add a WHERE clause to the query:
WHERE
timedate >= CURRENT_DATE - INTERVAL 2 day
AND timedate< CURRENT_DATE

Deleting records that are over 4 years old from today's date on MySQL

I want to delete records from my table when an end-date column is over 3 years expired past the current date
See below for what i have already tried
DELETE FROM membership
WHERE (SELECT EXTRACT (YEAR FROM end_date)) <
(SELECT EXTRACT (YEAR FROM (SELECT DATE_ADD( CURDATE(), INTERVAL -4 YEAR))))
I expect results that are from 2016 and before that to be deleted in my table
Thanks in advance
This will delete everything that has an end_date with a year of 2016 or older:
DELETE FROM membership WHERE YEAR(end_date) <= YEAR(CURDATE() - INTERVAL 3 YEAR);
EDIT: If you want to delete everything with an end_date that is over 3 years old:
DELETE FROM membership WHERE end_date < NOW() - INTERVAL 3 YEAR;
Some notes:
compare the bare column end_date against a value, as a date type
test expressions in SELECT statements, before running DELETE
What is the first date value that is greater than the end_date on the rows you want to delete? Test that expression in a SELECT statement.
SELECT DATE_FORMAT( NOW(), '%Y-01-01') + INTERVAL -3 YEAR
returns
2016-01-01
or, date value four years before now
SELECT DATE(NOW()) + INTERVAL -4 YEAR
returns:
2015-04-05
adjust that expression until it returns the value we need. Then we can include that expression in a statement, comparing to bare column end_date column, like this:
SELECT m.*
FROM membership m
WHERE m.end_date < DATE(NOW()) + INTERVAL -4 YEAR
ORDER BY m.end_date DESC
or if we know that the date value we need is '2015-04-05' or '2017-01-01' then we can just specify that as a literal:
SELECT m.*
FROM membership m
WHERE m.end_date < '2017-01-01' + INTERVAL 0 MONTH
ORDER BY m.end_date DESC
After we confirm that the SELECT statement is returning the set of rows we want to delete, then we can replace the SELECT keyword with DELETE.

MYSQL: Getting all results from last week starting Monday)

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.

MySQL select records for the past 3 months

what will be the smartest way to select all rows from MySQL table for the past 3 months if the table has the following columns:
| id (int) | year (int)| month (int) |
Considering that if the current month & year are for example 2.2016 I need to select all records for 11.2015 & 12.2015 & 1.2016
It is easy if the current month is greater than 3 because all months that I need to select are in the same year so I can subtract 3 from the current month and run simple query
SELECT * FROM mytabe where year=2016 and month >= xx
Select * from mytable where STR_TO_DATE(concat(year,"-",month,"-01"),'%Y-%m-%d')>date_sub(curdate(),Interval 3 month) ;
The above query will get fetch year and month from date 3 months before today
You can select three Months records by these queries follow this.
The columnName means which column data want you select.
The tableName means which table data want you select.
The dateColumnName means which column date base you want to select data.
It would return Last Month data from today.
SELECT columName FROM tableName WHERE dateColumName BETWEEN ( DATE(NOW()) - INTERVAL 1 MONTH) AND Date(Now())
It would return Second Last Month data from today.
SELECT columName FROM tableName WHERE dateColumName BETWEEN ( DATE(NOW()) - INTERVAL 2 MONTH) AND ( DATE(NOW()) - INTERVAL 1 MONTH)
It would return Third Last Month data from today.
SELECT columName FROM tableName WHERE dateColumName BETWEEN ( DATE(NOW()) - INTERVAL 3 MONTH) AND ( DATE(NOW()) - INTERVAL 2 MONTH)
May It help to others.
Please try this
Select * from mytable where STR_TO_DATE(concat(year,"-",month,"-01"),'%Y-%m-%d')>date_sub(curdate(),Interval 3 month) ;

MySQL select all dates that are an increment of x days

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