Reputation: 3
I have a table in SQL server:
name varchar(10)
start_time timestamp
end_time timestamp
has data in table like:
John, '2014-05-26 00-00-01', null
John, '2014-05-25 15-00-01', null
Tom, '2014-05-25 16-00-01', null
John, '2014-05-25 09-00-01', null
Tom, '2014-05-25 03-00-01', null
..
I want to have a SQL to update end_time with next start_time from same person, after update, the result like:
John, '2014-05-26 00-00-01', null
John, '2014-05-25 15-00-01', '2014-05-26 00-00-01'
Tom, '2014-05-25 16-00-01', null
John, '2014-05-25 09-00-01', '2014-05-25 15-00-01'
Tom, '2014-05-25 03-00-01', '2014-05-25 16-00-01'
Is there any easy way in SQL? I think need inner join?
(some idea like:
update mytable t1
set t1.end_time = min(t2.start_time)
inner join mytable t2 on t1.name = t2.name where t1.start_time < t2.start_time and t1.end_time = null;
but does not work)
Upvotes: 0
Views: 645
Reputation: 6073
This may help you.
DECLARE @TABLE TABLE
(
NAME VARCHAR(10),
START_TIME DATETIME,
END_TIME DATETIME
)
INSERT INTO @TABLE (NAME,START_TIME,END_TIME) VALUES
('JOHN', '2014-05-26 00:00:01',NULL),
('JOHN', '2014-05-25 15:00:01',NULL),
('TOM', '2014-05-25 16:00:01',NULL),
('JOHN', '2014-05-25 09:00:01',NULL),
('TOM', '2014-05-25 03:00:01',NULL)
UPDATE A
SET A.END_TIME = LU.START_TIME
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY START_TIME DESC) [ROW]
FROM @TABLE
) A
LEFT JOIN (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY START_TIME DESC) [ROW]
FROM @TABLE
) LU
ON A.NAME = LU.NAME
AND A.ROW = LU.ROW + 1
SELECT * FROM @TABLE
Upvotes: 1
Reputation: 1269743
The following query gets the next start time, using a correlated subquery (you can also use cross apply
or the lead()
function, if available).
select t.*,
(select top 1 t2.start_time
from t2.name = t.name and t2.start_time > t.start_time
order by t2.start_time asc
) as next_start_time
from mytable t;
One very nice feature of SQL Server is the updatable CTE. So you can use this in an update statement:
with toupdate as (
select t.*,
(select top 1 t2.start_time
from t2.name = t.name and t2.start_time > t.start_time
order by t2.start_time asc
) as next_start_time
from mytable t
)
update toupdate
set end_time = next_start_time;
Upvotes: 0