Получить накопительную сумму за каждый месяц в oracle sql

#sql #oracle #datetime #count #distinct

#sql #Oracle #дата и время #подсчитать #различная

Вопрос:

Привет, у меня есть таблица с 3 столбцами.

 custid  p_date          vegetable
0000009 07-APR-20       tomato
0000013 25-MAR-20       potato
0000015 11-APR-19       tomato
0000016 23-JUL-18       potato
0000019 19-JUL-18       potato
0000018 07-JUN-20       turnip
0000020 12-JUL-18       turnip
0000022 23-JUL-18       potato
0000023 12-JUL-18       turnip
0000024 11-AUG-20       potato
 

Мне нужно рассчитать отдельное количество для клиентов на основе столбца veggie
вместе с совокупной суммой за каждый месяц

выходные данные должны содержать следующие столбцы

 date        
tomato_ct 
cum_tomato_ct
potato_ct
cum_potato_ct
turnip_ct        
cum_turnip_ct
 

Комментарии:

1. Пожалуйста, покажите нам результат, который вы хотите, а не только имена столбцов.

Ответ №1:

Если вы хотите, чтобы ежемесячные подсчеты и совокупные подсчеты сводились по vegetable, вы можете сделать:

 select trunc(p_date, 'month') as p_month,
    sum(case when vegetable = 'tomato' then 1 else 0 end) as tomato_ct,
    sum(sum(case when vegetable = 'tomato' then 1 else 0 end)) over(order by trunc(p_date, 'month')) as cum_tomato_ct,
    sum(case when vegetable = 'potato' then 1 else 0 end) as potato_ct,
    sum(sum(case when vegetable = 'potato' then 1 else 0 end)) over(order by trunc(p_date, 'month')) as cum_potato_ct,
    sum(case when vegetable = 'turnip' then 1 else 0 end) as turnip_ct,
    sum(sum(case when vegetable = 'turnip' then 1 else 0 end)) over(order by trunc(p_date, 'month')) as cum_turnip_ct
from mytable
group by trunc(p_date, 'month')
 

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

 select trunc(p_date, 'month') as p_month,
    sum(case when vegetable = 'tomato' then 1 else 0 end) as tomato_ct,
    sum(sum(case when vegetable = 'tomato' then 1 else 0 end)) over(order by trunc(p_date, 'month')) as cum_tomato_ct,
    sum(case when vegetable = 'potato' then 1 else 0 end) as potato_ct,
    sum(sum(case when vegetable = 'potato' then 1 else 0 end)) over(order by trunc(p_date, 'month')) as cum_potato_ct,
    sum(case when vegetable = 'turnip' then 1 else 0 end) as turnip_ct,
    sum(sum(case when vegetable = 'turnip' then 1 else 0 end)) over(order by trunc(p_date, 'month')) as cum_turnip_ct
from (
    select cust_id, vegetable, min(p_date) as p_date
    from mytable
    group by cust_id, vegetable
) t
group by trunc(p_date, 'month')
 

Комментарии:

1. Я получил желаемый результат. Спасибо. Проверка подсчета

2. Я не согласен!!! Это приведет к возникновению ошибки, поскольку аналитические функции не разрешены в агрегатной функции.

3. @Popeye: здесь все наоборот: агрегатная функция находится внутри аналитической функции.

4. В том же запросе, если мне нужно общее количество заказов и накопительное количество, как я могу отредактировать?

Ответ №2:

Вы можете использовать комбинацию analytical функции и GROUP BY следующим образом:

 SQL>
SQL> -- sample data
SQL> WITH YOUR_TABLE(custid,  p_date,          vegetable) AS
  2  (SELECT '0000009', TO_DATE('07-APR-20','DD-MON-RR'),       'tomato' FROM DUAL UNION ALL
  3  SELECT '0000013', TO_DATE('25-MAR-20','DD-MON-RR'),       'potato' FROM DUAL UNION ALL
  4  SELECT '0000015', TO_DATE('11-APR-19','DD-MON-RR'),       'tomato' FROM DUAL UNION ALL
  5  SELECT '0000016', TO_DATE('23-JUL-18','DD-MON-RR'),       'potato' FROM DUAL UNION ALL
  6  SELECT '0000019', TO_DATE('19-JUL-18','DD-MON-RR'),       'potato' FROM DUAL UNION ALL
  7  SELECT '0000018', TO_DATE('07-JUN-20','DD-MON-RR'),       'turnip' FROM DUAL UNION ALL
  8  SELECT '0000020', TO_DATE('12-JUL-18','DD-MON-RR'),       'turnip' FROM DUAL UNION ALL
  9  SELECT '0000022', TO_DATE('23-JUL-18','DD-MON-RR'),       'potato' FROM DUAL UNION ALL
 10  SELECT '0000023', TO_DATE('12-JUL-18','DD-MON-RR'),       'turnip' FROM DUAL UNION ALL
 11  SELECT '0000024', TO_DATE('11-AUG-20','DD-MON-RR'),       'potato' FROM DUAL)
 12  -- actual query starts from here
 13  SELECT P_DATE,
 14     COUNT(CASE WHEN vegetable = 'tomato' THEN 1 END) AS TOMATO_CT,
 15     MAX(TOMATO_CNT) AS CUM_TOMATO_CT,
 16     COUNT(CASE WHEN vegetable = 'potato' THEN 1 END) AS POTATO_CT,
 17     MAX(POTATO_CNT) AS CUM_POTATO_CT,
 18     COUNT(CASE WHEN vegetable = 'turnip' THEN 1 END) AS TURNIP_CT,
 19     MAX(TURNIP_CNT) AS CUM_TURNIP_CT
 20    FROM
 21    (SELECT T.*,
 22   COUNT(CASE WHEN vegetable = 'tomato' THEN 1 END) OVER (ORDER BY P_DATE) AS TOMATO_CNT,
 23   COUNT(CASE WHEN vegetable = 'potato' THEN 1 END) OVER (ORDER BY P_DATE) AS POTATO_CNT,
 24   COUNT(CASE WHEN vegetable = 'turnip' THEN 1 END) OVER (ORDER BY P_DATE) AS TURNIP_CNT
 25  FROM (SELECT DISTINCT custid, TRUNC(p_date,'MON') P_DATE, vegetable FROM YOUR_TABLE) T
 26     )
 27   GROUP BY P_DATE
 28   ORDER BY P_DATE;

P_DATE                TOMATO_CT CUM_TOMATO_CT  POTATO_CT CUM_POTATO_CT  TURNIP_CT CUM_TURNIP_CT
-------------------- ---------- ------------- ---------- ------------- ---------- -------------
01-JUL-2018 00:00:00          0             0          3             3          2             2
01-APR-2019 00:00:00          1             1          0             3          0             2
01-MAR-2020 00:00:00          0             1          1             4          0             2
01-APR-2020 00:00:00          1             2          0             4          0             2
01-JUN-2020 00:00:00          0             2          0             4          1             3
01-AUG-2020 00:00:00          0             2          1             5          0             3

6 rows selected.

SQL>
 

Комментарии:

1. Не могли бы вы, пожалуйста, объяснить приведенный выше запрос. Как max(tomato_cnt) выдает накопительную сумму?

2. Потому что внутренний запрос содержит совокупный расчет для всех упомянутых овощей. и, используя MAX, он использует максимум всего совокупного количества за сгруппированный месяц. Если вы будете выполнять внутренний запрос в одиночку, вы сможете увидеть логику, лежащую в основе MAX во внешнем запросе