TIMESTAMPDIFF Missing Days - sql

Can someone explain to me why this returns only 360 days and not 365 days?
I expect it to not count the first day but, what about the other 4 days?
SELECT
(TIMESTAMPDIFF(16,CHAR(TIMESTAMP('2017-12-31') - TIMESTAMP('2017-01-01'))))
FROM sysibm.sysdummy1
I am planning on just adding + 5 at the end.

If you have DB2 for Linux, Unix and Windows - now called Db2 - Version 11.1 you could also use
SELECT DAYS_between('2017-12-31','2017-01-01') FROM SYSIBM.SYSDUMMY1

I think the documentation explains this pretty well:
The returned estimate may vary by a number of days. For example, if
the number of days (interval 16) is requested for the difference
between '1997-03-01-00.00.00' and '1997-02-01-00.00.00', the result is
30. This is because the difference between the timestamps is 1 month, and the assumption of 30 days in a month applies.
In other words, the difference is 11 months and 30 days -- 11 * 30 + 30 = 360.
SELECT DAYS(DATE('2017-12-31')) - DAYS(DATE('2017-01-01'))
FROM sysibm.sysdummy1
For a more exact representation, try:

Related

Convert arbitrary string values to timestamps SQL

I am wondering if there is a way to convert arbitrary string values (such as the examples below) to something that can be interpreted as a timestamp, perhaps in days.
Dropdown_values
Desired Output(days)
12 weeks
84
1 Week 4 Days
11
1 Year
365
1 Year 1 Week 2 Days
374
The idea I had was to split part out the values since they are all separated by spaces and then do the addition in a separate column, are there other (better) ways to do this? Thank you.
To expand on my comment as an answer:
select extract(epoch from '12 Week'::interval)/86400; 84
select extract(epoch from '1 Year 1 Week 2 Days'::interval)/86400; 11
select extract(epoch from '1 Year 1 Week 2 Days'::interval)/86400; 374.25
The above is how I usually deal with this sort of thing. Extract the epoch value from a the interval and then divide by the number of seconds in a day. It would be a good idea to read in the docs this Interval input and Interval output to understand how an interval is constructed and returned and the assumptions used. Note: the queries will return a float value not a timestamp. A value like 84 cannot be timestamp. You could turn it into an interval like: 84 * '1 day'::interval 84 days. If at all possible it is good idea to store data as actual timestamps(start and end) and then derive intervals from that.

how to convert minutes to days in oracle

How would you convert a number of minutes to number of days? For instance, number of minutes is 20160. Now how do I get number of days based on that using SQL?
--divide by 60 get the number of hours and then by 24 to get the number of days
select 20160/60/24 as days_from_min
from dual
You divide:
select 20160 / (24 * 60) as num_days
This returns a fraction. You can floor() or round() to get a whole number.
Only for the sake of completeness: here is a way to do it with Oracle functions. (For people who do not want to just assume that the Earth will continue to rotate at a constant speed for the life of their software.)
select extract(day from numtodsinterval(20160,'MINUTE')) days
from dual;
This gives full days only, so it's essentially the same as
select floor(20160/(24*60)) days from dual;

Getting random time interval in postgreSQL

