Is it possible to rank item by partition without use CTE method
Expected Table
item | value | ID |
---|---|---|
A | 10 | 1 |
A | 20 | 1 |
B | 30 | 2 |
B | 40 | 2 |
C | 50 | 3 |
C | 60 | 3 |
A | 70 | 4 |
A | 80 | 4 |
By giving id to the partition to allow agitated function to work the way I want.
item | MIN | MAX | ID |
---|---|---|---|
A | 10 | 20 | 1 |
B | 30 | 40 | 2 |
C | 50 | 60 | 3 |
A | 70 | 80 | 4 |
SQL Version: Microsoft SQL Sever 2017
CodePudding user response:
Assuming that the value
column provides the intended ordering of the records which we see in your question above, we can try using the difference in row numbers method here. Your problem is a type of gaps and islands problem.
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY value) rn1,
ROW_NUMBER() OVER (PARTITION BY item ORDER BY value) rn2
FROM yourTable
)
SELECT item, MIN(value) AS [MIN], MAX(value) AS [MAX], MIN(ID) AS ID
FROM cte
GROUP BY item, rn1 - rn2
ORDER BY MIN(value);
Demo
If you don't want to use a CTE here, for whatever reason, you may simply inline the SQL code in the CTE into the bottom query, as a subquery:
SELECT item, MIN(value) AS [MIN], MAX(value) AS [MAX], MIN(ID) AS ID
FROM
(
SELECT *, ROW_NUMBER() OVER (ORDER BY value) rn1,
ROW_NUMBER() OVER (PARTITION BY item ORDER BY value) rn2
FROM yourTable
) t
GROUP BY item, rn1 - rn2
ORDER BY MIN(value);
CodePudding user response:
You can generate group IDs by analyzing the previous row item
value that could be obtained with the LAG
function and finally use GROUP BY
to get the minimum and maximum value
in item groups.
SELECT
item,
MIN(value) AS "min",
MAX(value) AS "max",
group_id 1 AS id
FROM (
SELECT
*,
SUM(CASE WHEN item = prev_item THEN 0 ELSE 1 END) OVER (ORDER BY value) AS group_id
FROM (
SELECT
*,
LAG(item, 1, item) OVER (ORDER BY value) AS prev_item
FROM t
) items
) groups
GROUP BY item, group_id
Query produces output
item | min | max | id |
---|---|---|---|
A | 10 | 20 | 1 |
B | 30 | 40 | 2 |
C | 50 | 60 | 3 |
A | 70 | 80 | 4 |
You can check a working demo here