Compare date and time in SQL for DB2 - sql

I need to compare date and time of 2 fields and see if its greater than 24 hours however there is another field whose value is less than the 24 hours of the compared date. For example ,
create date - 18/7/2019 11:15 AM
target date - 19/07/2019 11:16 AM
There is a gap of 24 hours here
Actual date - 19/07/2019 10:45 AM
Actual date is less than above said gap of 24 hours . Hence the query should return such records that has actual date less than the create date and target date gap of 24 hours. Here all the fields are of DATETIME data type in DB2 database.

It's not clear what you really try to do.
Actual date is less than above said gap of 24 hours
How can a date may be comparable to a gap (or time duration)?
Should we understand it as:
Gap between actual and created is less than gap between target and created?
If so, then try the following:
select *
from
(
select create, target, actual
, timestampdiff(8, char(target - create)) gap_target
, timestampdiff(8, char(actual - create)) gap_actual
from table(values
(timestamp('2019-07-18-11.15.00'), timestamp('2019-07-19-11.16.00'), timestamp('2019-07-19-10.45.00'))
) t (create, target, actual)
)
where
gap_target >= 24 and gap_actual < 24
-- or some another expression like:
-- gap_actual < gap_target
;
CREATE TARGET ACTUAL GAP_TARGET GAP_ACTUAL
------------------- ------------------- ------------------- ---------- ----------
2019-07-18 11:15:00 2019-07-19 11:16:00 2019-07-19 10:45:00 24 23
Is this what you want?
If not, then provide a few number of input records and the exact result desired.

Related

Calculate time difference in PSQL with HH:MM splitted in several columns

I've a PSQL table like this:
Order
Start_Hour
Start_Minute
Finish_Hour
Finish_Minute
10
10
15
12
15
10
12
15
14
15
10
16
00
17
00
And I need to calculate by a query the total time expressed in hours that I spent to finish the order. In this scenario I expect to have a total of 5 hours:
12:15 - 10:15 = 2 hours
14:15 - 12:15 = 2 hours
17:00 - 16:00 = 1 hours
The query result must be 5.
The idea was concatenate start hour/minute and finish hour/minute, convert them to hour, make the difference, calculating the total.
SELECT (Start_Hour & ":" & Start_Minute) as start, (Finish_Hour & ":" & Finish_Minute) as finish
FROM OrderDetails
But when I try to convert them to HH:MM using cast or convert but I got errors.
Any advice?
Thank you
This query uses make_time as Adrian Klaver suggests.
select
"Order",
sum(extract(hour from
make_time("Finish_Hour", "Finish_Minute", 0) -
make_time("Start_Hour", "Start_Minute", 0))
) as duration
from the_table
group by "Order";
However I have remarks about your data design. Hour and minute are not enough for storing time because (apart from missing precision and other reasons) the end time might be over midnight. You have a specific data type for this - timestamp. I would suggest something like
create table the_table
(
order_nr integer,
start_time timestamp,
finish_time timestamp
);
Also note that using mixed case names in Postgresql requires double-quoting.
Use make_time:
select make_time(12, 15, 0) - make_time(10, 15, 0);
?column?
----------
02:00:00
Where in your case you would substitute in Start_Hour, Start_Minute, Finish_Hour, Finish_Minute.

Find the minute difference between 2 date time

I need to get the difference between 2 date time in minutes(Time difference in minutes). And the last difference will be calculated based on 6 PM of every date.
Sample data: need result of last column
User_Name Date Time difference in minutes
User 1 1/1/06 12:00 PM 30
user 2 1/1/06 12:30 PM 315
user 3 1/1/06 5:45 PM 15
Here the date will be always in same date and the last user date difference calculated based on default value 6PM. Assuming the dates of any user will not cross 6PM time.
Please suggest how to write the query for the same.
You could use the lead window function.
I assume your table is called mytable and the date column is mydate (it is a bad idea to call a column Date as it is a reserved word).
select user_name,
round((lead(mydate, 1, trunc(mydate)+18/24)
over (partition by trunc(mydate) order by mydate)
- mydate) *24*60) as difference
from mytable
I found the solution.. if its not correct let me know
SELECT User_name,created_date,
trunc(to_number((cast(nvl(lead (created_date,1) OVER (ORDER BY created_date),TRUNC(SYSDATE) + (19/24)) as date) - cast(created_date as date)))*24*60) as difference
FROM users;