I need random interval time between 0 and (10 days and 5 hours).
My code:
select random() * (interval '10 days 5 hours')
from generate_series(1, 50)
It works like should, except a few strange results, like:
0 years 0 mons 7 days 26 hours 10 mins 1.353353 secs
The problem is 26 hours, it shouldn't be more than 23. And I never get 10 days, what I'd like to.
Intervals in Postgres are quite flexible, so hour values of greater than 23 do not necessarily roll over to days. Use jusify_interval() to return them to the normal "days" and "hours"."
So:
select justify_interval(random() * interval '10 day 5 hour')
from generate_series(1, 200)
order by 1 desc;
will return values with appropriate values for days, hours, minutes, and seconds.
Now, why aren't you getting intervals with more than 10 days? This is simple randomness. If you increase the number of rows to 200 (as above), you'll see them (in all likelihood). If you run the code multiple times, sometimes you'll see none in that range; sometimes you'll see two.
Why? You are asking how often you get a value of 240+ in a range of 245. Those top 5 hours account for 0.02% of the range (about 1/50). In other words a sample of 50 is not big enough -- any given sample of 50 random values is likely to be missing 1 or more 5 hour ranges.
Plus, without justify_interval(), you are likely to miss those anyway because they may show up as 9 days with an hours component larger than 23.
Try this:
select justify_hours(random() * (interval '245 hours'))
FROM generate_series(1, 50)
See Postgres Documentation for an explanation of the justify_* functions.
One option would be to use an interval of one hour, and then multiply by the random number between 0 and 1 coming from the series:
select random() * 245 * interval '1 hour'
from generate_series(1, 50);
I can see that the other answers suggest using justify_interval. If you just want a series of intervals between 0 and 245 hours (245 hours corresponding to 10 days and 5 hours), then my answer should suffice.

Why is result of age() not always equivalent to interval when going back in time?

I've come across some unexpected behavior of my SQL code in PostgreSQL 9.6 cornering date calculations. While analyzing, I've found out that Postgres will not always return the same value for going back n days and then calculate the duration with age().
Consider this code: We set some day as "base", go 45 days back and then calculate the duration.
WITH basedate AS (SELECT '2018-05-01'::date AS b),
myperiod AS (SELECT (basedate.b - interval '45 days') AS "startDate",
basedate.b AS "endDate" FROM basedate)
SELECT age("endDate","startDate") FROM myperiod;
I expect this query to always result in 45 days. However, if I change my basedate to 2018-06-01, I'll get 44 days.
Why is this the case?
My guess is this is somehow related to May having 31 days. However, I cannot exactely explain why, since both 2018-05-01 and 2018-06-01 will result in the same duration if I change 45 days to 15 days.
That's not quite true.
Your first query returns
age
---------------
1 mon 15 days
(1 row)
and if you modify the date to 2018-06-01, you get
age
---------------
1 mon 14 days
(1 row)
Both are correct, aren't they?
The problem is rather that PostgreSQL treats a month as 30 days in functions like justify_interval:
SELECT justify_interval('45 days');
justify_interval
------------------
1 mon 15 days
(1 row)
But then, the alternative would be to throw an error, and the behavior is clearly documented.
Laurenz Albe's answer points to the right thing: I should have expected a result starting with 1 mon.
The problem was actually in the client, in this case OmniDB 2.8. See here: GitHub OmniDB: Does OmniDB auto-convert intervals to days? The issue was fixed in OmniDB 2.9
In all other clients I've tested I got a result like Laurenz Albe predicted.
So, if you come across here while having a similar issue: By any means, check if the problem is in your client or the library you use.

problem with SQL query in DB2

How can i write a query in DB2 for following thing:
The difference between current timestamp and a timestamp field in dB should be >=4 hours AND
<= 24 hours
You don't really give enough information to answer the question (i.e., do you want data only from the past, only in the future, etc), but let's assume you want the data where the timestamp column ("tscolumn") is more than 4 hours old and less than 24 hours old:
select *
from table t
where t.tscolumn between current timestamp - 4 hours
and current timestamp - 24 hours
If my assumption is wrong it's pretty easy to rewrite this to meet your requirements.
Try following
select * from tableName where
date <= DATEADD(Hour, -4, CURRENT_TIME) and
date date >= DATEADD(Hour, -24, CURRENT_TIME)
select *
from table t
where timestampdiff(8,char(current timestamp - time_from_table)) between 4 and 24
here timestamp(8, - refers hours, below are the values for different arguments.
Value Description
1 Fractions of a second
2 Seconds
4 Minutes
8 Hours
16 Days
32 Weeks
64 Months
128 Quarters
256 Years