Rank records in sets based on multiple fields

Viewed 54
╔════════════════════╦═══════════╦══════════╦═══════╦══════╗
║      ENDTIME       ║ TRAILERID ║ POSITION ║ STORE ║ STOP ║
╠════════════════════╬═══════════╬══════════╬═══════╬══════╣
║ 11/7/2017 15:15:44 ║       145 ║ L1       ║ BOS   ║    1 ║
║ 11/7/2017 15:16:57 ║       145 ║ L2       ║ NY    ║    3 ║
║ 11/7/2017 15:17:24 ║       145 ║ R1       ║ NY    ║    2 ║
║ 11/7/2017 15:17:57 ║       145 ║ R2       ║ NY    ║    1 ║
║ 11/7/2017 15:18:26 ║       145 ║ L3       ║ CT    ║    2 ║
║ 11/7/2017 15:34:24 ║       145 ║ R3       ║ CT    ║    1 ║
║ 11/7/2017 16:02:01 ║       999 ║ L1       ║ NJ    ║    2 ║
║ 11/7/2017 16:22:33 ║       999 ║ R1       ║ NJ    ║    1 ║
║ 11/7/2017 16:23:14 ║       999 ║ L2       ║ WA    ║    3 ║
║ 11/7/2017 16:27:16 ║       999 ║ R2       ║ WA    ║    2 ║
║ 11/7/2017 16:27:46 ║       999 ║ L3       ║ WA    ║    1 ║
╚════════════════════╩═══════════╩══════════╩═══════╩══════╝

I'm trying to change the stop field to look like below

╔════════════════════╦═══════════╦══════════╦═══════╦══════╗
║      ENDTIME       ║ TRAILERID ║ POSITION ║ STORE ║ STOP ║
╠════════════════════╬═══════════╬══════════╬═══════╬══════╣
║ 11/7/2017 15:15:44 ║       145 ║ L1       ║ BOS   ║    3 ║
║ 11/7/2017 15:16:57 ║       145 ║ L2       ║ NY    ║    2 ║
║ 11/7/2017 15:17:24 ║       145 ║ R1       ║ NY    ║    2 ║
║ 11/7/2017 15:17:57 ║       145 ║ R2       ║ NY    ║    2 ║
║ 11/7/2017 15:18:26 ║       145 ║ L3       ║ CT    ║    1 ║
║ 11/7/2017 15:34:24 ║       145 ║ R3       ║ CT    ║    1 ║
║ 11/7/2017 16:02:01 ║       999 ║ L1       ║ NJ    ║    2 ║
║ 11/7/2017 16:22:33 ║       999 ║ R1       ║ NJ    ║    2 ║
║ 11/7/2017 16:23:14 ║       999 ║ L2       ║ WA    ║    1 ║
║ 11/7/2017 16:27:16 ║       999 ║ R2       ║ WA    ║    1 ║
║ 11/7/2017 16:27:46 ║       999 ║ L3       ║ WA    ║    1 ║
╚════════════════════╩═══════════╩══════════╩═══════╩══════╝

my attempt was to use row_number and rank but I cant' get to get the right results. Is giving me the first table result.

SELECT ps.ENDTIME, ps.TRUCKID as TRAILERID, ps.CONTAINERPOSITION as POSITION,ps.STORE,RANK() OVER( PARTITION by ps.STORE  ORDER BY ps.ENDTIME DESC)AS STOP 
FROM TRAILERDATA ps
ORDER BY ps.ENDTIME ASC

The most important thing is to label by group of stores with the same rank even if the ENDTIME is not in proper sequence.

1 Answers

Sample data

DECLARE @T TABLE 
    (EndTime datetime2(0), TrailerID int, Position varchar(50), Store varchar(50));
INSERT INTO @T (EndTime, TrailerID, Position, Store) VALUES
('2017-11-07 15:15:44',145,'L1','BOS'),
('2017-11-07 15:16:57',145,'L2','NY'),
('2017-11-07 15:17:24',145,'R1','NY'),
('2017-11-07 15:17:57',145,'R2','NY'),
('2017-11-07 15:18:26',145,'L3','CT'),
('2017-11-07 15:34:24',145,'R3','CT'),
('2017-11-07 16:02:01',999,'L1','NJ'),
('2017-11-07 16:22:33',999,'R1','NJ'),
('2017-11-07 16:23:14',999,'L2','WA'),
('2017-11-07 16:27:16',999,'R2','WA'),
('2017-11-07 16:27:46',999,'L3','WA');

Query

WITH
CTE
AS
(
    SELECT
        EndTime, TrailerID, Position, Store
        ,MAX(EndTime) OVER (PARTITION BY TrailerID, Store) AS SortingTime
    FROM @T
)
SELECT
    EndTime, TrailerID, Position, Store
    ,SortingTime
    ,DENSE_RANK() OVER (PARTITION BY TrailerID ORDER BY SortingTime DESC) AS Stop
FROM CTE
ORDER BY TrailerID, Stop DESC, EndTime;

Result

+---------------------+-----------+----------+-------+---------------------+------+
|       EndTime       | TrailerID | Position | Store |     SortingTime     | Stop |
+---------------------+-----------+----------+-------+---------------------+------+
| 2017-11-07 15:15:44 |       145 | L1       | BOS   | 2017-11-07 15:15:44 |    3 |
| 2017-11-07 15:16:57 |       145 | L2       | NY    | 2017-11-07 15:17:57 |    2 |
| 2017-11-07 15:17:24 |       145 | R1       | NY    | 2017-11-07 15:17:57 |    2 |
| 2017-11-07 15:17:57 |       145 | R2       | NY    | 2017-11-07 15:17:57 |    2 |
| 2017-11-07 15:18:26 |       145 | L3       | CT    | 2017-11-07 15:34:24 |    1 |
| 2017-11-07 15:34:24 |       145 | R3       | CT    | 2017-11-07 15:34:24 |    1 |
| 2017-11-07 16:02:01 |       999 | L1       | NJ    | 2017-11-07 16:22:33 |    2 |
| 2017-11-07 16:22:33 |       999 | R1       | NJ    | 2017-11-07 16:22:33 |    2 |
| 2017-11-07 16:23:14 |       999 | L2       | WA    | 2017-11-07 16:27:46 |    1 |
| 2017-11-07 16:27:16 |       999 | R2       | WA    | 2017-11-07 16:27:46 |    1 |
| 2017-11-07 16:27:46 |       999 | L3       | WA    | 2017-11-07 16:27:46 |    1 |
+---------------------+-----------+----------+-------+---------------------+------+

In the result you can see how SortingTime allows to calculate DENSE_RANK that you need. Essentially, SortingTime defines grouping by TrailerID and Store and also conveniently provides a way to sort by.


The query above relies on EndTime being different for different Stores. More specifically, the MAX time being different. If you have two Stores with the same maximum EndTime, the query would assign the same Stop for them.

If this is the possibility, then add Store to the ORDER BY:

WITH
CTE
AS
(
    SELECT
        EndTime, TrailerID, Position, Store
        ,MAX(EndTime) OVER (PARTITION BY TrailerID, Store) AS SortingTime
    FROM @T
)
SELECT
    EndTime, TrailerID, Position, Store
    ,SortingTime
    ,DENSE_RANK() OVER (PARTITION BY TrailerID ORDER BY SortingTime DESC, Store) AS Stop
FROM CTE
ORDER BY TrailerID, Stop DESC, EndTime;
Related