Generating Time slots between two time for today - sql

I am editing my question little bit
I have Office Timing Table As follows.
TIME_FROM TIME_TO TIME_FROM1 TIME_TO1 TIME_FROM2 TIME_TO2
07:00 AM 14:00 PM 700 1400 06/08/2020 07:00:00 AM 06/08/2020 02:00:00 PM
16:00 PM 18:00 PM 1600 1800 06/08/2020 04:00:00 PM 06/08/2020 06:00:00 PM
Office Starting time is 7.00 AM and ending time is 6.00 PM with break time in between.This Times can vary based on selected Office.
Input parameters are
1.Travel Time in minutes to reach Office
2.Time slot duration in minutes
After taking Travel Time in minutes into consideration,I want to generate time slots of 15 minute(variable) interval between these time ranges like
7.00 AM
7.15 AM
7.30 AM
7.45 AM
8.00 AM
.
.
.
.
1.30 PM
1.45 PM
2.00 PM
Second Shift starts here
4.00 PM
4.15 PM
4.30 PM
.
.
.
.
.
5.30 PM
5.45 PM
Scenario 1 :
Travel time needed :31 minutes
Booking attempt time 6.15 AM
Office Opening Time 7.00 AM
Required result
7.00
7.15
.
.
1.45 PM( Dont include shift ending time 2.00PM)
4.00 PM
4.15 PM
.
.
5.45 PM
Scenario 2 :
Travel time needed :31 minutes
Booking attempt time 6.45 AM
Office Opening Time 7.00 AM
Required result
7.16
7.31
.
.
1.46 PM( Dont include shift ending time 2.00PM)
4.00 PM
4.15 PM
.
.
5.45 PM
Scenario 3 :
Travel time needed :31 minutes
Booking attempt time 9.45 AM
Office Opening Time 7.00 AM
Required result
10.16
10.31
.
.
1.46 PM( Dont include shift ending time 2.00PM)
4.00 PM
4.15 PM
.
.
5.45 PM
Scenario 4 :
Travel time needed :31 minutes
Booking attempt time 3 PM
Office Second shift opening Time 4.00 PM
Required result
04.00 PM
04.15 PM
.
.
5.45 PM( Dont include shift ending time 18.00PM)
Scenario 5 :
Travel time needed :31 minutes
Booking attempt time 3.45 PM
Office Second shift opening Time 4.00 PM
Required result
04.16 PM
04.31 PM
.
.
5.46 PM( Dont include shift ending time 18.00PM)

WITH
--cte to determine office hours, this is probably a table irl
office_timing (id, time_from2, time_to2) AS
(
SELECT 1, TO_DATE('09/08/2020 07:00:00 AM','DD/MM/YYYY HH:MI:SS AM'), TO_DATE('09/08/2020 02:00:00 PM','DD/MM/YYYY HH:MI:SS AM') FROM dual UNION ALL
SELECT 2, TO_DATE('09/08/2020 04:00:00 PM','DD/MM/YYYY HH:MI:SS AM'), TO_DATE('09/08/2020 06:00:00 PM','DD/MM/YYYY HH:MI:SS AM') FROM dual
)
--cte to determine when travel time to office, replace with other values to test. Make this a variable if it is an input parameter
,travel_time (travel_mins) AS
(
SELECT 31 FROM DUAL
)
--cte to determine slot length, replace with other values to test. Make this a variable if it is an input parameter
,
slot_minutes (mins) AS
(
SELECT 15 FROM DUAL
)
--cte to determine when query is run, replace with other values to test. Make this a variable if it is an input parameter
,run_date_tab (run_date) AS
(
SELECT
TO_DATE('09/08/2020 03:45:00 PM','DD/MM/YYYY HH:MI:SS AM') + travel_mins/1440
FROM travel_time
)
--cte to determine start time based on the query run date
-- if run date is in a time slot then take run date
-- if run date is outside time slot then take closest future start date
,
start_time_tab (qry_start_time) AS
(
SELECT MIN(CASE
WHEN t.time_from2 <= r.run_date AND t.time_to2 > r.run_date
THEN r.run_date
WHEN t.time_from2 > r.run_date
THEN t.time_from2
ELSE
NULL
END)
FROM run_date_tab r
CROSS JOIN office_timing t
)
,slots (slot_start_time) AS
(
SELECT
s.qry_start_time +(level - 1) / ((60/m.mins)*24)
FROM start_time_tab s CROSS JOIN slot_minutes m CONNECT BY
level < 100
)
SELECT TO_CHAR(s.slot_start_time,'DD/MM/YYYY HH:MI:SS AM')
FROM slots s
JOIN office_timing t ON t.time_from2 < s.slot_start_time AND t.time_to2 > s.slot_start_time;

