Как подсчитать несколько столбцов в SQL (Oracle) с критериями? - PullRequest
1 голос
/ 27 мая 2020

Я работаю над SMS-шлюзом, который содержит несколько платных SMS-услуг с разными номерами,
каждое SMS, отправленное клиенту, имеет 4 статуса, как показано ниже ( перенаправлено, доставлено, срок действия истек, доставка не удалась )

enter image description here

Теперь у меня есть первая_таблица для системы зарядки с приведенными ниже деталями ( ТАБЛИЦА-A )

enter image description here

и ниже ( ТАБЛИЦА-B ), которые содержат статус каждого отправленного SMS с его идентификатором enter image description here

Ниже мой ожидаемый окончательный результат, чтобы спрогнозировать детали для каждой sms-службы:

enter image description here

Сначала я подумал это было легко, все, что мне нужно, это просто использовать COUNT(Case when ...)
, но в моем случае у меня есть тысячи SMS-номеров (услуг), поэтому, если я воспользуюсь этим подходом, это будет так: -

COUNT(CASE WHEN a.SMS_SHORT_CODE='1111' AND B.STATUS='forwarded' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='1111' AND B.STATUS='delivered' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='1111' AND B.STATUS='expired' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='1111' AND B.STATUS='delivery failed' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='5000' AND B.STATUS='forwarded' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='5000' AND B.STATUS='delivered' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='5000' AND B.STATUS='expired' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='5000' AND B.STATUS='delivery failed' )
...
...
...
...
...
...
...

Вышеупомянутый подход непрактичен, если у вас много сервисов, при этом отмечая, что CASE может обрабатывать только 250 условий?

Итак, какой подход является наилучшим? o сделать left outer join для (Таблица A) на (Таблица B) с использованием идентификатора SMS и подсчитать каждый SMS-статус и спрогнозировать его, как показано ниже?

enter image description here

Ответы [ 3 ]

1 голос
/ 27 мая 2020

Вы можете использовать предложение PIVOT ( введено в Oracle 11g версии ) для этих status столбцов:

SELECT sms_short_code, 
       COUNT_OF_forwarded, 
       COUNT_OF_delivered, 
       COUNT_OF_expired,
       COUNT_OF_delivery_failed
  FROM tableB
 PIVOT 
 (
  COUNT(*) FOR status IN ( 'forwarded'       AS COUNT_OF_forwarded,
                           'delivered'       AS COUNT_OF_delivered,
                           'expired'         AS COUNT_OF_expired,
                           'delivery failed' AS COUNT_OF_delivery_failed )
 ) 

, например, только используя TableB достаточно.

Демо

1 голос
/ 27 мая 2020

Я бы предложил условное агрегирование:

select b.SMS_SHORT_CODE,
       sum(case when status = 'forwaded' then 1 else 0 end) as count_of_forwaded,
       sum(case when status = 'delivered' then 1 else 0 end) as count_of_status,
       sum(case when status = 'expired' then 1 else 0 end) as count_of_expired,
       sum(case when status = 'delivery failed' then 1 else 0 end) as count_of_delivery_failed
from TABLEB b
group by b.SMS_SHORT_CODE ;

Обратите внимание, что JOIN не требуется. Все данные, которые вы хотите агрегировать, находятся в TABLEB.

1 голос
/ 27 мая 2020

Пожалуйста, используйте запрос ниже,

select 
A.SMS_SHORT_CODE,
case when status = 'forwaded' then count(status ) end as count_of_forwaded,
case when status = 'delivered' then count(status ) end as count_of_status,
case when status = 'expired' then count(status ) end as count_of_expired,
case when status = 'delivery failed' then count(status ) end as count_of_delivery_failed
from TABLEA A
inner join TABLEB B 
on (A.SMS_ID = B.SMS_ID)
group by A.SMS_SHORT_CODE, status ;
...