Reputation: 449
I have a table
loctype order
ACUTE 1
ACUTE 2
COM 3
COM 4
ACUTE 5
COM 6
I want a query that will apply rankings to groups in order, so my desired outcome is:
loctype order group_order
ACUTE 1 1
ACUTE 2 1
COM 3 2
COM 4 2
ACUTE 5 3
COM 6 4
Is there a way to do this as a SQL query without resorting to cursors?
Upvotes: 0
Views: 1054
Reputation: 449
I tried the given solution for SQL Server 2008 (that's what I have to work with). Unfortunately it didn't give quite the correct results, however working from Gordon's example, I came up with this, which does give exactly the desired result.
SELECT
*
FROM
(
SELECT
*,
DENSE_RANK() over(order by (SELECT ISNULL(MAX(#tmp.[order]),0) FROM #tmp WHERE #tmp.[order]<t.[order] AND #tmp.loctype <> t.loctype)) as intorder
FROM
#tmp AS t
) AS u
This gives
loctype order group_order
ACUTE 1 1
ACUTE 2 1
COM 3 2
COM 4 2
ACUTE 5 3
COM 6 4
Essentially it hides an initial ordering inside the DENSE_RANK(). Without the DENSE_RANK() it looks like this:
SELECT
*
FROM
(
SELECT
*,
(SELECT ISNULL(MAX(#tmp.[order]),0) FROM #tmp WHERE #tmp.[order] t.loctype) as intgroup
FROM
#tmp AS t
) AS u
And gives this result:
loctype order intgroup
ACUTE 1 0
ACUTE 2 0
COM 3 2
COM 4 2
ACUTE 5 4
COM 6 5
The interim group order can then be DENSE_RANKed to give the desired outcome.
Upvotes: 0
Reputation: 1269753
One method for achieving this is a difference of row_number()
to identify the groups and then dense_rank()
on the minimum value. The code looks like:
select t.*, dense_rank(minid) over (order by minid) as group_order
from (select t.*, min(id) over (partition by loctype, grp) as minid
from (select t.*
(row_number() over (order by [order]) -
row_number() over (partition by loctype order by [order])
) as grp
from t
) t
) t;
Another method (for SQL Server 2012+) is to use lag()
with a cumulative sum:
select t.*,
sum(case when loctype = prev_loctype then 0 else 1 end) over
(order by id) as group_order
from (select t.*, lag(loctype) over (order by id) as prev_loctype
from t
) t
Upvotes: 1