I have the following table:
x
+----+------+------+
| 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.