I am trying to use TIMESTAMPDIFF function in one of my queries and is making an headache for me.
TABLE
id | web_address | timeperiod | timeperiod_exp
1 | www.google.com | 1564692614 | 1564779014
1564692614 = GMT: Thursday, August 1, 2019 8:50:14 PM
1564779014 = GMT: Friday, August 2, 2019 8:50:14 PM
WHATS THE PROBLEM ?
As one can see the difference between these two timestamps is exactly 1 day but is returning no records.
SELECT * FROM mytable WHERE TIMESTAMPDIFF(DAY, timeperiod, timeperiod_exp) >= 1
WHERE IS THE FIDDLE ?
https://www.db-fiddle.com/f/udmrC2xdvrEEKGxEF7ty84/7
WHAT SHOULD BE DONE ?
Please take a look at the fiddle above and suggest what should be modified or other function in place of timestampdiff.
Look at the documentation for TIMESTAMPDIFF()
TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2)
Returns datetime_expr2 − datetime_expr1, where datetime_expr1 and
datetime_expr2 are date or datetime expressions. One expression may be
a date and the other a datetime
As you see, it expects the parameters to be of type DATE or DATETIME. But you have your timestamps stored as integers.
So either use FROM_UNIXTIME() to convert your integer timestamps to DATETIME:
SELECT *
FROM mytable
WHERE TIMESTAMPDIFF(DAY, FROM_UNIXTIME(timeperiod), FROM_UNIXTIME(timeperiod_exp)) >= 1
db-fiddle
Or just use simple arithmetics (since we know how many seconds are in one day):
SELECT *
FROM mytable
WHERE (timeperiod_exp - timeperiod) >= 60*60*24
db-fiddle
As if i see the function TIMESTAMPDIFF() should take two timestamps but it is taking dates instead of direct timestamps in integers Thus the following works:
SELECT * FROM mytable WHERE TIMESTAMPDIFF(DAY, FROM_UNIXTIME(timeperiod), FROM_UNIXTIME(timeperiod_exp)) >= 1
Updated Fiddle
https://www.db-fiddle.com/f/udmrC2xdvrEEKGxEF7ty84/8
Related
I have a table with a column of type date (yyyy-mm-dd h:i:s) on a MYSQL 5.7.26 server.
When I query like this:
SET #THIS_YEAR = "2019-01-01 00:00:00";
SELECT * FROM table WHERE `date` > year(#THIS_YEAR);
I am expecting all entries with date since 2019-01-01.
But I also get entries from years before.
But this query works is:
SELECT * FROM table WHERE `date` > "2019";
Btw this query also returns the wrong (or rather unexpected) results:
SELECT * FROM table WHERE `date` > 2019;
What is the difference between these queries? Why doesnt it work with a variable or when comparing the date to an integer? I assume its somekind of auto type conversion?
MySQLs implicit type conversion can be very surprising. If you want to understand the behavior of your queries, you can try to apply the type conversion rules as described in Type Conversion in Expression Evaluation. However - I failed to do that for your case. For example: For the two expressions date > '2019' and date > 2019 I would apply the following rule:
If one of the arguments is a TIMESTAMP or DATETIME column and the
other argument is a constant, the constant is converted to a timestamp
before the comparison is performed.
But that cannot be the case, because neither the number 2019 nor the string '2019' can be converted to a temporal type. Here is a query, which demonstrates some implicit conversions:
select '2019' + interval 0 day -- implicit cast to date(time)
, 2019 + interval 0 day
, 20190101 + interval 0 day
, 190101 + interval 0 day
, '2019*01*01' + interval 0 day
, '2019-01-01' + interval 0 day
, '2019-01-01' + 0 -- implicit cast to numeric
, date('2019-01-01') + 0
, date('2018-01-01') > 2019
, date('2018-01-01') > '2019'
;
Result:
Expression | Result
------------------------------|-----------
'2019' + interval 0 day | null
2019 + interval 0 day | null
20190101 + interval 0 day | 2019-01-01
190101 + interval 0 day | 2019-01-01
'2019*01*01' + interval 0 day | 2019-01-01
'2019-01-01' + interval 0 day | 2019-01-01
'2019-01-01' + 0 | 2019
date('2019-01-01') + 0 | 20190101
date('2018-01-01') > 2019 | 1
date('2018-01-01') > '2019' | 0
As you see, when we try to convert 2019 or '2019' to a date (or datetime), we get NULL. Thus the conditions should also be evaluated to NULL and the result set would be empty. But as we know, that is not the case. Maybe I'm just wrong, assuming that 2019 and '2019' are constants. But then I don't know what they could mean.
So I can only make assumptions. And my assumtion is: Whenever one comparator is numeric, the other value is also converted to a numeric value. This would be the case for date > 2019 aswell as for date > year(#THIS_YEAR). In this case the date 2018-01-01 is converted to 20180101 (see the table above), which (in numeric context) is greater than 2019. So you get rows from the year 2018.
For date > '2019' I can only assume, that the values are compared as strings. And '2018-01-01' as string is considered "smaller" than 2019.
But even if that behavior would be properly documented, the rules are too difficult to remember, because one can hardly see any logic behind them. (I don't say - there is no logic - I just don't see any.)
So I can give you one advise: If you want to compare two incompatible types, always cast or convert them to be compatible.
WHERE year(date) >= year(#THIS_YEAR)
would be fine, since you compare two numeric values. But that is not necessery in your case and you can just use
WHERE date >= #THIS_YEAR
because 2019-01-01 00:00:00 in
`SET #THIS_YEAR = "2019-01-01 00:00:00";`
is a perfectly formatted DATETIME string and can be considered compatible with the DATETIME type. '2019-01-01' would be just fine aswell.
Note that if you wrapp a column into a function call (like year(date)) you will loose the ability to use an index on that column.
The underlying problem is one of data types.
In short words: The interpreter has a hard time knowing if your "2019" is a string or a date. So it goes by what it expects there to be.
If you store the value into a variable, it is parsed as a string, because a string is expected here. If you compare it directly, a date value is expected - and so MySQL tries to parse a date, successfully.
2019, as opposed to "2019" clearly is a number, not a date value. So that explains funny behaviour there.
This query will compare the year from #THIS_YEAR and date:
SET #THIS_YEAR = "2019-01-01 00:00:00";
SELECT * FROM table WHERE year(`date`) = year(#THIS_YEAR);
Notice date is wrapped in the year function. This means that you are now comparing year() to year().
This query works
SELECT * FROM table WHERE `date` > "2019";
Because the interpreter will use a character representation of date and perform character by character comparison: "2019-" > "2019"
This query doesn't work:
SELECT * FROM table WHERE `date` > 2019;
For the same reason. The interpreter will use a character representation of date and then compare the first character to 2019. "2" < 2019 (both in terms of human readable and numeric representation of the character 2
And this query:
SET #THIS_YEAR = "2019-01-01 00:00:00";
SELECT * FROM table WHERE `date` > year(#THIS_YEAR);
Has the same problem. year() returns a number so it will again be: "2">2019
In mysql, we can do the following for adding months:
SELECT DATE_ADD('2014-08-20', INTERVAL 13 MONTH); //Result: 2015-09-20
Is there any way to do the reversed operation ? Example:
SELECT DIFF_IN_MONTHS('2015-09-20', '2014-08-20') //Result: 13
Roundings due to day differences are not a problem for me.
The function TIMESTAMPDIFF does this:
SELECT TIMESTAMPDIFF(MONTH, '2015-09-20', '2014-08-20');
TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2)
Returns datetime_expr2 – datetime_expr1, where datetime_expr1 and
datetime_expr2 are date or datetime expressions. One expression may be
a date and the other a datetime; a date value is treated as a datetime
having the time part '00:00:00' where necessary. The unit for the
result (an integer) is given by the unit argument
So you are wanting to get the difference in days between the 2 dates?
DATEDIFF('1015-09-20','2014-08-20')
The title might be a bit misleading, but what I want is:
SELECT * FROM table ORDER BY pid ASC
And in one of the columns I have a DATE(). I want to compare the current date (not time) and return how many days are left till that date. Let's say the date is 2013-04-20 and today's date is 2013-04-16 I don't want to get any data if it's < current date. If it is I want it returned in days.
I've been looking around here and I've found no way to do it, and I can't for the love of me figure it out.
If you're looking for the difference between two date you can use the GETDATE function in MS SQL
SELECT DATEDIFF(DD, DateOne, DateTwo) FROM TABLE
This will return the difference in number of days between the two dates.
If you only want rows where the date field is less than or equal to today's date you can use:
SELECT DATEDIFF(DD, DateField, GETDATE())
FROM TableName
WHERE DateField <= GETDATE()
If you're using MySQL you can use DATEDIFF()
SELECT
DATEDIFF(NOW(), date_column) AS days_diff
FROM
tablename
Get the difference between two dates (ANSI SQL)
select the_date_column - current_date as days_left
from the_table
where the_date_column - current_date <= 4;
SQLFiddle: http://sqlfiddle.com/#!12/3148d/1
I want to make a query which returns me some values between two dates and two times...
The DATE and TIME values are in different columns, DATE is called FECHA and TIME is called HORAIN
I have 4 possible values with just a DATE query:
Value 1 has Date 2012-05-07 time 02:45:00
Value 2 has Date 2012-05-07 time 12:00:00
Value 3 has Date 2012-05-08 time 04:35:00
Value 4 has Date 2012-05-08 time 07:30:00
What I want to get, is the results from 07:00:00 to 23:59:59 from the first day, and values from 00:00:00 to 06:59:59 from the second day (so an interval from 07 AM to 06:59 AM)
This is my query, which is returning NO VALUES... It must return me VALUE 2 and VALUE 3, because it matches my desired requirements
SELECT * FROM mytable
WHERE
(DATE(fecha)>='2012-05-07' AND TIME(horain)>='07:00:00')
AND
(DATE(fecha)<='2012-05-08' AND TIME(horain)<='06:59:59');
What am I doing wrong? :(
You can fetch result using Concat(). It concatenating two fields value.so You can concatenate fecha with horain field value and then search for results like given below .
SELECT * FROM `mytable` WHERE (Concat(`fecha`, ' ', `horain`, '') <= '2012-05-08 06:59:59') AND (Concat(`fecha`, ' ', `horain`, '') >= '2012-05-07 07:00:00')
Concat() function take 4 parameter.
Value1
String from which concatenate value1 to value2
Value2
String want to concatenate in last
Hopefully it will be helpful for you
thanks.
Try to debug it one step at a time - eliminate as much restrictions and see if you get records - when you get them, add one condition at a time:
start with:
SELECT * FROM mytable
continue with:
SELECT * FROM mytable
WHERE
DATE(fecha)>='2012-05-07'
and so on, until you find the condition that cuts out all your records and see why that is happening
Try SELECT * FROM mytable WHERE FECHA >= 2012-05-07 AND horain >= 07:00:00)
AND FECHA <= 2012-05-08 AND horain <= 06:59:59 );
The time and date are checked separately
If we restructure your where clause and leave out the date part you get:
SELECT * FROM mytable
WHERE TIME(horain)>='07:00:00' AND
TIME(horain)<='06:59:59'
This will never give you a result since both can never be true.
what you can do, is combine the date and time fields
SELECT * FROM mytable
WHERE
concat(fecha,' ',horain) as date BETWEEN '2012-05-07 07:00:00' AND '2012-05-08 06:59:59';
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'