I was wondering if someone could help me with this SQL statement?
Say, I have an SQL Server 2008 table like this:
id -- INT PRIMARY KEY
dtIn -- DATETIME2
dtOut -- DATETIME2
type -- INT
id dtIn dtOut type
1 05:00 10:00 1
2 08:00 16:00 2
3 02:00 08:00 1
4 07:30 11:00 1
5 07:00 12:00 2
I need to remove any time overlaps in the table above. This can be illustrated with this diagram:

So I came up with this SQL:
UPDATE [table] AS t
SET dtOut = (SELECT MIN(dtIn) FROM [table] WHERE type = t.type AND t.dtIn >= dtIn AND t.dtIn < dtOut)
WHERE type = t.type AND t.dtIn >= dtIn AND t.dtIn < dtOut
But it doesn’t work. Any idea what am I doing wrong here?
****EDIT****
OK, it took me awhile to get to this. Seems to be a working SQL for what I need it for:
--BEGIN TRANSACTION;
--delete identical dtIn
DELETE dT1
FROM tbl dT1
WHERE EXISTS
(
SELECT *
FROM tbl dT2
WHERE dT1.Type = dT2.Type
AND dT1.dtIn = dT2.dtIn
AND (
dT1.dtOut < dT2.dtOut
OR (dT1.dtOut = dT2.dtOut AND dT1.id < dT2.id)
)
);
--adjust dtOuts to the max dates for overlapping section
UPDATE tbl
SET dtOut = COALESCE((
SELECT MAX(dtOut)
FROM tbl as t1
WHERE t1.type = tbl.type
AND t1.dtIn < tbl.dtOut
AND t1.dtOut > tbl.dtIn
), dtOut);
-- Do the actual updates of dtOut
UPDATE tbl
SET dtOut = COALESCE((
SELECT MIN(dtIn)
FROM tbl as t2
WHERE t2.type = tbl.type AND
t2.id <> tbl.id AND
t2.dtIn >= tbl.dtIn AND t2.dtIn < tbl.dtOut
), dtOut);
--COMMIT TRANSACTION;
Just off the top of my head I believe that one of Joe Celko’s books had this as an example problem. You might find the excerpt available on Google.
This might be closer. I think you weren’t really doing the subquery the right way.
EDIT
I overlooked the id column at the top of the page so obviously that’s a better check than making sure the endpoints don’t match up. The solution is probably easier if you can assume that no two rows of identical type have the dtIn.
Btw, there’s no reason to use a CROSS APPLY when a subquery will do exactly the same job.
EDIT 2
I did some quick testing and I think my query handles the scenario in your diagram. There’s one case where it might not do what you want.
For a given type, think about the final two segments S1 and S2 in order of start time. S2 starts after S1 but also imagine it ends before S1 does. S2 is fully contained in the interval of S1, so it’s either ignorable or the information for the two segments needs to be split into a third segment and that’s where the problem gets trickier.
So this solution just assumes they can be ignored.
EDIT 3 based on the comment about combining updates
SQLFiddle posted by OP
Either one of the two updates below should replace the two updates above.