Reputation: 3276
I have a table which stores bunch of records like this:
Time UserName
10:30 John
10:40 John
10:45 John
11:05 Sara
11:07 John
11:08 Ned
11:09 Ned
But I need to somehow skip records with same UserName
as in previous record, so only record with first UserName
will be in result, like so:
Time UserName
10:30 John
11:05 Sara
11:07 John
11:08 Ned
It's very obvious how to do this in regular programming languages, but I can't understand how to do this in SQL.
Upvotes: 0
Views: 1026
Reputation:
The query below uses the "gaps and islands" method (a.k.a. "tabibitosan" method) to group together CONSECUTIVE rows with the same username
.
This only works if all times are distinct (otherwise the output from row_number()
is not deterministic); but if the times are not all distinct, there is no "natural" sense of "consecutive" names anyway (in that case the problem itself needs to be clarified).
select min(time) as time, username from
(select time, username,
row_number() over (order by time) -
row_number() over (partition by username order by time) as gp
from inputs
)
group by username, gp
order by time;
inputs
is the base table.
Upvotes: 3
Reputation: 1270993
I think the simplest method is to use lag()
:
select t.time, t.name
from (select t.*,
lag(name) over (order by time) as prev_name
from t
) t
where prev_name is null or prev_name <> name;
I would imagine that this also has the best performance.
Upvotes: 3
Reputation: 1605
something like this
select t1.Time ,t1.UserName from
( select Time ,UserName
,ROW_NUMBER() OVER ( ORDER BY Time,UserName ) R from table) t1
join ( select Time ,UserName
,ROW_NUMBER() OVER ( ORDER BY Time,UserName ) R from table) t2
on t1.R = t2.R - 1
where t1.UserName <> t2.UserName;
Upvotes: 1
Reputation: 537
This will work in all DBs without even analytic functions:
select * from temp t1
where not exists ( select 1 from temp t2
where t2.UserName = t1.UserName
and t2.Time < t1.Time
and not exists (select 1 from temp t3
where t3.UserName != t2.UserName
and t3.Time > t2.Time
and t3.Time < t1.Time
)
) ;
The inner query ensures there is no other same name that appears before another name in between.
Upvotes: 1