Need help in finding nearest shift time in SQL - sql

I have following table for shifts.
AutoId StartTime EndTime
1 08:00:00 AM 04:00:00 PM
2 04:00:00 PM 12:00:00 AM
3 12:00:00 AM 08:00:00 AM
Now I want to assign Shifts to employees automatically..
For example, if someone comes 7:32 AM then his shift should be the first shift, that is, from 08:00:00 AM to 4:00:00 PM. If someone comes 11:45 PM then it should be automatically set as the third shift.
I also want that if an employee come in during the first hour of the shift then it should also work.
How do I find the nearest shift by giving employee InTime?

Something like:
SELECT AutoId, StartTime, EndTime
FROM Shifts
WHERE StartTime = (SELECT MIN(StartTime) FROM Shifts WHERE DATEADD(hh, 1, StartTime) > inTime)
EDIT: Added grace period

Related

Exclude overlapped time period

I wish to write a query for below problem.
The problem is, I want to eliminate all overlapping periods, so that I get the total amount of time which is not taken in any other row.
Example:
NAME
Start Date Time
End Date time
Load shed
21-03-2020 12:30
21-03-2020 13:30
Shutdown
21-03-2020 13:00
21-03-2020 14:00
breakdown
21-03-2020 13:10
21-03-2020 14:10
Load shed
24-03-2020 12:30
24-03-2020 13:30
Shutdown
24-03-2020 11:00
24-03-2020 19:00
breakdown
24-03-2020 13:10
24-03-2020 14:10
Now what we have to do is:
Return time period between start date time and end date time but exclude overlapped time.
Expected result will be:
NAME
Start Date Time
End Date time
Time_interval
Load shed
21-03-2020 12:30
21-03-2020 13:30
01:00
Shutdown
21-03-2020 13:30
21-03-2020 14:00
00:30
breakdown
21-03-2020 14:00
21-03-2020 14:10
00:10
Shutdown
24-03-2020 11:00
24-03-2020 19:00
08:00
Now we can see in result,
First row: As it is because it has the lowest start date time in all
overlapped rows.
Second row: 30 minutes already used in first row so
we exclude 30 minutes here and write left time interval.
Third row:
we exclude till time 14:00 because its already used in row 2 so now time
interval has 10 minutes only.
Fourth row: We exclude all rows from
given table because they all overlapped and they are within start date
time 24-3-2020 11:00 and 24:03:2020 19:00 .
Hope you understand the problem.
Thanks in advance.
You can calculate the previous enddt before each row. Then, if that is larger than the start date, use that for the row. And, if the duration of the row is negative, then filter out the row.
The code looks like:
select name, imputed_startdt, enddt, prev_enddt,
convert(time, dateadd(minute, datediff(minute, imputed_startdt, enddt), 0)) as duration
from (select t.*, max(enddt) over (order by startdt rows between unbounded preceding and 1 preceding) as prev_enddt
from t
) t cross apply
(values (case when prev_enddt > startdt then prev_enddt else startdt end)
) v(imputed_startdt)
where prev_enddt < enddt or prev_enddt is null;
Here is a db<>fiddle.

Get the total sum hours in a column SQL SERVER

