MySQL - BETWEEN will not select correct results - mysql

I am trying to select rows that are in between two dates. First, here is my data:
punch_id eid time unixtime punch_type day date doy
135 2 12:53 1314723193 0 4 08/28/2011 241
134 2 12:53 1314723190 3 4 08/31/2011 241
133 2 12:53 1314723187 2 4 08/20/2011 241
132 2 12:52 1314723125 1 4 08/30/2011 241
I have tried these two queries.
SELECT * FROM `punches` WHERE `date` >= '08/20/11' AND `date` <= '08/31/11'
SELECT * FROM `punches` WHERE `date` BETWEEN '08/20/11' AND '08/31/11'
Neither of these select the rows containing the date 08/31/11. It selects the 08/20/11 ones though. I tried to use it another way and when I run the query:
SELECT * FROM `punches` WHERE `date` >= '08/10/11' AND `date` <= '08/20/11'
I again do not get the correct result: the 20th is left out once again. What is the problem with the way I am executing this?

See this related question.
As others have mentioned, your primary problem is not accounting for the time. A few options to handle that:
Use a function to convert the DateTime to a Date. I don't recommend this option, since it will likely make the function non-sargeable.
Expand your BETWEEN to explicitly include the last moment of the day: (note: this is the latest possible value that MS SQL can store, don't know if MySQL has the same value)
SELECT * FROM `punches` WHERE `date`
BETWEEN '08/20/11 00:00:00.000' AND '08/31/11 23:59:59.997'
Use a < for the upper value
SELECT * FROM `punches` WHERE `date` >= '08/20/11' AND `date` < '09/01/11'
I actually think that last one is easier, in most situations.
I suppose you could do other things, like change the datatype of the column, but I've assumed here that you're just interested in changing the query.
** Disclaimer: I'm a MS SQL guy, not MySQL

I don't know mysql, but in other RDBMS, dates are assuming a time part of 12 AM. If you want to include the high date, add 1 to the day.

Is your date field of type DATE or DATETIME?
It probably has to do with the time of day. If you have a DATETIME stored as
2011-08-31 13:00:00
then it won't match on
BETWEEN '08/20/11' AND '08/31/11'
You'd have to use
BETWEEN '08/20/11' AND '09/01/11'
The MySQL docs for between say it matches "less than or equal to" max, so it is probably the time of day throwing you off.

When you don't specify a time with the date, then 00:00:00 is implied. Therefore the real query that the database is doing is more like...
SELECT * FROM `punches` WHERE `date` BETWEEN '08/20/11 00:00:00' AND '08/31/11 00:00:00'
Therefore a punch on 08/31/2011 at 12:53 will not get included. I think this should work, and is a bit more elegant than adding a day to the end date...
SELECT * FROM `punches` WHERE DATE(`date`) BETWEEN '2011-08-20' AND '2011-08-31'

Related

SQL query to retrieve latest 2 week records

I have a database with CreatedDate is store in Unix epoch time and some other info. I want a query to able to retrieve latest 2 week record base on the last record.
Below is part of the example
ID User Ranking CreatedDate
-------------------------------------------------------
1 B.Sisko 1 1461136714
2 B.Sisko 2 1461123378
3 B.Sisko 3 1461123378
4 B.Sisko 3 1461600137
5 K.Janeway 4 1461602181
6 K.Janeway 4 1461603096
7 J.Picard 4 1461603096
The last record CreatedDate is 25 Apr 2016, so I want the record from 12 Apr to 25 Apr.
I not sure how to compare to get latest data? any suggestion
The simplest method is probably to just subtract two weeks from today's date/time:
where CreatedDate >= UNIX_TIMESTAMP() - 7*24*60*60
Another approach is to convert the value to a date/time:
where from_unixtime(CreatedDate) >= date_sub(now(), interval 2 week)
The advantage of this approach is that it is easier to align to days. So, if you want two weeks starting at midnight:
where from_unixtime(CreatedDate) >= date_sub(curdate(), interval 2 week)
The disadvantage is that the function on the column prevents the use of indices on that column.
EDIT:
This is definitely not how your question was phrased. But in that case, you should use:
select t.*
from t cross join
(select from_unixtime(max(CreatedDate)) as maxcd from t) m
where from_unixtime(CreatedDate) >= date_sub(maxcd, interval 2 week);
It may seem odd, but you need to execute two queries one to find the Maximum Date and knock off 14 days -- and then use that as a condition to requery the table. I used ID_NUM since ID is a reserved word in Oracle and likely other RDBMS as well.
SELECT ID_NUM, USER, RANKING,
TO_DATE('19700101000000', 'YYYYMMDDHH24MISS')+((CreatedDate-18000)
/(60*60*24)) GOOD_DATE
FROM MY_TABLE
WHERE
GOOD_DATE >=
(SELECT MAX( TO_DATE('19700101000000', 'YYYYMMDDHH24MISS')+
((CreatedDate-18000) /(60*60*24))) -14
FROM MY_TABLE)

select specific time from diffrent dates datetime mysql field

I have a range of dates like
2015-05-31 17:36:36.000000
to
2015-12-20 22:20:00.000000.
well, i want fetch rows which are between 17 and 19 of each day in that period of time. of course it is important that include minutes too.
i mean, in every single day, if a row has a time which is between 17 to 20, i need that.
What query should i use?
i used
SELECT *
FROM (`orktape`)
WHERE STR_TO_DATE(timestamp, '%Y-%m-%d %H:%i:%s') >= '2015-05-31 17:36:36.000000'
AND STR_TO_DATE(timestamp, '%Y-%m-%d %H:%i:%s') < '2015-12-20 22:20:00.000000'
ORDER BY `timestamp` desc
but it result all the rows which are between 2015-05-31 17:36:36.000000 and 2015-12-20 22:20:00.000000 which include some rows like 2015-12-20 02:20:00.000000 which is not the correct result.
Thanks.
You can select in a range of hours by...
SELECT * FROM orktape WHERE HOUR(mytimestamp) >= 17 AND HOUR(mytimestamp) < 19
Not sure what your timestamp column is called, I would not call it timestamp, that could be confusing.

Grouping timestamp field by date

I am trying to write an SQL query to return how many links were submitted to my website over the last 7 day period. So far I have this:
SELECT COUNT(`id`) AS `count`
FROM `links`
WHERE `created` > NOW() - 86400
AND `created` < NOW()
this works for one day, it returns one row called count with the number of links submitted in the last 24 hours. I need to change it to return 2 columns called date and count, with 7 rows (one for each day).
The tricky part that I can't get my head around is that created is a timestamp column, and I don't have access to change it so I have to work with it.
Edit: work in progress for the query:
SELECT DAY(FROM_UNIXTIME(created)) AS day, COUNT(id) count
FROM links
GROUP BY DAY(FROM_UNIXTIME(created))
LIMIT 7
NOW() actually shouldn't be working as it returns a datetime. Also, if you want to fetch 7 days worth of data, you want to subtract 604800 from UNIX_TIMESTAMP(). You can use then date and time functions with FROM_UNIXTIME. This will make grouping easier. Optimally, your column should be of datetime type.
It would go something like:
SELECT DAY(FROM_UNIXTIME(created)) day, COUNT(id) count
FROM links
WHERE created > UNIX_TIMESTAMP() - 604800 AND created < UNIX_TIMESTAMP()
GROUP BY DAY(FROM_UNIXTIME(created))
You can alternatively use the BETWEEN operator:
WHERE created BETWEEN UNIX_TIMESTAMP() - 604800 AND UNIX_TIMESTAMP()
See the demo

What SQL statement will return rows with a matched date and datetimes?

Edit: I've been staring at the screen too long and realized that I actually put down 6 o'clock (18) down instead of 4 o'clock (16) like I needed. I had one row that matched the 18, which is why there was only one row that kept getting returned. Technically, my code works if I changed it to 16's, but #Gordon Linoff's answer is much faster with the JOINs. My statement takes 0.33 seconds to return, and Gordon's takes 0.0003.
I've got three tables that I'm trying to match up rows by two datetime columns and a date column. My current SQL command looks like:
SELECT puyforecast.timestamp, tacforecast.timestamp, date
FROM puyforecast, tacforecast, stnrain
WHERE puyforecast.timestamp LIKE CONCAT(date, ' 18:%')
AND tacforecast.timestamp LIKE CONCAT(date, ' 18:%');
This pulls up only the first matching row:
2013-01-28 18:37:33, 2013-01-28 18:37:34, 2013-01-28 which is what I would expect from the statement. I want to see all rows that have a matching date and datetime stamps. The two timestamps from both puyforecast and tacforecast should only be the rows where the time is at at 18:00 (4 o'clock in the afternoon). I don't care about minutes or seconds when comparing the datetimes, so those shouldn't have an effect on the matching.
I should be seeing an entry like so:
2013-01-28 18:37:33, 2013-01-28 18:37:34, 2013-01-28
2013-01-29 18:00:02, 2013-01-29 18:00:34, 2013-01-29
2013-01-30 18:00:02, 2013-01-30 18:00:34, 2013-01-30
...
and &c, with date matching going on until the current date. The two datetime columns go back farther in time than the date column does.
I've been trying a few searches, but I can't seem to find what it is I'm searching for.
Can you just match these on date?
SELECT pf.timestamp, tf.timestamp, date
FROM stnrain s join
puyforecast pf
on date(pf.timestamp) = s.date and
hour(pf.timestamp) = 18 join
tacforecast tf
on date(tf.timestamp) = s.date and
hour(tf.timestamp) = 18
The improvement on performance was not because you converted your queries to use the JOIN syntax, it was probably because you got rid of the LIKE conditions. Date and datetime columns should not be compared with LIKE, that is for string comparisons.
You can also rewrite your query like this:
SELECT p.timestamp AS p_timestamp,
t.timestamp AS t_timestamp,
s.date
FROM stnrain AS s
JOIN puyforecast AS p
ON p.timestamp >= s.date + INTERVAL 18 HOUR
AND p.timestamp < s.date + INTERVAL 19 HOUR
JOIN tacforecast AS t
ON t.timestamp >= s.date + INTERVAL 18 HOUR
AND t.timestamp < s.date + INTERVAL 19 HOUR ;
This may use different indexes (on the timestamp columns) and it might be more efficient. Of course it might be worse, test it!

MySQL SELECT WHERE datetime matches day (and not necessarily time)

I have a table which contains a datetime column. I wish to return all records of a given day regardless of the time. Or in other words, if my table only contained the following 4 records, then only the 2nd and 3rd would be returned if I limit to 2012-12-25.
2012-12-24 00:00:00
2012-12-25 00:00:00
2012-12-25 06:00:00
2012-12-26 05:00:00
NEVER EVER use a selector like DATE(datecolumns) = '2012-12-24' - it is a performance killer:
it will calculate DATE() for all rows, including those, that don't match
it will make it impossible to use an index for the query
It is much faster to use
SELECT * FROM tablename
WHERE columname BETWEEN '2012-12-25 00:00:00' AND '2012-12-25 23:59:59'
as this will allow index use without calculation.
EDIT
As pointed out by Used_By_Already, in the time since the inital answer in 2012, there have emerged versions of MySQL, where using '23:59:59' as a day end is no longer safe. An updated version should read
SELECT * FROM tablename
WHERE columname >='2012-12-25 00:00:00'
AND columname <'2012-12-26 00:00:00'
The gist of the answer, i.e. the avoidance of a selector on a calculated expression, of course still stands.
... WHERE date_column >='2012-12-25' AND date_column <'2012-12-26' may potentially work better(if you have an index on date_column) than DATE.
You can use %:
SELECT * FROM datetable WHERE datecol LIKE '2012-12-25%'
SELECT * FROM `table` where Date(col) = 'date'
Similiar to what Eugene Ricks said. If one is using spring data/jpa with Java 8 and above you can use plusDays(long hours) to increase day 25 to 26.
Example:
LocalDateTime lowerDateTime=LocalDateTime.parse("2012-12-25T00:00:00");
LocalDateTime upperDateTime = lowerDateTime.plusDays(1l);
System.out.println("my lowerDate =="+lowerDateTime);
System.out.println("my upperDate=="+upperDateTime);