Как ранжировать столбец в SQL, основываясь на разнице в днях и разделах строки? - PullRequest
0 голосов
/ 20 апреля 2020

Я пытаюсь получить RANK () для столбца на основе разницы строк <3. </p>

select hotel.*,
IFNULL(datediff(visit_date, lag(visit_date)
OVER (partition by hotel_id)), 0) as diff
from hotel;

Я получаю следующий вывод:

hotel_id customer_id  visit_date  diff
1            1        2020-01-01    0
1            2        2020-01-03    2
2            1        2020-01-01    0
2            2        2020-01-10    9
2            3        2020-01-14    4
3            1        2020-01-04    0
3            1        2020-01-11    7

I я застрял с частью RANK ().

Ожидаемый результат: если разность дней меньше 3, то 1 еще 2. И если следующий больше 3 дней, то 3, и и так далее

hotel_id customer_id  visit_date  rank
1            1        2020-01-01    1
1            2        2020-01-03    1
2            1        2020-01-01    1
2            2        2020-01-10    2
2            3        2020-01-14    3
3            1        2020-01-04    1
3            1        2020-01-11    2

Ответы [ 3 ]

1 голос
/ 20 апреля 2020

Вы можете использовать этот запрос для генерации ваших rank значений. Он использует пару CTE s, первый для генерации номеров строк для каждого посещения (для каждого отеля), а второй (рекурсивный) CTE для генерации значений rank, итерируя по строкам из первое CTE и только увеличение rank, когда разница в датах превышает 2 дня:

WITH RECURSIVE hotel_rows AS (
  SELECT hotel_id, customer_id, visit_date,
         ROW_NUMBER() OVER (PARTITION BY hotel_id ORDER BY visit_date) AS rn
  FROM hotel
  ORDER BY hotel_id, visit_date
),
ranks AS (
  SELECT hotel_id, customer_id, visit_date, rn, 1 AS `rank`
  FROM hotel_rows
  WHERE rn = 1
  UNION ALL
  SELECT h.hotel_id, h.customer_id, h.visit_date, h.rn,
         r.rank + (h.visit_date > r.visit_date + INTERVAL 2 DAY)
  FROM hotel_rows h
  JOIN ranks r ON h.hotel_id = r.hotel_id
              AND h.rn = r.rn + 1
)
SELECT SELECT hotel_id, customer_id, visit_date, `rank`
FROM ranks
ORDER BY hotel_id, visit_date

Вывод (для моей слегка расширенной демонстрации):

hotel_id    customer_id     visit_date  rank
1           1               2020-01-01  1
1           2               2020-01-03  1
2           1               2020-01-01  1
2           2               2020-01-10  2
2           3               2020-01-14  3
2           1               2020-01-15  3
2           2               2020-01-20  4
3           1               2020-01-04  1
3           1               2020-01-11  2

Демонстрация на dbfiddle

0 голосов
/ 20 апреля 2020

Я бы express это как:

select h.*,
       (case when lag(visit_date) over (partition by hotel_id order by visit_date) < visit_date - interval 3 day
             then 2 else 1
       end)
from hotel h;

Редактировать;

На основе вашей пересмотренной точки вы хотите назначить группы на основе разницы дат, а затем использовать row_number() :

select h.*,
       1 + sum( coalesce(visit_date > prev_vd + interval 3 day, 0) ) over (partition by hotel_id order by visit_date) as grp
from (select h.*,
             lag(visit_date) over (partition by hotel_id order by visit_date) as prev_vd
      from hotel h
     ) h;

Здесь - это дб <> скрипка.

0 голосов
/ 20 апреля 2020

Если вы хотите получить результат в соответствии с заданным условием, вы можете попробовать ниже на SQL Сервер. вот это Демо

select
  hotel_id, 
  customer_id, 
  visit_date,
  case 
    when days < 3 then 1
    else 2
  end as rnk
from
(
  select
    *,
    datediff(day, n_date, visit_date) as days
  from
  (
      select
        *,
        coalesce(lag(visit_date) over (partition by hotel_id order by visit_date), visit_date) as n_date

      from hotel
  ) val
)days
...