I have the following table:
+----+------+------+ | id | cat1 | cat2 | +----+------+------+ | 1 | A | foo | | 2 | A | foo | | 3 | A | bar | | 4 | B | sci | | 5 | B | ble | | 6 | B | ble | +----+------+------+
I would like to rank the subcategory (cat2).
Desired outcome:
+----+------+------+------+ | id | cat1 | cat2 | res | +----+------+------+------+ | 1 | A | foo | 1 | | 2 | A | foo | 1 | | 3 | A | bar | 2 | | 4 | B | sci | 1 | | 5 | B | ble | 2 | | 6 | B | ble | 2 | +----+------+------+------+
I use DENSE_RANK with PARTITION BY to get the following result:
+----+------+------+------+ | id | cat1 | cat2 | res | +----+------+------+------+ | 1 | A | foo | 2 | | 2 | A | foo | 2 | | 3 | A | bar | 1 | | 4 | B | sci | 2 | | 5 | B | ble | 1 | | 6 | B | ble | 1 | +----+------+------+------+
Statement:
SELECT DENSE_RANK() OVER (PARTITION BY cat1 ORDER BY cat2 asc) as res, t.* FROM mytable t ORDER BY id;
As you can see, the only thing I’m missing is the order of the result. Currently, the rank is based on the alphabetic order of cat2. However, I want to preserve the order given by the id’s (see desired outcome). Simply changing the ORDER BY of my DENSE_RANK will not do the trick.
Advertisement
Answer
WITH cte AS ( SELECT MIN(id) id, cat1, cat2
FROM test
GROUP BY cat1, cat2 )
SELECT t1.id,
t1.cat1,
t1.cat2,
DENSE_RANK() OVER (PARTITION BY t1.cat1 ORDER BY t2.id asc) as res
FROM test t1
JOIN cte t2 USING (cat1, cat2)
ORDER BY t1.id;
Of course, CTE may be converted to subquery.