Oracle provides a fairly comprehensive date (including timestamp) handling functions. Generally I live by the axiom that once a column is converted to date the only reason to convert to a string it to create a display column. There are however exceptions. One of those is (often times) when the date needs to be sliced and diced and reassembled. That is the case here to properly calculate the end time by your 'match the minute run' requirement .
You are not going to get shift break line from an SQL solution, at least I'm going to do it. You could with PL/SQL by iterating over the results. However, that is an easy task for your presentation layer. I have added a column to the final result indicating the shift. With that in mind:
with time_range (sts, ets) as
( select case when extract(hour from systimestamp) <= 07
then trunc(systimestamp) + interval '07:00' hour to minute
else trunc(systimestamp, 'mi')
end sot
, case when extract(hour from systimestamp) <= 07
then trunc(systimestamp) + interval '18:00' hour to minute
else to_timestamp(to_char(systimestamp,'yyyymmdd') || '18' || to_char(systimestamp,'mi'), 'yyyymmddhh24mi')
end eot
from dual
)
, office_hours (start_time, end_time) as
( select * from time_range
union all
select start_time+interval '15' minute, end_time
from office_hours
where start_time < end_time
)
select to_char(start_time, 'hh.mi am')
, case when 60 * extract(hour from cast( start_time as timestamp))
+ extract(minute from cast( start_time as timestamp)) <= 14*60
then 'first shift'
else 'second shift'
end shift
from office_hours;
What it does:
The work of the query is done in 2 CTEs and a select using them:
time_range: determines the start and end times necessary given the
current time (on the server).
office_hours: a recursive CTE that computes the 15 minute intervals
for start to end times.
Main: Select the start of the range and determines shift.
See fiddle for example. Note: In its current form the query will always return at least 1 row. If run after the end time, it returns a row indication that time. There are 2 additional queries with a slight modification allowing actual specification of run time instead of getting that from the system. for these I have "set the runtime" in them to 07:00 and 09:02 respectively.

Related

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.

Need hours difference in SQL query

Looking for a query which can retrieve the time difference of two times. Below is the example:
EmpID EmpOnTime EmpOffTime
1 2:45 3:00
2 1:00 4:00
3 1:35 2:55
4 2:45 3:20
Result should be:
For EmpID 1 Time diffrence: 0:15
For EmpID 2 Time diffrence: 3:00
For EmpID 3 Time diffrence: 1:20
For EmpID 4 Time diffrence: 0:35
I am using the following query which giving wrong result
Query:
select offTime, onTime, (strftime('%s',offTime) - strftime('%s',onTime)) / 60 AS diffrence
from emplyoee;
This one was trickier than initially thought. Here is the SQL you will need, however your input data will need to be formatted differently to get it to work.
select EmpId,
offTime,
onTime,
time(((strftime('%s', offTime) - strftime('%s', onTime)) / 60), 'unixepoch') as difference
from employee;
I had to store the data in the YYYY-MM-DD HH:MM:SS:
2019-07-18 03:00:00
Otherwise SQLite gets confused if you mean am or pm, and the %s cannot calculate since it returns the number of seconds since 1970-01-01.
I think you can use this:
SELECT
EmpID,
time(
julianday("2000-01-01 00:00:00") +
julianday(substr("0" || EmpOffTime || ":00", 1, 8)) -
julianday(substr("0" || EmpOnTime || ":00", 1, 8))) As diff
FROM
yourTable
[SQL Fiddle Demo]
Your times need to complete with :00 at the end and sometimes with 0 at the beginning that I handle it with substr("0" || yourTime || ":00", 1, 8), then by using julianday() you can find differences of two date, and also I add julianday("2000-01-01 00:00:00") to difference to get make a valid value of time and so on.

How to write SQL queries to calculate aggregate server up-time?

