I want to retrieve records from db according to date format YYYY,MM,dd given by me but the column type is YYYY,MM,dd hh:mm:ss.
tried to use Date format function
SELECT *
FROM tabl.error_logs
where created_at = DATE_FORMAT(NOW(),'%Y-%m-%d'- INTERVAL 3 DAY);
I expect the created date will be 2019-06-08, but the result is empty
What is the actual datatype of created_at column?
This answer is going to ignore that funkiness with the format with commas, and assume that it's not character type data, and that it's DATETIME or TIMESTAMP.
Normative pattern for predicates on DATETIME and TIMESTAMP columns is a range comparison.
For example, to get all datetimecol values on June 10th, then something like this:
WHERE t.datetimecol >= '2019-06-10 00:00:00'
AND t.datetimecol < '2019-06-11 00:00:00'
Typically, I would just pass that one date value, and let MySQL figure out the next day. If we omit the time portion, MySQL will assume 00:00:00
WHERE t.datetimecol >= '2019-06-10' + INTERVAL 0 DAY
AND t.datetimecol < '2019-06-10' + INTERVAL 1 DAY
For performance, to allow MySQL to make effective use of a range scan operation on a suitable index, we want to avoid wrapping the column reference in a function. That is, specifying DATE(t.datetimecol) in a condition in the WHERE clause is going to force MySQL to evaluate the DATE() function on every row in the table.
With references to the bare column, that allows MySQL to make use of an index, if a suitable index is available.
e.g.
SELECT e.*
FROM tabl.error_logs e
WHERE e.created_at >= DATE(NOW()) + INTERVAL -3 DAY
AND e.created_at < DATE(NOW()) + INTERVAL -2 DAY
note that we can easily test those expressions in the WHERE clause, to verify they are returning what we want, and tweak as necessary:
SELECT DATE(NOW()) + INTERVAL -3 DAY
, DATE(NOW()) + INTERVAL -2 DAY
To make your query sargable, you need ...
SELECT *
FROM tabl.error_logs
WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL 3 DAY)
AND created_at < DATE_SUB(CURDATE(), INTERVAL 2 DAY)
This selects all values of created_at on or after midnight three days ago, up to but not including < midnight two days ago. It uses a range scan on an index on created_at if one is available.
You coudl use date_sub()
SELECT *
FROM tabl.error_logs
where date(created_at) = DATE_SUB(date(now()), INTERVAL 3 DAY);
if the column created_at is a date then you could avoid the date() function and let the index (if present) work for this column
SELECT *
FROM tabl.error_logs
where created_at = DATE_SUB(date(now()), INTERVAL 3 DAY);
Related
I'm trying to use sql CURDATE(), in format "YYYY-MM-DD", to select items from yesterday but time column is in "YYYY-MM-DD HH-MM-SS" format.
Is it possible to put CURDATE between % %, something like in this example (which obviously doesn't work);
SELECT * FROM table WHERE created_at LIKE % CURDATE() - INTERVAL 1 day %
Or if there is no syntax variation which makes use of curdate & also that works, do please recommend another way if there is any in sql bag of tricks.
Don't use string functions as strings! If you want yesterday, you can use:
where created_at >= current_date - interval 1 day and
created_at < current_date
Plus, this can use an index.
Or, you can simplify this to:
where date(created_at) = current_date - interval 1 day
And this version does not use an index on created_at.
I have this query
SELECT * FROM `timeclock_timecard`
WHERE `clock_in_datetime` > DATE_SUB(CURDATE(), INTERVAL 1 DAY)
which can get record in the last day but I need to limit to records created after 7AM
Any help please?
SELECT * FROM `timeclock_timecard`
WHERE `clock_in_datetime` > DATE_SUB(CURDATE(), INTERVAL 1 DAY)
and hour(`clock_in_datetime`) > 7;
Added one more filter condition to check for the hour.
Your query was almost correct, because CURDATE() only gives the date you can just subtract 17 hours to get the correct result. fiddle.
SELECT * FROM `timeclock_timecard`
WHERE `clock_in_datetime` >= DATE_SUB(CURDATE(), INTERVAL 17 HOUR)
To get the entries of the current day, we can add 7 hours (CURDATE() has time 0:00).
SELECT * FROM `timeclock_timecard`
WHERE `clock_in_datetime` >= DATE_ADD(CURDATE(), INTERVAL 7 HOUR)
To get only rows from yesterday, with a time value of 7AM or later, we can add 7 hours to the expression.
If we only up until midnight of today (just rows from yesterday), we can add another condition, the datetime is less than midnight today.
For example:
SELECT t.*
FROM `timeclock_timecard` t
WHERE t.`clock_in_datetime` >= DATE(NOW()) + INTERVAL -1 DAY + INTERVAL 7 HOUR
AND t.`clock_in_datetime` < DATE(NOW())
If you want to exclude the exact 7:00:00 AM value, change the >= to just >.
FOLLOWUP
Q: What I actually want is between about 5-6am TODAY and mindnight TODAY so anytime during today that I run the report for today I will get only timeclock data from users who clocked in/out today only and not include yesterdays data.
A: The predicates are going to be of the form
WHERE t.`clock_in_datetime` >= expr1
AND t.`clock_in_datetime` < expr2
You just need to find the expressions expr1 and expr2 that return the appropriate datetime values.
Just use a simple SELECT statement to test:
SELECT DATE(NOW()) + INTERVAL 5 HOUR AS `start`
, DATE(NOW()) + INTERVAL 1 DAY AS `end`
Q: I also modified my select to take in account my datetime is in UTC and my result needs to get todays records using local timezone.
SELECT * , CONVERT_TZ( clock_in_datetime , '+00:00', '-4:00' ) FROM `timeclock_timecard`
A: Personally, I would do the timezone conversion on the exprN values, not the column values. Having predicates on bare columns allows MySQL to make effective use of an index; wrapping the columns in expressions prevents MySQL from using an index.
If the MySQL system clock is UTC, and your datetime values stored in the table are in a different timezone, yes, use the MySQL CONVERT_TZ function.
Again, using a simple SELECT statement to develop and test the expressions:
SELECT CONVERT_TZ( DATE(NOW()) + INTERVAL 5 HOUR, '+0:00', to_tz) AS `start`
, CONVERT_TZ( DATE(NOW()) + INTERVAL 1 DAY , '+0:00', to_tz) AS `end`
Where to_tz is the timezone of the values in the table.
Once you get expressions start and end returning the values you need, then use those expressions in the predicates of the query of the timecard table.
I read some posts here and seems like nothing special but I can not still select the entries of the last days.
SELECT
p1.kArtikel,
p1.cName,
p1.cKurzBeschreibung,
p1.dLetzteAktualisierung,
p1.dErstellt,
p1.cSeo,
p2.kartikelpict,
p2.nNr,
p2.cPfad
FROM
tartikel AS p1 WHERE DATE(dErstellt) > (NOW() - INTERVAL 7 DAY)
INNER JOIN
tartikelpict AS p2
ON (p1.kArtikel = p2.kArtikel) WHERE (p2.nNr = 1)
ORDER BY
p1.kArtikel DESC
LIMIT
100;', $connection);
If I add the between today and last 7 days my Code will not output anything.
The WHERE clause is misplaced, it has to follow the table references and JOIN operations.
Something like this:
FROM tartikel p1
JOIN tartikelpict p2
ON p1.kArtikel = p2.kArtikel
AND p2.nNr = 1
WHERE p1.dErstellt >= DATE(NOW() - INTERVAL 7 DAY)
ORDER BY p1.kArtikel DESC
EDIT (three plus years later)
The above essentially answers the question "I tried to add a WHERE clause to my query and now the query is returning an error, how do I fix it?"
As to a question about writing a condition that checks a date range of "last 7 days"...
That really depends on interpreting the specification, what the datatype of the column in the table is (DATE or DATETIME) and what data is available... what should be returned.
To summarize: the general approach is to identify a "start" for the date/datetime range, and "end" of that range, and reference those in a query. Let's consider something easier... all rows for "yesterday".
If our column is DATE type. Before we incorporate an expression into a query, we can test it in a simple SELECT
SELECT DATE(NOW()) + INTERVAL -1 DAY
and verify the result returned is what we expect. Then we can use that same expression in a WHERE clause, comparing it to a DATE column like this:
WHERE datecol = DATE(NOW()) + INTERVAL -1 DAY
For a DATETIME or TIMESTAMP column, we can use >= and < inequality comparisons to specify a range
WHERE datetimecol >= DATE(NOW()) + INTERVAL -1 DAY
AND datetimecol < DATE(NOW()) + INTERVAL 0 DAY
For "last 7 days" we need to know if that mean from this point right now, back 7 days ... e.g. the last 7*24 hours , including the time component in the comparison, ...
WHERE datetimecol >= NOW() + INTERVAL -7 DAY
AND datetimecol < NOW() + INTERVAL 0 DAY
the last seven complete days, not including today
WHERE datetimecol >= DATE(NOW()) + INTERVAL -7 DAY
AND datetimecol < DATE(NOW()) + INTERVAL 0 DAY
or past six complete days plus so far today ...
WHERE datetimecol >= DATE(NOW()) + INTERVAL -6 DAY
AND datetimecol < NOW() + INTERVAL 0 DAY
I recommend testing the expressions on the right side in a SELECT statement, we can use a user-defined variable in place of NOW() for testing, not being tied to what NOW() returns so we can test borders, across week/month/year boundaries, and so on.
SET #clock = '2017-11-17 11:47:47' ;
SELECT DATE(#clock)
, DATE(#clock) + INTERVAL -7 DAY
, #clock + INTERVAL -6 DAY
Once we have expressions that return values that work for "start" and "end" for our particular use case, what we mean by "last 7 days", we can use those expressions in range comparisons in the WHERE clause.
(Some developers prefer to use the DATE_ADD and DATE_SUB functions in place of the + INTERVAL val DAY/HOUR/MINUTE/MONTH/YEAR syntax.
And MySQL provides some convenient functions for working with DATE, DATETIME and TIMESTAMP datatypes... DATE, LAST_DAY,
Some developers prefer to calculate the start and end in other code, and supply string literals in the SQL query, such that the query submitted to the database is
WHERE datetimecol >= '2017-11-10 00:00'
AND datetimecol < '2017-11-17 00:00'
And that approach works too. (My preference would be to explicitly cast those string literals into DATETIME, either with CAST, CONVERT or just the + INTERVAL trick...
WHERE datetimecol >= '2017-11-10 00:00' + INTERVAL 0 SECOND
AND datetimecol < '2017-11-17 00:00' + INTERVAL 0 SECOND
The above all assumes we are storing "dates" in appropriate DATE, DATETIME and/or TIMESTAMP datatypes, and not storing them as strings in variety of formats e.g. 'dd/mm/yyyy', m/d/yyyy, julian dates, or in sporadically non-canonical formats, or as a number of seconds since the beginning of the epoch, this answer would need to be much longer.
Since you are using an INNER JOIN you can just put the conditions in the WHERE clause, like this:
SELECT
p1.kArtikel,
p1.cName,
p1.cKurzBeschreibung,
p1.dLetzteAktualisierung,
p1.dErstellt,
p1.cSeo,
p2.kartikelpict,
p2.nNr,
p2.cPfad
FROM
tartikel AS p1 INNER JOIN tartikelpict AS p2
ON p1.kArtikel = p2.kArtikel
WHERE
DATE(dErstellt) > (NOW() - INTERVAL 7 DAY)
AND p2.nNr = 1
ORDER BY
p1.kArtikel DESC
LIMIT
100;
I have all dates stored as timestamps (int) in the database.
how can I get dates that are exactly 3 days earlier?
I tried
SELECT date from user WHERE DATE_ADD(DATE( FROM_UNIXTIME( `created` ) ), INTERVAL 3 DAY) = CURDATE()
is that the best/most efficient way to do it?
i think the database prefer to only do the date add 2 times to define the range, like:
SELECT date FROM user
WHERE UNIX_TIMESTAMP(DATE_ADD(CURDATE(), INTERVAL -3 DAY)) <= `created`
AND `created` < UNIX_TIMESTAMP(DATE_ADD(CURDATE(), INTERVAL -2 DAY));
Test putting DESCRIBE keyword before SELECT in both case, and the database respond with how its going to perform the query
SELECT date
FROM user
WHERE created = UNIX_TIMESTAMP(CURRENT_DATE - INTERVAL 3 DAY)
Note: no function used on the created column in where clause. This query should be able to use index.
I need to get the result from the table, which the date should be difference of 5 from the current date.
ie., specific_date column is present in my table. The format of the date is YYYY-MM-DD.
I need the query something like,
SELECT * FROM `table_name` WHERE DATEDIFF(NOW(), specific_date) < 5
It looks like you are trying to do this:
WHERE specific_date < (NOW() + 5 days)
First of all, think carefully about the boundary cases. These boundary cases can bite your ankles in SQL. Do you actually want
WHERE specific_date <= (NOW() + 5 days)
Do your specific_date columns timestamps contain only days (that is dates with times equal to midnight) or do they contain dates and times? If you're going to get the results you want, you need to be careful about those details.
At any rate, try this:
WHERE specific_date <= DATE_ADD(NOW(), INTERVAL 5 DAY)
This is a good way to do such a lookup. The column value stands alone on one side of the inequality predicate (the <=) so mySQL can do an index range scan if you have an index on the column.
Date arithmetic in MySQL is quite flexible. You can do
NOW() + INTERVAL 10 SECOND
NOW() - INTERVAL 2 MINUTE
NOW() + INTERVAL 4 HOUR
CURDATE() - INTERVAL 1 WEEK /* midnight one week ago */
LAST_DAY(NOW()) + INTERVAL 1 DAY - INTERVAL 1 MONTH /*first day of present month*/
NOW() - INTERVAL 1 QUARTER
CURDATE() - INTERVAL 5 YEAR
and so forth.
Have a look at the BETWEEN operator.
expr BETWEEN min AND max
Another way is to use the DATE_SUB operator
WHERE date_column > DATE_SUB(NOW(), INTERVAL 5 DAY)