【问题标题】:How to count multiple columns in SQL (Oracle) with criteria?如何使用条件计算 SQL (Oracle) 中的多个列?
【发布时间】:2020-05-27 10:10:01
【问题描述】:

我正在开发 SMS-Gateway,它拥有多个不同号码的收费 SMS-服务,
每条发送给客户的短信都有以下 4 种状态(已转发、已送达、已过期、送达失败

现在我有以下充电系统的 first_table 以及以下详细信息(TABLE-A

及以下 (TABLE-B) 包含每条已发送 SMS 的状态及其 ID

以下是我预期的最终结果,用于预测每个短信服务的详细信息:

起初我认为这很简单,我只需要使用COUNT(Case when ...)
但就我而言,我有数千个短信号码(服务),所以如果我使用这种方法,它会是这样的:-

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 个条件时,上述方法不实用?

那么,使用 SMS-ID 对(表 B)上的(表 A)执行left outer join 并计算每个 SMS 状态并进行如下预测的最佳方法是什么?

【问题讨论】:

    标签: sql oracle count pivot


    【解决方案1】:

    我建议条件聚合:

    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

    【讨论】:

    • 谢谢,我会尝试,但我需要表 A 的左外连接,因为有些短信是免费的,表 A 只包含收费的短信,这就是我使用连接的原因。
    • @OsamaAl-Banna。 . .没事儿。您可以使用left join。但您的问题不需要它。
    • 我选择这种方法是因为更简单,适用于其他场景,对我来说不太复杂,我想我也需要了解枢轴。
    【解决方案2】:

    请使用以下查询,

    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 ;
    

    【讨论】:

      【解决方案3】:

      您可以对那些status 列使用PIVOT 子句(在Oracle 11g 版本中引入):

      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就够了。

      Demo

      【讨论】:

      • 感谢 Barbaros Özhan,我会尝试,但我需要与表 A 的表左外连接,因为有些短信是免费的,表 A 只包含收费的短信,这就是我使用连接的原因。
      • 不客气@OsamaAl-Banna,但需要根据需要扩展输出集并通过编辑来详细说明问题。
      猜你喜欢
      • 2021-09-07
      • 2021-07-31
      • 2019-11-29
      • 2013-02-26
      • 2019-11-23
      • 1970-01-01
      • 2018-05-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多