I have a requirement in SQL where I have data of a server start stop time on daily basis for one month. I need the result where it should calculate the first start time of the day, last stop time of the day, total time server was started in a day on daily basis and for servers.
Table is like below and expected output is also given.
Table:
Date & Time Reader ServerID
3/14/2016 6:36:20 AM ON 123
3/14/2016 6:58:45 AM OFF 123
3/14/2016 8:06:19 AM ON 123
3/14/2016 9:32:48 AM OFF 123
3/15/16 6:00:00 AM ON 123
3/15/16 6:01:00 AM OFF 123
3/14/2016 9:46 AM ON 124
3/14/2016 10:01 AM OFF 124
3/14/16 11:01 AM ON 124
3/14/16 12:01 PM OFF 124
Expected output
UserID FirstIN Last Out TotalInTime (min) Date
123 6:00 09:32 86 3/14
123 06:00 06:01 1 3/15
124 9:46 12:01 75 3/14
So, for each day & server, you want the minimum and maximum time and the sum of minutes "ON".
First you need rows of ON/OFF pairs (pairs on a row, not pairs of rows) whose minutes you can calculate. Then you sum the minutes and take the minimum and maximum times.
SQL Server has datepart. You can use that to compute days. To make On/Off pairs, join the table to itself along these lines:
select A.ServerID, datepart(day, A.time) as day,
A.time as ON, min(B.time) as OFF
from T as A join T as B on datepart(day, A.time) = datepart(day, B.time)
and A.Reader = 'ON' and B.Reader = 'OFF'
and A.time < B.time
group by A.ServerID, datepart(day, A.time), A.time
You can make a view like that, or a CTE, or insert the results in a temporary table. Let's call the result V.
select ServerID, day, min(ON), max(OFF)
, sum(datediff(minute, OFF, ON)) as minutes
from V
group by ServerID, day
(You can also nest the first query inside the second one.)
The trick is knowing how to find the "next" time for any pair (a question I've answered often), and how to use the server's date functions.

convert the timestamp from gmt to cst in teradata with day light savings

I want to display the timestamp(GMT) of my table as CST with daylight savings .
From march 2nd sunday 2:00AM to November 1st sunday 2:00AM = timestamp(GMT) - 5 hours
other days of the year = timestamp(GMT) - 6 hours
It appears to be working. Now having another problem. Teradata table is having CST timestamp. Another table (different source, but loaded to teradata staging tables) has GMT. Both timestamp looks alike. But when i minus both , it doesnot give me NULL value. Timestamp looks like 12/20/2012 08:30:00.000000
Assuming the datatype is a TIMESTAMP without a TIME ZONE you might simply specify the time zone you want (in TD13.10+). 'America Central' is a pre-defined time zone with daylight savings:
CREATE VOLATILE TABLE vt ( ts TIMESTAMP(0)) ON COMMIT PRESERVE ROWS;
INSERT INTO vt (TIMESTAMP'2013-03-10 07:59:00');
INSERT INTO vt (TIMESTAMP'2013-03-10 08:01:00');
INSERT INTO vt (TIMESTAMP'2013-11-03 06:59:00');
INSERT INTO vt (TIMESTAMP'2013-11-03 07:01:00');
SEL ts, ts AT 'America Central' AS CST
FROM vt
ORDER BY 1;
*** Query completed. 4 rows found. 2 columns returned.
*** Total elapsed time was 1 second.
ts CST
------------------- -------------------------
2013-03-10 07:59:00 2013-03-10 01:59:00-06:00
2013-03-10 08:01:00 2013-03-10 03:01:00-05:00
2013-11-03 06:59:00 2013-11-03 01:59:00-05:00
2013-11-03 07:01:00 2013-11-03 01:01:00-06:00

absolutely NO functions surrounding a tstamp in a SQL? Hourly historical data query

I need to obtain for some specific hours data for a specific week day back to 10 weeks. The DB I work on is Oracle. I came up with the following condtions with the time stamp field:
TO_CHAR(hy.tstamp,'HH24')='10'
AND hy.tstamp > sysdate - 70
AND mod(extract ( day from sysdate-1) - extract ( day from hy.tstamp), 7) =0
Someone told me "absolutely NO functions surrounding a tstamp" (for performance reasons?). How would you to specify the conditions without operations on the time stamp field?
This sounds like the person complaining about performance has never heard of function based indexes.
Create index char_hy_stamp on my_table(to_char(hy.tstamp,'HH24'));
This should avoid the full table scan that is undoubtedly part of your explain plan. As soon as you get your sqlfiddle functioning we can go from there.
You can filter out the time slices without functions or function indexes if you join to a table of acceptable ranges. You can create one on the fly like this (note that you need the functions to create the table, but you won't need them afterward):
SELECT
TRUNC(SYSDATE + 6) - (7 * LEVEL) + INTERVAL '10' HOUR AS StartAt,
TRUNC(SYSDATE + 6) - (7 * LEVEL) + INTERVAL '11' HOUR AS EndAt
FROM DUAL
CONNECT BY LEVEL <= 10
With today's date being 5/8/2013, this will give you the following:
STARTAT ENDAT
------------------- -------------------
05/07/2013 10:00:00 05/07/2013 11:00:00
04/30/2013 10:00:00 04/30/2013 11:00:00
04/23/2013 10:00:00 04/23/2013 11:00:00
04/16/2013 10:00:00 04/16/2013 11:00:00
04/09/2013 10:00:00 04/09/2013 11:00:00
04/02/2013 10:00:00 04/02/2013 11:00:00
03/26/2013 10:00:00 03/26/2013 11:00:00
03/19/2013 10:00:00 03/19/2013 11:00:00
03/12/2013 10:00:00 03/12/2013 11:00:00
03/05/2013 10:00:00 03/05/2013 11:00:00
Now just join it to your query to get the time slices you want, and note that you don't need functions:
WITH TimeRanges AS (
SELECT
TRUNC(SYSDATE + 6) - (7 * LEVEL) + INTERVAL '10' HOUR AS StartAt,
TRUNC(SYSDATE + 6) - (7 * LEVEL) + INTERVAL '11' HOUR AS EndAt
FROM DUAL
CONNECT BY LEVEL <= 10
)
SELECT
... whatever ...
FROM your_table hy
INNER JOIN TimeRanges ON
hy.tstamp >= TimeRanges.StartAt AND
hy.tstamp < TimeRanges.EndAt
If your DB person understands that filtering on timestamp functions kills performance (unless, as Woot4Moo points out, they implement function indexes), they'll understand that the functions used to create the table of timeslices won't impact the larger query.