I am currently storing dates as Unix Time Stamps in an INT(10) column in a mysql version 4.0.8 db (MyISAM engine).
I query these dates to extract records between a date range using the following SQL:
$sql = "SELECT `users`.`real_name`, `users`.`user_value`, `clients`.`client_name`, `clients`.`client_stars`, `timing`.`start_date`, `timing`.`end_date`, `projects`.`project_name`
from timing
LEFT JOIN users on (users.id = timing.user_id)
LEFT JOIN clients on (clients.id = timing.client_id)
LEFT JOIN projects on (projects.project_id = timing.project_id)
WHERE start_date BETWEEN :start_date AND :end_date";
I am using PDO, hence the params.
I am 100% sure the :start_date and :end_date vars are correct in all cases as I have checked these. Also start_date is not ambiguous and there are no warnings/notices regarding this query.
My problem is that I do not get the rows expected. If I ask for rows between Midnight 2013/11/14 and Midnight 2013/11/15, the expectation is ONLY results from the 14th. However, rows from the 15th are also passed - but not all of them.
I also just tested between 1384473600 and 1384473600 - which is between midnight today and midnight today (as in the same timestamp).
The rows returned should be 0, yet it has returned all rows from today (for instance the first row returned has a start_date value of 1384524193)!
Have I missed something about how the between operator works in mySQL? How can it return rows when the min and max are the same?
I have tested and tested, and nearly every time I make a query, rows are returned that are ABOVE the specified between ceiling.
What is going wrong?
BETWEEN is a notoriously bad way to match dates and timestamps, because it's inclusive of both ends of the range.
This may work better for you
WHERE start_date >= :start_date
AND start_date < :end_date + 86400
The magic number 86400 is the number of seconds in a day. This selects all start_date values between midnight on the :start_date parameter inclusive, and then excludes all values on or after midnight on the day after the :end date. If you were using actual timestamps, you could say + INTERVAL 1 DAY instead of + 86400.
Although I do not know why, when I reversed the logic it worked perfectly.
WHERE timing.start_date < :end_date
AND timing.start_date >= :start_date
This did not work however, and returned the same erroneous results.
WHERE start_date >= :start_date
AND start_date < :end_date
Can Anyone explain why?
Related
How to write a sql query to find out that there are 2 days left before the current date.
In php, this can be done via:
$res['end_date'] - time () < 86400 * 3;
How can I do the same after 1 sql query, well or better, only 2 days, if less so that it does not work out, well, if it works out, it's okay.
UPD:
It is necessary to compose a sql query that will select only those records that have 2 days left before the end_date expires
The type is int for the field end_date and is stored via the time () function in php.
Can't compose a WHERE clause.
You can use the FROM_UNIXTIME function to convert it to a DateTime you can then use the NOW() plus 2 days to check if the date is under 2 days. You then have to check that the date is before the current time otherwise you'll get dates that have already gone.
SELECT
end_date
FROM
table
WHERE
FROM_UNIXTIME(end_date) <= NOW() + INTERVAL 2 DAY
AND
FROM_UNIXTIME(end_date) > NOW()
Assuming that you are storing an epoch timestamp (the number of seconds since January 1st, 1970), I would recommend:
select *
from mytable
where end_date >= unix_timestamp() and end_date < unix_timestamp() + 2 * 24 * 60 * 60
unix_timestamp() gives you the current epoch. You can use simple math to add two days to that.
The upside of this approach is that this does direct filtering against the store value, so this can take advantagae of an index on end_date - as opposed to converting the timestamp to a date, which requires converting the whole column before the filtering can happen. So this is much more efficient.
You can ajust the inequalities as you prefer. I used a half-open interval (inclusive on the lower bound and exclusive on the upper bound), which is a widely used approach.
I ended up doing this:
$time = time();
$params = $db->query("SELECT * FROM `params` WHERE (`end_date` - {$time}) < 86400 * 3");
And it worked.
I always do
select *
from mytable
where FROM_UNIXTIME(end_date) < NOW() + INTERVAL 2 DAY
This will get results where two days in the future is ahead of the end date ie, anything that will end within 2 days (or has already ended as I didn't add a check for that)
Edit: I see you can't use where
If you cannot use where clause
select FROM_UNIXTIME(end_date) - INTERVAL 2 DAY as end_date
from mytable
And then check in php if the result is before or after. This will show all results however
how to search between two date , when date format in database like :
2015-10-10 02:23:41 am
i just want to search between two date with format :
2015-10-10
without
02:23:41 am
any ideas please ?
Your question isn't completely clear. But, I guess you hope to find all the rows in your table where Date occurs on or after midnight on 2015-08-05 and before midnight on 2015-09-11 (the day after the end of the range you gave in your question.
Those two search criteria will find all the rows with Date values in the range you specified. (I'm ignoring the 02 at the end of 2015-09-10 02 in your question because I can't guess what it means, if anything.)
Try this query:
SELECT *
FROM table
WHERE `Date` >= '2015-08-05'
AND `Date` < '2015-09-10' + INTERVAL 1 DAY
This has the benefit that it can exploit an index on the Date column if you have one, so it can be fast.
You could write
SELECT *
FROM table /* slow! */
WHERE DATE(`Date`) BETWEEN '2015-08-05' AND '2015-09-10'
That's slightly easier to read, but the WHERE condition isn't sargable, so the query will be slower.
Notice that the beginning of the range uses >= -- on or after midnight, and the end of the range uses < -- before midnight.
Pro tip: Avoid the use of reserved words like DATE for column names. If you make mistakes writing your queries, their presence can really confuse MySQL, not to mention you, and slow you down.
May I suggest:
select * from table where cast(date as date) between '2015-08-05' and '2015-09-10'
When your where clause is based on a timestamp, but you're using date as the parameters for your between, it excludes anything that happens on the second date unless it happened precisely at midnight.
When using the end date for the range, include the time of the end of the day:
SELECT *
FROM YourTable
WHERE date BETWEEN '2015-08-05' AND '2015-09-10 23:59:59'
I'm trying to do a SELECT * FROM but only items that are less than 30 days old. Here is my select code:
SELECT * FROM `{$table_name33}` WHERE `type`='wpst-requiredinfo' ORDER BY `foreignkey` ASC;
However, my problem is that I can't figure out how to add WHERE AND last_updated is less than 30 days.
I'm not exactly sure how to write the query, but the date is showing up like this: 1428412603 in the table column, it doesn't look much like a date to me. I don't know where to start.
Try this where clause:
WHERE `type`='wpst-requiredinfo' and
last_updated >= date_sub(now(), interval 30 day)
EDIT:
Your date seems to be in Unix time format.
WHERE `type`='wpst-requiredinfo' and
last_updated >= unixtime_timestamp() - 30*24*60*60
Note: this puts all the functions on the current time. In particular, it does not use FROM_UNIXTIME(last_updated). This ensures that an index can be used for this part of the query. The best index would be on (type, last_updated).
I have a query that counts the "Xp" difference per day from my database, this all works as it should however it groups from midnight-midnight, what I would like to do is group 3am to 3am.
However another issue I think I may have is that my query may not always have the rows being the exact second at 3am due to the fact that it has to run a huge query and retrieve data from another website per user profile, so it should get all data after 3am, but before maybe 4am or something, so it has enough time to get all of the rows.
my current mysql is:
SELECT FROM_UNIXTIME(date, '%Y%m%d') AS YYYYMMDD, MAX(xp)-MIN(xp) AS xp_gain
FROM skills
WHERE userID = '$checkID'
AND skill = '$skill'
AND date >= '$date'
GROUP BY YYYYMMDD
ORDER BY date ASC
The best way to handle this is to add (if you can) another column that is just a DATE (not a DATETIME) and have this field rollover from one day to the next at 3am, (you can to this by subtracting 3 hours from the current time when doing the INSERT).
This gives you a couple of benefits, especially with a large number of rows:
It is much faster to query or group by a DATE than a range of
DATETIME
It will always query the rows at the exact second of 3am,
regardless of how long the query takes.
I have a DATETIME field. I would like to select all the records that have been updated in the last week. Right now I'm using this query:
SELECT SUM(mins_spent) as time_sum FROM todos WHERE
lastUpdate >= '2008-12-22' AND lastUpdate <='2008-12-28'
But the results i get seem to be different depending on time of the day, e.g on 7 PM I might get 17 hours and on 11 PM I'l get 14 hours even though it should be increasing, not decreasing. I was thinking of changing the query to:
SELECT SUM(mins_spent) as time_sum FROM todos WHERE
lastUpdate >= '2008-12-22 00:00:00' AND lastUpdate <='2008-12-28 00:00:00'
Would it help at all? Suggestions please..
'2008-12-22' should equal '2008-12-22 00:00:00'.
Are you wanting "till end-of-day 28th?" If so, add 23:59:59 to the 2nd date.
Alternatively, you can use lastUpdate < "2008-12-29".
How are you tracking changes to an existing ToDo? INSERT and/or DELETE? Or UPDATE?
If you're DELETE'ing records upon "completion," you'll just have fewer records.
If you're UPDATE'ing, are you allowing dates to change to beyond the current week? If so, they'll be removed from your results.
To see what's happening, You may try grabbing a few aggregates on the table, mins_spent, and lastUpdate (mark down the values and run occasionally to see how they change).
SELECT count(*) AS Total
FROM todos
WHERE lastUpdate >= '2008-12-22' AND lastUpdate <= '2008-12-28 23:59:59'
SELECT min(mins_spent) AS Min, max(mins_spent) AS Max, avg(mins_spent) AS Avg
FROM todos
WHERE lastUpdate >= '2008-12-22' AND lastUpdate <= '2008-12-28 23:59:59'
SELECT min(lastUpdate) AS Min, max(lastUpdate) AS Max
FROM todos
WHERE lastUpdate >= '2008-12-22' AND lastUpdate <= '2008-12-28 23:59:59'
Judging from the MySQL 6.0 Reference Manual for Date and Time Types, you should be more or less OK as written. However, if it really isn't working, then you may have found a reportable bug.
A DATE value is coerced to the DATETIME type by adding the time portion as '00:00:00'. To perform the comparison by ignoring the time part of the DATETIME value instead, use the CAST() function to perform the comparison in the following way:
date_col = CAST(NOW() as DATE);
Your queries say '<= '2008-12-28'; that should be strictly less-than, not less-than-or-equal.
One very fine point would be: do the expressions you wrote get treated as DATETIME (because the LHS is a DATETIME column) or as a DATE (because the RHS is best treated as a DATE) or, indeed, does the DATETIME get converted to a string to match the RHS? It would make a difference if the LHS is converted to a DATE, because any time on the 28th would come in range, whereas you seem to want everything from the 21st to the 27th. What happens if you do explicitly fixup the types with casts?
Also, is the MySQL server running in the same time zone as you? There seemed to be an 'off-by-an-hour' difference between what you were seeing and the nominal end of day? I'm still not sure exactly how that might be (mis-)working, but it could be an otherwise unaccounted for factor.