I have a table with following records:
=======================
| ID | device_num |
=======================
| 1 | 11 |
| 2 | 11 |
| 3 | NULL |
| 4 | 11 |
| 5 | 11 |
| 6 | NULL |
| 7 | 11 |
| 8 | 12 |
| 9 | 12 |
| 10 | 13 |
| 11 | NULL |
| 12 | 13 |
| 13 | 13 |
| 14 | 13 |
| 15 | 14 |
| 16 | 14 |
=======================
I want to assign a rank to each device number based on following cases:
1- Rank should be started with 1.
2- Each record should be compared with its previous record if both has the same device number then assign a same rank to records.
3- Do not assign rank to NULL
records. In case if we get same device number after the Null record then rank should be increased by one.
4- If device number not matches with previous record then increase rank by 1.
Desired output:
===============================
| ID | RANK | device_num |
===============================
| 1 | 1 | 11 |
| 2 | 1 | 11 |
| 3 | | NULL |
| 4 | 2 | 11 |
| 5 | 2 | 11 |
| 6 | | NULL |
| 7 | 3 | 11 |
| 8 | 4 | 12 |
| 9 | 4 | 12 |
| 10 | 5 | 13 |
| 11 | | NULL |
| 12 | 6 | 13 |
| 13 | 6 | 13 |
| 14 | 6 | 13 |
| 15 | 7 | 14 |
| 16 | 7 | 14 |
===============================
I have tried with PostgreSQL Rank functions dense
, rank
etc but not able to assign rank in this order.
Try this:
SELECT id, device_num,
CASE
WHEN device_num IS NOT NULL
THEN DENSE_RANK() OVER (ORDER BY CASE
WHEN device_num IS NOT NULL
THEN min_id
END)
END AS RANK
FROM (
SELECT id, device_num,
MIN(id) OVER (PARTITION BY device_num, grp) AS min_id
FROM (
SELECT id, device_num,
ROW_NUMBER() OVER (ORDER BY id) -
ROW_NUMBER() OVER (PARTITION BY CASE
WHEN device_num IS NULL THEN -1
ELSE device_num
END
ORDER BY id) AS grp
FROM mytable) AS t) AS s
ORDER BY id
I've made the assumptions that:
id
field in your table that specifies row order. device_num
field is of integer
type and -1
is not a valid value for the field. I write a query like this:
;WITH t1 AS (
SELECT *
, ROW_NUMBER() OVER (ORDER BY (SELECT null)) AS rn
FROM yourTable
) -- To add a row-number to yourTable
, t2 AS (
SELECT *
, CASE
WHEN device_num IS NULL THEN 0
WHEN ISNULL(LAG(device_num) OVER (ORDER BY rn), -1) <> ISNULL(device_num, -1) THEN 1
ELSE 0
END AS willChange
FROM t1
)
SELECT device_num
, CASE
WHEN device_num IS NULL THEN null
ELSE SUM(willChange) OVER (ORDER BY rn)
END [RANK]
FROM t2;
EDIT : By using ID
: it can be like this:
;WITH t AS (
SELECT *
, CASE
WHEN device_num IS NULL THEN 0
WHEN ISNULL(LAG(device_num) OVER (ORDER BY ID), -1) <> ISNULL(device_num, -1) THEN 1
ELSE 0
END AS willChange
FROM yourTable
)
SELECT device_num
, CASE
WHEN device_num IS NULL THEN null
ELSE SUM(willChange) OVER (ORDER BY ID)
END [RANK]
FROM t;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.