#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 во внешнем запросе