DENSE_RANK прерывается последовательно при изменении - PullRequest
0 голосов
/ 24 сентября 2018

Столбец grp должен представлять блок, разделенный на GroupId, RouteId и упорядоченный LengthStart, где при перемещении по блокам, если locationId остается тем же, grp остается тем же.Разрыв в последовательности создает новую grp

+---------+----------+--------------+------------+-------------+------+
| GROUPID |  ROUTEID |  LENGTHSTART |  LENGTHEND |  LOCATIONID |  GRP |
+---------+----------+--------------+------------+-------------+------+
|     1   | A        | 0            | 1          | 1           | 1    |
|     1   | A        | 1            | 2          | 1           | 1    |
|     1   | A        | 2            | 3          | 2           | 2    |
|     1   | A        | 3            | 4          | 1           | 3    |
|     2   | A        | 2            | 3          | 2           | 4    |
|     1   | B        | 2            | 3          | 2           | 5    |
|     1   | A        | 4            | 5          | 1           | 3    |
+---------+----------+--------------+------------+-------------+------+

Мой поиск по этой проблеме привел меня к следующему решению: DENSE_RANK в соответствии с определенным порядком

Моя попыткапри расчете grp:

SELECT *, ROW_NUMBER() OVER (ORDER BY GroupId, RouteId, LengthStart) - ROW_NUMBER() OVER (PARTITION BY GroupId, RouteId, LocationId ORDER BY GroupId, RouteId, LengthStart) AS grp
FROM mytable

Я пытался принять это решение таким образом, чтобы у меня было больше уровней разбиения, и оно работает в действительно базовых сценариях использования (таких, как показанный выше, но в сложныхсценарии его провал).

Я не совсем понимаю, почему два row_number () вычитают и как это работает, но это очень хорошо сработало в простом примере.

Я пробовал другие подходы, использующие LAG, но просто не понимал, как взять логику и применить ее.

Вот скрипка с более сложным сценарием:

https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=3704dfe8583b0dd020b189184d149cb7

Вы можете увидеть одну из многих ошибок, которые я видел, выделенные здесь: enter image description here

Ответы [ 2 ]

0 голосов
/ 24 сентября 2018

Изменение параметров в предложениях over приведет к другому результату.Обратите внимание, что вам не нужно повторять столбцы, используемые для разделения в порядке.Концепция этого метода состоит в том, чтобы вычислить общее значение (в столбце grp), которое часто используется в последующих вычислениях, таких как;количество шагов, или стоимость, или мин / макс и т. д.

SELECT
    *
  , ROW_NUMBER() OVER (ORDER BY GroupId, RouteId, LengthStart) 
  - ROW_NUMBER() OVER (PARTITION BY GroupId, RouteId ORDER BY LengthStart ) AS grp
FROM mytable
ORDER BY
    GroupId
  , RouteId
  , LengthStart

Полезно вывести два вычисления row_number, чтобы вы могли увидеть, как это работает:

    Id      GroupId   RouteId   LengthStart   LengthEnd   LocationId   rn1   rn2   grp  
 --------- --------- --------- ------------- ----------- ------------ ----- ----- ----- 
  2651246         3   AAA         0.0000000   0.0920000      1884268     1     1     0  
  2651247         3   AAA         0.0920000   0.5800000      1855305     2     2     0  
  2651248         3   AAA         0.5800000   1.3610000      1884268     3     3     0  
  2651249         3   AAA         1.3610000   1.6170000      1884268     4     4     0  
  2651250         3   AAA         1.6170000   2.3750000      1884268     5     5     0  
  2681493         3   BBB         0.0000000   1.5600000      1864963     6     1     5  
  2681494         3   BBB         1.5600000   2.7100000      1864963     7     2     5  
  2681495         3   BBB         2.7100000   3.3900000      1864963     8     3     5  
  2954915         3   CCC         0.0000000   0.0500000      1883382     9     1     8  
  2954916         3   CCC         0.0500000   0.1400000      1846300    10     2     8  
  …                                                                                     

rn1 столбец начинается с 1 и продолжает увеличиваться.Второй столбец rn перезапускается на 1 с каждым разделом, но поскольку он также увеличивается на единицу в той же последовательности заказов, когда вы вычитаете rn2 из rn1, вы получаете «постоянный» результат для grp для каждого раздела, используемого вrn2

0 голосов
/ 24 сентября 2018

Похоже, это проблема пробелов и островков, в которой вы неправильно поняли решение.

В этом случае столбец grp сам по себе не определяет пробел или остров, онпросто дает вам дополнительную информацию, необходимую для их идентификации.

В вашем случае способ, которым вы ее реализовали (locationId, grp), формирует новую "подгруппу"идентификатор.

Я бы также немного изменил ваш запрос, чтобы было легче понять, что происходит ...

SELECT
  *,
    ROW_NUMBER() OVER (PARTITION BY GroupID, RouteID             ORDER BY LengthStart)
  - ROW_NUMBER() OVER (PARTITION BY GroupId, RouteId, LocationId ORDER BY LengthStart) AS grp
FROM
  mytable
ORDER BY
  GroupId, RouteId, LengthStart

Это делает более ясным, что разные GroupID, RouteID имеют ничего не имеет отношения друг к другу при обработке промежутков и островков (подгруппы) .

Тогда я могу показать упрощенный пример ...

  LocationID, Start, SetRowNum, LocRowNum, Difference, GroupID

      1        000       1       1          0          (1,0)
      1        100       2       2          0          (1,0)

      2        200       3         1          2        (2,2)
      2        300       4         2          2        (2,2)

      1        400       5       3          2          (1,2)

      2        500       6         3          3        (2,3)

      3        600       7           1          6      (3,6)

      2        700       8         4          4        (2,4)
      2        800       9         5          4        (2,4)

Для каждого LocationID отдельно вырабатывается island.

A gap - просто любая строка длялюбой другой LocationID.

«Хитрость» заключается в том, что на каждом острове оба ряда увеличиваются вместе.При обоюдном увеличении разница остается неизменной.Эта разница составляет island_id.

Затем, во время разрыва, первое число увеличивается, так что когда мы достигаем следующего острова, разница между двумя значениями увеличивается, давая новый island_id ** за это LocationID.

Помните, что при разработке island_id для location_1 мы рассматриваем все остальные местоположения как gaps между островами местоположения 1.

Для местоположения 1 у нас есть острова в строках 1,2 и 5, с IslandID из 0 и 2 соответственно.

  LocationID, Start, SetRowNum, LocRowNum, Difference, GROUP_ID

      1        000       1       1          0          (1,0)
      1        100       2       2          0          (1,0)

      GAP

      1        400       5       3          2          (1,2)

Для местоположения 2 у нас есть острова в строках3,4, 6 и 8,9 с IslandID из 2, 3, 4 соответственно.

  LocationID, Start, SetRowNum, LocRowNum, Difference

     GAP

      2        200       3         1          2        (2,2)
      2        300       4         2          2        (2,2)

     GAP

      2        500       6         3          3        (2,3)

     GAP

      2        700       8         4          4        (2,4)
      2        800       9         5          4        (2,4)

Для Местоположения 3 у нас есть острова в ряду 7с IslandID из 6.

  LocationID, Start, SetRowNum, LocRowNum, Difference

     GAP

      3        600       7           1          6      (3,6)

     GAP

В общем, все острова имеют разные идентификаторы.

Но у Location1 и Location2 есть острова с IslandID = 2.

  • Итак, вам нужно использовать (locationID, IslandID) вместе
  • Составной ключ будет уникальным для этого раздела
...