Sql Fiddle Example
I have this result table
Id Hours
----- -----
1 09:00
2 09:30
3 10:00
4 10:30
5 11:00
6 11:30
7 12:00
8 12:30
9 13:00
10 13:30
11 14:00
12 14:30
13 15:00
14 15:30
15 16:00
16 16:30
17 17:00
18 17:30
19 18:00
I need to get the total sum hours, for example from 09:00 to 18:00 there is a total of :
9
hours, I need to get this sum of hours
Your table schema hour is varchar, you need to cast as time, then do the calculation
SELECT datediff(hour,min(cast(hour as time)),max(cast(hour as time)))
FROM Timetable
sqlfiddle
NOTE
I would suggest your hour column as datetime or time instead of varchar. because hour column intention is time.
EDIT
If your time is 9:00 to 17:30, you can try to use datediff minute to get the total diff minutes then divide 60 to get hours.
SELECT datediff(minute,min(cast(hour as time)),max(cast(hour as time))) / CAST(60 as float)
FROM Timetable
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=6e005cdfad4eca3ff7c4c92ef14cc9c7
use datediff function
select datediff(hour,min(h),max(h)) from
(
select CAST(hour AS TIME) as h from Timetable
) as t
strongly disagreed to put time value in varchar ,so it is better change your data type from varchar to time
declare #a time = '13:00',#b time = '17:30' --- Here you can give time, what you need.
select distinct convert(varchar(20)
, datediff(MINUTE,#a,#b) / 60)
+ ':' +
convert(varchar(20), datediff(MINUTE,#a,#b) % 60)
from #Timetable
where hour in (#a,#b)
For your SQL Fiddle Sample Data.
Obviously, you need to use datediff(). However, you should be doing the datediff() in minutes or seconds and then converting to hours:
SELECT datediff(minute, min(cast(hour as time)), max(cast(hour as time))) / 60.0
FROM Timetable;
This will handle the case where the number of hours is not an exact number of hours.

oracle sql Time to Resolve Calculation

I have a question and hopefully someone can help, because i have been stuck on this for a long time.
I have a column with remaining minutes for a task to expire and i want to calculate when this task will expire within the business days timeframe starting from the current sysdate day lets say weekdays from 09:00 to 17:00.
| Task No | Minutes Remaining | Expiration date |
| Task1 | 1800 | 27-10-16 9:45 AM |
| Task2 | 3400 | 28-10-16 9:45 AM |
| Task3 | 400 | 29-10-16 9:45 AM |
| Task4 | 180 | 30-10-16 9:45 AM |
| Task5 | 8400 | 31-10-16 9:45 AM |
| Task6 | 5000 | 1-11-16 9:45 AM |
OK, this was a fun problem. To summarize: You are given a date (which in Oracle always includes the time-of-day) from which you start measurement, and an initial duration in minutes. You need to find the expiration date (meaning date and time-of-day as always), which is calculated by adding the duration in minutes to the "clock-starting" date, but the clock should only run during business hours - 9 to 17, Monday to Friday only (not on weekends).
I assume if the "minutes remaining" is 0, then the expiration should be the same as the "clock-starting" date if it falls within work hours, or 9 am on the next work day otherwise.
To understand the solution, let's break it down in two parts. First let's consider a very special case: the "clock starts" on a Monday at 9 am. Then break down minutes remaining into an integer multiple of 2400 (5*8*60 = 2400 minutes in a full work week), plus an integer multiple of 480 from what's left (480 minutes to a work day), plus whatever is left, if anything. Then: the expiration date is the "clock-starting" date, plus however many weeks, plus however many whole days (between 0 and 4), plus the remaining minutes. One exceptional case here: if the "minutes remaining" is an exact multiple of 480 minutes, then expiration is at 5 pm on a certain work day, and not 9 am on the next work day. This requires special handling in the formula. All this is done in the outer query (at the bottom of the solution below).
Then we need to reduce the general case to this special case. This is done in the subquery prep in the solution. I simply increase the "minutes remaining" by the work minutes elapsed from 9 am on Monday at the beginning of the week. This is a relatively simple computation. Note that if the "clock starting" date is after 5 pm on a Friday (or any time on Saturday or Sunday), I must add exactly 2400 minutes, a full work week.
In the solution, I show a variety of "clock starting" dates, dt, and minutes remaining, rm. I tested a variety of situations, and I think the solution is correct, but you may want to test on more data (other situations I didn't include in the tests).
with
inputs ( task, min_rem, dt ) as (
select 'Task1', 1800, to_date('27-10-16 9:45 AM', 'dd-mm-yy hh:mi AM') from dual union all
select 'Task2', 3400, to_date('28-10-16 9:45 AM', 'dd-mm-yy hh:mi AM') from dual union all
select 'Task3', 400, to_date('29-10-16 3:45 AM', 'dd-mm-yy hh:mi AM') from dual union all
select 'Task4', 180, to_date('30-10-16 9:45 AM', 'dd-mm-yy hh:mi AM') from dual union all
select 'Task5', 8400, to_date('31-10-16 9:45 PM', 'dd-mm-yy hh:mi AM') from dual union all
select 'Task6', 5000, to_date('01-11-16 5:00 PM', 'dd-mm-yy hh:mi AM') from dual union all
select 'Task7', 0, to_date('01-12-16 5:00 PM', 'dd-mm-yy hh:mi PM') from dual
),
prep ( task, min_rem, dt, adj_min, adj_dt ) as (
select task, min_rem, dt,
min_rem + case when dt > trunc(dt, 'iw') + 5 + 17/24 then 2400
else (trunc(dt) - trunc(dt, 'iw')) * 480 +
least(480, greatest(0, 1440 * (dt - trunc(dt) - 9/24)))
end,
trunc(dt, 'iw') + 9/24
from inputs
)
select task, min_rem, dt,
adj_dt + 7 * trunc(adj_min / 2400)
+ case when adj_min/480 = trunc(adj_min/480)
then mod(adj_min, 2400) / 480 - 1 + 8/24
else trunc(mod(adj_min, 2400) / 480) + mod(adj_min, 480) / 1440
end as expiration
from prep
order by task
;
Output:
TASK MIN_REM DT EXPIRATION
----- ---------- ----------------- -----------------
Task1 1800 27-10-16 09:45 AM 01-11-16 03:45 PM
Task2 3400 28-10-16 09:45 AM 08-11-16 10:25 AM
Task3 400 29-10-16 03:45 AM 31-10-16 03:40 PM
Task4 180 30-10-16 09:45 AM 31-10-16 12:00 PM
Task5 8400 31-10-16 09:45 PM 24-11-16 01:00 PM
Task6 5000 01-11-16 05:00 PM 16-11-16 12:20 PM
Task7 0 01-12-16 05:00 PM 01-12-16 05:00 PM
7 rows selected

Finding in between which two dates in a column the target date is

Got a table that I am trying to clean up and can't figure out how to find a record where one date falls between two dates in the actual columns
TargetDateTime Location TransferDateTime
01/01/2014 1:00 PM Room 1 01/01/2014 10:00 AM
01/01/2014 1:00 PM Room 2 01/01/2014 12:30 PM
01/01/2014 1:00 PM Room 3 01/01/2014 01:30 PM
01/01/2014 1:00 PM Room 4 01/01/2014 03:00 PM
TransferDateTime marks the time when a person was moved to the room
TargetDateTime marks some event that a person did.
In this example, TargetDateTime is 1:00 PM; therefore the event took place in Room 2 because 1:00 PM falls between 12:30 PM and 1:30 PM.
What would be the best way in SQL to select only that row and ignore the rest?
Thanks a bunch for any suggestions!
Based on your sample data and guessing that you have groups of the same TargetDateTime, the following should do it.
;WITH MyCTE AS
(
SELECT TargetDateTime,
Location,
TransferDateTime
ROW_NUMBER() OVER (PARTITION BY TargetDateTime ORDER BY TransferDateTime) AS rn
FROM TableName
WHERE TransferDateTime >= TargetDateTime
)
SELECT *
FROM MyCTE
WHERE rn = 1

How to count the records per half hour from a period (datetimefrom and datetimeto) field?

I have a table which looks like you can see below:
Id Date ScheduledTimeFrom ScheduledTimeTo ActualTimeFrom ActualTimeTo
1 2013-01-01 1899-12-30 07:00:00 1899-12-30 18:00:00 1899-12-30 07:23:00 1899-12-30 17:15:00
I need to calculate per half hour how many records exists, the output should be like:
Time Actual Count:
7:00 4
7:30 4
8:00 4
8:30 4
9:00 4
9:30 5
10:00 5
10:30 6
11:00 7
11:30 8
12:00 8
12:30 8
13:00 8
13:30 8
14:00 8
14:30 8
15:00 7
15:30 7
16:00 7
16:30 6
17:00 5
17:30 4
18:00 4
I already tried to make a helper table which should hold the times per halfhour. I have joined this helpertable with the table that contains the data and after that I tried to use a group by function but it was not working.
My query was like:
Create table period (timefrom datetime, timeto datetime)
insert into period
select '1899-12-30 07:00:00.000', '1899-12-30 07:30:00.000'
Union all
select '1899-12-30 07:30:00.000', '1899-12-30 08:00:00.000'
select *
from period p left join table1 t on t.ActualTimeFrom < p.timeto and t.ActualTimeTo >=p.timefrom
Grouping this give me no desired result....
Anyone an idea how to come to the result?
P.s. I am using sql server 2005.
After snooping around and testing it on my side, looks like this date function could be the answer:
DATEADD(mi,DATEDIFF(mi,0,YOUR_DATE_COLUMN)/30*30,0)