Reputation: 364
I have a table which has information on races that have taken place, it holds participants who took part, where they finished in the race and what time they finished. I would like to add a time difference column which shows how far behind each participant was behind the winner.
Race ID Finish place Time Name
1 1 00:00:10 Matt
1 2 00:00:11 Mick
1 3 00:00:17 Shaun
2 1 00:00:13 Claire
2 2 00:00:15 Helen
What I would like to See
Race ID Finish place Time Time Dif Name
1 1 00:00:10 Matt
1 2 00:00:11 00:00:01 Mick
1 3 00:00:17 00:00:07 Shaun
2 1 00:00:13 Claire
2 2 00:00:15 00:00:02 Helen
I have seen similar questions asked but I was unable to relate it to my problem.
My initial idea was to have a number of derived tables which filtered out by finish place but there could be more than 10 racers so things would start to get messy. I'm using Management Studio 2012
Upvotes: 0
Views: 73
Reputation: 196
You can use window functions. MIN([time]) OVER (PARTITION BY race_id ORDER BY finish_place)
gives first row's time value in the same race. DATEDIFF(SECOND, (MIN([time]) OVER (PARTITION BY race_id ORDER BY finish_place)), time)
gives the difference.
Upvotes: 0
Reputation: 502
Using http://www.convertcsv.com/csv-to-sql.htm to build example data:
DROP TABLE IF EXISTS mytable
CREATE TABLE mytable(
Race_ID INTEGER
,Finish_place INTEGER
,Time VARCHAR(30)
,Name VARCHAR(30)
);
INSERT INTO mytable(Race_ID,Finish_place,Time,Name) VALUES (1, 1,'00:00:10','Matt');
INSERT INTO mytable(Race_ID,Finish_place,Time,Name) VALUES (1, 2,'00:00:11','Mick');
INSERT INTO mytable(Race_ID,Finish_place,Time,Name) VALUES (1, 3,'00:00:17','Shaun');
INSERT INTO mytable(Race_ID,Finish_place,Time,Name) VALUES (2, 1,'00:00:13','Claire');
INSERT INTO mytable(Race_ID,Finish_place,Time,Name) VALUES (2, 2,'00:00:15','Helen');
A CTE with only first finshed places would be easier to understand.
WITH CTE_FIRST
AS (
SELECT
M.Race_ID
,M.Finish_place
,M.Time
,M.Name
FROM mytable M
WHERE M.Finish_place = 1
)
SELECT
M.Race_ID
,M.Finish_place
,M.Time
,CASE
WHEN m.Finish_place = 1
THEN NULL
ELSE CONVERT(VARCHAR, DATEADD(ss, DATEDIFF(SECOND, c.Time, M.Time), 0), 108)
END AS [Time Dif]
,M.Name
FROM mytable M
INNER JOIN CTE_FIRST c
ON M.Race_ID = c.Race_ID
Upvotes: 1
Reputation: 1269443
You can use min()
as a window function:
select t.*,
(case when time <> min_time then time - min_time
end) as diff
from (select t.*, min(t.time) over (partition by t.race_id) as min_time
from t
) t
I would be more inclined to express this as seconds:
(case when time <> min_time then datediff(second, min_time, time)
end) as diff
Upvotes: 2