Сумма последовательных месяцев на основе групп с критериями - PullRequest
1 голос
/ 10 января 2020

У меня возникли проблемы с сокращением продаж в лучших регионах, которые происходили в течение нескольких месяцев подряд. Я знаю, что мне нужно использовать некоторую форму оконной функции с Row_Number или Dense_Rank, но у меня возникают проблемы с получением окончательного результата

Вот мои исходные данные:

+--------+-----------+------------+
| Fruit  | SaleDate  | Top_Region |
+--------+-----------+------------+
| Apple  | 1/1/2017  |          1 |
| Apple  | 2/1/2017  |          1 |
| Apple  | 3/1/2017  |          1 |
| Apple  | 4/1/2017  |          0 |
| Apple  | 5/1/2017  |          0 |
| Apple  | 6/1/2017  |          0 |
| Apple  | 7/1/2017  |          1 |
| Apple  | 8/1/2017  |          1 |
| Apple  | 9/1/2017  |          1 |
| Apple  | 10/1/2017 |          1 |
| Apple  | 11/1/2017 |          0 |
| Apple  | 12/1/2017 |          0 |
| Banana | 1/1/2017  |          0 |
| Banana | 2/1/2017  |          0 |
| Banana | 3/1/2017  |          1 |
| Banana | 4/1/2017  |          1 |
| Banana | 5/1/2017  |          1 |
| Banana | 6/1/2017  |          1 |
| Banana | 7/1/2017  |          1 |
| Banana | 8/1/2017  |          1 |
| Banana | 9/1/2017  |          0 |
| Banana | 10/1/2017 |          1 |
| Banana | 11/1/2017 |          1 |
| Banana | 12/1/2017 |          0 |
+--------+-----------+------------+

Это ожидаемый результат:

+--------+-----------+-----------+-------+
| Fruit  |   Start   |    End    | Total |
+--------+-----------+-----------+-------+
| Apple  | 1/1/2017  | 3/1/2017  |     3 |
| Apple  | 7/1/2017  | 10/1/2017 |     4 |
| Banana | 3/1/2017  | 8/1/2017  |     6 |
| Banana | 10/1/2017 | 11/1/2017 |     2 |
+--------+-----------+-----------+-------+

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

До сих пор я пробовал несколько различных комбинаций, с это самое близкое.

SELECT fruit,
        MIN(saledate) AS spanStart ,
        MAX(saledate) AS spanEnd,
        COUNT(*) AS spanLength
FROM    ( SELECT    s.* ,
                    ( ROW_NUMBER() OVER ( ORDER BY month )
                      - ROW_NUMBER() OVER ( PARTITION BY fruit, topregion ORDER BY month ) ) AS fruits
          FROM      #salesdata s
        ) s
GROUP BY fruit,fruits ,
        topregion
HAVING  topregion = 1
ORDER BY COUNT(*) DESC;

Любая помощь будет принята с благодарностью

1 Ответ

0 голосов
/ 10 января 2020

Это типичная проблема пробелов и островов. Одна стратегия состоит в том, чтобы идентифицировать группы смежных групп строк, вычисляя разницу между двумя row_number() с. Затем мы можем отфильтровать группы с top_region = 1 и использовать агрегацию, чтобы получить дату начала, дату окончания и количество записей в группе.

Ваш запрос действительно близок, но в первом row_number() отсутствует partition by fruit в его over() предложении. И я обнаружил, что псевдоним этого столбца fruits, где другой столбец называется fruit подвержен ошибкам.

select 
    fruit,
    min(sale_date) start_date,
    max(sale_date) end_date,
    count(*) total
from (
    select 
        t.*,
        row_number() over(partition by fruit order by sale_date) rn1,
        row_number() over(partition by fruit, top_region order by sale_date) rn2
    from mytable t
) t
where top_region = 1
group by fruit, rn1 - rn2
order by fruit, start_date

Вы можете запустить внутренний запрос отдельно, чтобы увидеть результат, который он выдает.

Демонстрация на DB Fiddle :

fruit  | start_date | end_date   | total
:----- | :--------- | :--------- | ----:
Apple  | 2017-01-01 | 2017-01-03 |     3
Apple  | 2017-01-07 | 2017-01-10 |     4
Banana | 2017-01-03 | 2017-01-08 |     6
Banana | 2017-01-10 | 2017-01-11 |     2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...