I have a table with times of the timetable of workers belonging to the same shift
Start End Start End
----- ----- ----- -----
08:30 10:00 08:30 10:00
10:15 13:00 10:15 13:00
13:45 17:30 --> 13:45 14:30
--> 14:30 17:30
I am looking for tricky join operation that does this:
- find the row that contains 14:30
- replace it with two new rows where
-- row1 goes from Start to 14:30
-- row2 goes from 14:30 to End
- if 14:30 already is a Start time then do nothing
Somebody has an idea?
I finally came up with this:
IF OBJECT_ID('tempdb..#A') IS NOT NULL
DROP TABLE #A
IF OBJECT_ID('tempdb..#B') IS NOT NULL
DROP TABLE #B
CREATE TABLE #A ( StartTime time, EndTime time)
INSERT INTO #A (StartTime, EndTime) VALUES ('08:30', '10:00')
INSERT INTO #A (StartTime, EndTime) VALUES ('10:15', '13:00')
INSERT INTO #A (StartTime, EndTime) VALUES ('13:45', '17:30')
CREATE TABLE #B ( Change time, ord int)
INSERT INTO #B (Change, ord) VALUES ('14:30', 1)
INSERT INTO #B (Change, ord) VALUES ('14:30', 2)
select CASE WHEN ord = 2 THEN Change ELSE StartTime END as StartTime, CASE WHEN ord = 1 THEN Change ELSE EndTime END as EndTime
from #A as A
left outer join #B x on StartTime < Change and EndTime > Change
Here's a different option that should be a bit more performant...
IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL
BEGIN DROP TABLE #TestData; END;
CREATE TABLE #TestData (
beg_time TIME(0) NOT NULL,
end_time TIME(0) NOT NULL
);
INSERT #TestData(beg_time, end_time) VALUES
('08:30', '10:00'), ('10:15', '13:00'), ('13:45', '17:30'), ('18:45', '20:30');
--========================================================================
SELECT
beg_time = ISNULL(x.beg_time, td.beg_time),
end_time = ISNULL(x.end_time, td.end_time)
FROM
#TestData td
OUTER APPLY (
SELECT
t.beg_time,
t.end_time
FROM
( VALUES (td.beg_time, '14:30'), ('14:30', td.end_time) ) t (beg_time, end_time)
WHERE
td.beg_time <= '14:30'
AND td.end_time >= '14:30'
) x;
1 Like
Hi
I tried to solve it like this .. Hope it helps
Data Create Script
IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL
BEGIN DROP TABLE #TestData; END;
CREATE TABLE #TestData (
beg_time TIME(0) NOT NULL,
end_time TIME(0) NOT NULL
);
INSERT #TestData(beg_time, end_time) VALUES
('08:30', '10:00'), ('10:15', '13:00'), ('13:45', '17:30'), ('18:45', '20:30');
SQL
SELECT a.beg_time,
'14:30'
FROM (SELECT *
FROM #testdata
WHERE '14:30' BETWEEN beg_time AND end_time) a
UNION ALL
SELECT '14:30',
a.end_time
FROM (SELECT *
FROM #testdata
WHERE '14:30' BETWEEN beg_time AND end_time) a
UNION ALL
SELECT *
FROM #testdata
WHERE '14:30' NOT BETWEEN beg_time AND end_time
ORDER BY 1,
2
@Jason_A_Long: Cool, feels good! I wanted to make some brenchmark tests to compare it to my solution, but when implemented in my queries it returns less records than it should. I can't figure out why but unfortunately don't have the time now to investigate - beside the performance is pretty much the same.
Thanks anyway, apreciate your suggestion.
Martin
PS: to fulfill the last condition ("if 14:30 already is a Start time then do nothing") you need to exclude 14:30 in your where clause ->
WHERE
td.beg_time < '14:30'
AND td.end_time > '14:30'
@harishgg1: Thank you for your idea. When applying to my real monster query, things are getting a bit complicated as the table #testdata appears 3 times in your query. So I stick to my solution with one single join.
The last comment for Jason applies for your query too. If 14:30 is already a starting time, no replacement should be done.