Check if a time period is included in another time period

In my db i have many record, with start date and length of that time of period.
For example
id start_date lenght
1 2013-01-01 00:00:00 20
2 2013-02-30 00:00:00 10
3 2013-01-20 00:00:00 3
So i can easily get the end date.
Now if the user gave me any period of time, how can I control if that period is included in one of the time period that I have in the db?
Thank you.
You can get the list using a where clause and the date functions:
select *
from t
where XXX between start_date and date_add(start_date, interval length day);
EDIT:
The above is for one date. If the user gives two date, XXX and YYY, then this is what you want for any overlap:
select *
from t
where XXX <= date_add(start_date, interval length day) and
YYY >= start_date;
That is, the period the user gives you starts before the end of the interval and the period ends after the start of the interval.

How to find first free time in reservations table in PostgreSql

Reservation table contains reservations start dates, start hours and durations.
Start hour is by half hour increments in working hours 8:00 .. 18:00 in work days.
Duration is also by half hour increments in day.
CREATE TABLE reservation (
startdate date not null, -- start date
starthour numeric(4,1) not null , -- start hour 8 8.5 9 9.5 .. 16.5 17 17.5
duration Numeric(3,1) not null, -- duration by hours 0.5 1 1.5 .. 9 9.5 10
primary key (startdate, starthour)
);
table structure can changed if required.
How to find first free half hour in table which is not reserved ?
E.q if table contains
startdate starthour duration
14 9 1 -- ends at 9:59
14 10 1.5 -- ends at 11:29, e.q there is 30 minute gap before next
14 12 2
14 16 2.5
result should be:
starthour duration
11.5 0.5
Probably PostgreSql 9.2 window function should used to find
first row whose starthour is greater than previous row starthour + duration
How to write select statement which returns this information ?
Postgres 9.2 has range type and I would recommend to use them.
create table reservation (reservation tsrange);
insert into reservation values
('[2012-11-14 09:00:00,2012-11-14 10:00:00)'),
('[2012-11-14 10:00:00,2012-11-14 11:30:00)'),
('[2012-11-14 12:00:00,2012-11-14 14:00:00)'),
('[2012-11-14 16:00:00,2012-11-14 18:30:00)');
ALTER TABLE reservation ADD EXCLUDE USING gist (reservation WITH &&);
"EXCLUDE USING gist" creates index which disallows to inset overlapping entries. You can use the following query to find gaps (variant of vyegorov's query):
with gaps as (
select
upper(reservation) as start,
lead(lower(reservation),1,upper(reservation)) over (ORDER BY reservation) - upper(reservation) as gap
from (
select *
from reservation
union all values
('[2012-11-14 00:00:00, 2012-11-14 08:00:00)'::tsrange),
('[2012-11-14 18:00:00, 2012-11-15 00:00:00)'::tsrange)
) as x
)
select * from gaps where gap > '0'::interval;
'union all values' masks out non working times hence you can make reservation between 8am and 18pm only.
Here is the result:
start | gap
---------------------+----------
2012-11-14 08:00:00 | 01:00:00
2012-11-14 11:30:00 | 00:30:00
2012-11-14 14:00:00 | 02:00:00
Documentation links:
- http://www.postgresql.org/docs/9.2/static/rangetypes.html "Range Types"
- https://wiki.postgresql.org/images/7/73/Range-types-pgopen-2012.pdf
Maybe not the best query, but it does what you want:
WITH
times AS (
SELECT startdate sdate,
startdate + (floor(starthour)||'h '||
((starthour-floor(starthour))*60)||'min')::interval shour,
startdate + (floor(starthour)||'h '||
((starthour-floor(starthour))*60)||'min')::interval
+ (floor(duration)||'h '||
((duration-floor(duration))*60)||'min')::interval ehour
FROM reservation),
gaps AS (
SELECT sdate,shour,ehour,lead(shour,1,ehour)
OVER (PARTITION BY sdate ORDER BY shour) - ehour as gap
FROM times)
SELECT * FROM gaps WHERE gap > '0'::interval;
Some notes:
It will be better not to separate time and data of the event. If you have to, then use standard types;
If it is not possible to go with standard types, create function to convert numeric hours into the time format.

Storing the time in Oracle

Let me quickly explain. I have an application to manage visitors.
We have a start date of the visit (a visit can only be for one day).
We can add a time for example the time of a tour, the time the group will be having lunch, the time the group will be having a presentation etc. All times will take the start date of the visit and then append the time accordingly.
Simple code:
// set tour time in tour table
$y->setTourTime($visit->getVisitDate("Y-m-d") . $tourTime);
// can have many presentation
$p->setPresentationTime($visit->getVisitDate("Y-m-d") . $tourTime);
So I have many time stamps across multiple tables. The problem I have however, if I decide to change the start date in the visit entity, then I'll have to change all of the timestamps across the related tables (tour guide, lectures etc.) This is ugly
What I would prefer is to have a visit date, such as 2010-10-10 in the visit table. And then in the lecture tables, guide tables etc. to just store the time and not the date. How would you do that? just store it as a string, i.e. "10:00"?
Thanks for any input. :-)
You have several possibilities. I prefer to have datatypes that are best suited for the job. Calculating with times is best done using DATE, TIMESTAMP and INTERVAL, so I'd use something like this:
SQL> create table visits
2 ( startdate date
3 , starttime_tour interval day(0) to second(0)
4 , starttime_lunch interval day(0) to second(0)
5 , starttime_presentation interval day(0) to second(0)
6 , constraint visits_ck1 check (startdate = trunc(startdate))
7 )
8 /
Table created.
You can read more about the INTERVAL DAY TO SECOND datatype here: http://download.oracle.com/docs/cd/E11882_01/server.112/e17118/sql_elements001.htm#SQLRF00207
And here is an example how you insert and select from it:
SQL> insert into visits
2 values
3 ( trunc(sysdate)
4 , to_dsinterval('0 09:00:00')
5 , to_dsinterval('0 12:00:00')
6 , to_dsinterval('0 13:00:00')
7 )
8 /
1 row created.
SQL> select startdate
2 , starttime_tour
3 , starttime_lunch
4 , starttime_presentation
5 from visits
6 /
STARTDATE STARTTIME_TOUR STARTTIME_LUNCH STARTTIME_PRESENTATI
------------------- -------------------- -------------------- --------------------
17-12-2010 00:00:00 +0 09:00:00 +0 12:00:00 +0 13:00:00
1 row selected.
And calculating is very easy now:
SQL> select startdate
2 , startdate + starttime_tour as tour
3 , startdate + starttime_lunch as lunch
4 , startdate + starttime_presentation as presentation
5 from visits
6 /
STARTDATE TOUR LUNCH PRESENTATION
------------------- ------------------- ------------------- -------------------
17-12-2010 00:00:00 17-12-2010 09:00:00 17-12-2010 12:00:00 17-12-2010 13:00:00
1 row selected.
Hope this helps.
Regards,
Rob.
If you want to manipulate as a time it might be better to just create two date fields. One holds the visit date, the other holds the tour time with a generic date attached (1/1/2000 or something consistent & non-specific) - you ignore the date portion of the tour time but can still do time-based comparisons if necessary without converting a string to a time value.