Нарастающие итоги в Oracle SQL

У меня есть следующая таблица

CP          ROK DOPIS_C
-----------------------
6059150790  2014    C
6059150790  2015    C
6059150790  2016    C
6059150790  2017     
6059150790  2018    C
6059150790  2019     
6059150790  2020    C
6059150790  2021    C
6059150790  2022    C
6059150790  2023     
6059150790  2024     

мне нужен этот вывод

CP          ROK DOPIS_C     RN_C1
---------------------------------
6059150790  2014    C         1
6059150790  2015    C         2
6059150790  2016    C         3
6059150790  2017                 
6059150790  2018    C         1
6059150790  2019                 
6059150790  2020    C         1
6059150790  2021    C         2
6059150790  2022    C         3
6059150790  2023             
6059150790  2024                 

в столбце RN_C1 подсчитывается количество предыдущих записей, где DOPIS_C имеет значение C и если в предыдущей записи в столбце DOPIS_C имеется нулевое значение, счетчик сбрасывается

я пробую это

SELECT 
    CP,
    ROK,
    DOPIS_C,
    CASE 
        WHEN DOPIS_C = 'C' THEN 
            CASE 
                WHEN lag(DOPIS_C) OVER (ORDER BY ROK) IS NULL THEN 
                    ROW_NUMBER() OVER (ORDER BY ROK)
                WHEN lag(DOPIS_C) OVER (ORDER BY ROK) = 'C' THEN 
                    COUNT(CASE WHEN DOPIS_C = 'C' THEN 1 END) OVER (ORDER BY ROK) 
            END
        ELSE 0 
    END AS POSILANI
FROM 
    table;

но результат

6059150790  2014    C   1
6059150790  2015    C   2
6059150790  2016    C   3
6059150790  2017        0
6059150790  2018    C   5
6059150790  2019        0
6059150790  2020    C   7
6059150790  2021    C   6
6059150790  2022    C   7
6059150790  2023        0
6059150790  2024        0
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
0
57
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

В Oracle 12 вы можете использовать MATCH_RECOGNIZE для сопоставления шаблонов построчно:

SELECT cp,
       rok,
       dopis_c,
       CASE dopis_c WHEN 'C' THEN posilani END AS posilani
FROM   table_name
       MATCH_RECOGNIZE(
         PARTITION BY cp
         ORDER BY rok
         MEASURES
           COUNT(dopis_c) AS posilani
         ALL ROWS PER MATCH
         PATTERN ( C+ | NOT_C )
         DEFINE C AS dopis_c = 'C'
       );

Или в более ранних версиях вы можете использовать несколько аналитических функций:

SELECT cp,
       rok,
       dopis_c,
       rn,
       CASE dopis_c
       WHEN 'C'
       THEN rn - COALESCE(
              LAST_VALUE(CASE WHEN dopis_c IS NULL THEN rn END) IGNORE NULLS
                OVER (PARTITION BY cp ORDER BY rok),
              0
            )
       END AS posilani
FROM (
  SELECT cp,
         rok,
         dopis_c,
         ROW_NUMBER() OVER (PARTITION BY cp ORDER BY rok) AS rn
  FROM   table_name
);

или:

SELECT cp,
       rok,
       dopis_c,
       CASE dopis_c
       WHEN 'C'
       THEN ROW_NUMBER() OVER (PARTITION BY cp, dopis_c, c_grp ORDER BY rok)
       END AS posilani
FROM (
  SELECT cp,
         rok,
         dopis_c,
         COUNT(1) OVER (PARTITION BY cp ORDER BY rok)
           - COUNT(dopis_c) OVER (PARTITION BY cp ORDER BY rok) AS c_grp
  FROM   table_name
)
ORDER BY
       cp,
       rok

Что для примера данных:

CREATE TABLE table_name (CP, ROK, DOPIS_C) AS
SELECT 6059150790, 2014, 'C'  FROM DUAL UNION ALL
SELECT 6059150790, 2015, 'C'  FROM DUAL UNION ALL
SELECT 6059150790, 2016, 'C'  FROM DUAL UNION ALL
SELECT 6059150790, 2017, NULL FROM DUAL UNION ALL
SELECT 6059150790, 2018, 'C'  FROM DUAL UNION ALL
SELECT 6059150790, 2019, NULL FROM DUAL UNION ALL
SELECT 6059150790, 2020, 'C'  FROM DUAL UNION ALL
SELECT 6059150790, 2021, 'C'  FROM DUAL UNION ALL
SELECT 6059150790, 2022, 'C'  FROM DUAL UNION ALL
SELECT 6059150790, 2023, NULL FROM DUAL UNION ALL
SELECT 6059150790, 2024, NULL FROM DUAL;

Все выходы:

КП Республика Корея ДОПИС_С ПОСИЛАНИ 6059150790 2014 год С 1 6059150790 2015 год С 2 6059150790 2016 год С 3 6059150790 2017 год нулевой нулевой 6059150790 2018 год С 1 6059150790 2019 год нулевой нулевой 6059150790 2020 год С 1 6059150790 2021 год С 2 6059150790 2022 год С 3 6059150790 2023 год нулевой нулевой 6059150790 2024 год нулевой нулевой

рабочий пример

Спасибо, а если бы я захотел включить в расчет еще один столбец, где принцип расчета был бы тот же. например столбец dopis_k, где будет получено количество вхождений «K»

feoftheda 18.04.2024 09:41

@feoftheda В общем, если у вас есть следующий вопрос, вам следует задать новый вопрос . В этом случае вы можете запустить MATCH_RECOGNIZE дважды или использовать аналитические функции — несколько примеров находятся в этой скрипте.

MT0 18.04.2024 10:02

Вы также можете сделать это без MATCH_RECOGNIZE, но с помощью подзапроса:

select cp, rok_dopis, c, 
    nvl2(c,row_number() over(partition by cp,  c || n order by rok_dopis),null) as rn_c1
from (
    select d.*, 
        sum(case when c is null then 1 else 0 end) over(partition by cp order by rok_dopis) as n    
    from table_name d 
)
order by rok_dopis
;

Другие вопросы по теме