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

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.

Related

How to calculate the time difference in SQL with DATEDIFF?

I am using the DATEDIFF function to calculate the difference between my two timestamps.
payment_time = 2021-10-29 07:06:32.097332
trigger_time = 2021-10-10 14:11:13
What I have written is : date_diff('minute',payment_time,trigger_time) <= 15
I basically want the count of users who paid within 15 mins of the triggered time
thus I have also done count(s.user_id) as count
However it returns count as 1 even in the above case since the minutes are within 15 but the dates 10th October and 29th October are 19 days apart and hence it should return 0 or not count this row in my query.
How do I compare the dates in my both columns and then count users who have paid within 15 mins?
This also works to calculate minutes between to timestamps (it first finds the interval (subtraction), and then converts that to seconds (extracting EPOCH), and divides by 60:
extract(epoch from (payment_time-trigger_time))/60
In PostgreSQL, I prefer to subtract the two timestamps from each other, and extract the epoch from the resulting interval:
Like here:
WITH
indata(payment_time,trigger_time) AS (
SELECT TIMESTAMP '2021-10-29 07:06:32.097332',TIMESTAMP '2021-10-10 14:11:13'
UNION ALL SELECT TIMESTAMP '2021-10-29 00:00:14' ,TIMESTAMP '2021-10-29 00:00:00'
)
SELECT
EXTRACT(EPOCH FROM payment_time-trigger_time) AS epdiff
, (EXTRACT(EPOCH FROM payment_time-trigger_time) <= 15) AS filter_matches
FROM indata;
-- out epdiff | filter_matches
-- out ----------------+----------------
-- out 1616119.097332 | false
-- out 14.000000 | true

Compare date and time in SQL for DB2

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.

How do you filter to get data that is in between a certain time of day in IBM DB2

I am trying to add a filter condition in the DB2 database. I am new to it and come from an Oracle background. I am trying to get records with dates in between today at 4 AM and today at 5 PM only. I currently have the below query that returns zero results:
db2 => select datetimeColumn from datetimeExample WHERE datetimeColumn BETWEEN timestamp(current date) - 1 day + 4 hour AND timestamp(current date) - 1 day + 13 hour
DATETIMECOLUMN
--------------------------
0 record(s) selected.
And here is the data in the table that I believe should show but there is something wrong with condition statement, any help is appreciated
db2 => select * from datetimeExample
DATETIMECOLUMN
--------------------------
2016-06-16-09.38.53.759000
1988-12-25-17.12.30.000000
2016-12-25-17.10.30.000000
2016-06-16-04.10.30.000000
2016-06-16-05.10.30.000000
1988-12-25-15.12.30.000000
1988-12-25-14.12.30.000000
2016-06-16-12.10.30.000000
2016-06-16-07.10.30.000000
2016-06-16-08.10.30.000000
10 record(s) selected.
The query should work when you leave out the - 1 day. The reason is that timestamp(current date) returns the timestamp for today at zero hours. Then you add 4 hours and are at the required start time. Similar maths for the end time (and 5 pm should be + 17 hours).
select datetimeColumn from datetimeExample
WHERE datetimeColumn
BETWEEN timestamp(current date) + 4 hours AND timestamp(current date) + 17 hours

Dynamic Timestamp DB2 SQL

Using DB2 SQL
I would like to query for records since 2:00 yesterday. I want a dynamic expression that frees me from having to manually enter the current date prior to running the query. The created_datetime attribute is of timestamp dataype.
For example:
select record_key, other_stuff
from table
where created_datetime > "2 o'clock PM yesterday"
Is this kind of dynamic timestamp comparison even possible? Eventually, I'd like to be able to do a window of time, which gets complicated!
select count(1)
from table
where created_datetime between "2 o'clock PM yesterday" and "2 o'clock PM today"
I am familiar with current date, but I am trying to conceptualize how I would leverage that. The following gets me close, but it includes everything 24 hours prior to whenever the query is run.
select count(1)
from table
where created_datetime between (currentdate - 1 day) and (currentdate # 2 o'clock PM)
I know this is some pretty basic territory, and I feel guilty posting this question, but my research has not turned up anything for me so far. I appreciate every ounce of time spent on my behalf.
Try these
select record_key, other_stuff
from table
where created_datetime > CURRENT DATE - 10 HOURS
select count(1)
from table
where created_datetime between (CURRENT DATE - 10 HOURS) and (CURRENT DATE + 14 HOURS)
select count(1)
from table
where created_datetime between (CURRENT DATE - 1 DAYS) and (CURRENT DATE + 14 HOURS)
From the IBM Dev Works Library : DB2 Basics: Fun with Dates and Times
There are heaps of samples there.
E.g.
You can also perform date and time calculations using, for lack of a
better term, English:
current date + 1 YEAR
current date + 3 YEARS + 2 MONTHS + 15 DAYS
current time + 5 HOURS - 3 MINUTES + 10 SECONDS
Try this with this Timestamp option in you where clause.
Below sample to query for between last 24 hours.
select
timestamp(CURRENT date - 1 days,(CURRENT time - 24 hours)),
timestamp(CURRENT date,CURRENT time )
FROM
sysibm.sysdummy1;

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.