如何在 Oracle 12c 中不使用 DISTINCT 函数重写查询

How to re-write the query without using DISTINCT function in Oracle 12c

不使用 DISTINCT 函数,如何实现相同的结果。
TAB_C = 2947109424 行,实际 = 43460 行

    SELECT tc.email_addr_id 
                                 , COUNT(DISTINCT tc.m_act_id) AS num_12mons 
                                 , COUNT(DISTINCT CASE WHEN ROUND(tc.outbound_date, 'DD')  
                                     > (ROUND(sysdate, 'DD') - 90) 
                                     THEN tc.m_act_id ELSE NULL END) AS num_3mons 
                                  , COUNT(DISTINCT CASE WHEN ROUND(tc.outbound_date, 'DD')  
                                      > (ROUND(sysdate, 'DD') - 180) 
                                      THEN tc.m_act_id ELSE NULL END) AS num_6mons 
                                  , COUNT(DISTINCT CASE WHEN ROUND(tc.outbound_date, 'DD')  
                                      > (ROUND(sysdate, 'DD') - 270) 
                                      THEN tc.m_act_id ELSE NULL END) AS num_9mons 
                             FROM Tab_C tc     
                             INNER JOIN act a 
                             ON tc.act_id = a.act_id 
                             where a.channel_code IN ('FM','RM') 
                                 AND ROUND(tc.outbound_date, 'DD') > (ROUND(sysdate, 'DD') - 365) 
                             GROUP BY tc.email_addr_id

NULLIF 应该比 CASE 语句快得多,您可能会发现是 CASE 导致了速度变慢而不是明显……但这都是由于您的索引。 NULLIF 显然只在找到正确值的基础上起作用,而不是排除“错误”值,所以你必须反向搜索。

这个可能效果更好,但您需要仔细检查结果。

select email_addr_id,
    count(m_act_id) AS num_12mons,
    COUNT(nullif(sign(outbound_date +90 - ROUND(sysdate, 'DD')), -1))) AS num_3mons,
    COUNT(nullif(sign(outbound_date +180 - ROUND(sysdate, 'DD')), -1))) AS num_6mons,
    COUNT(nullif(sign(outbound_date +270 - ROUND(sysdate, 'DD')), -1))) AS num_9mons
from (
select distinct tc.email_addr_id, tc.m_act_id, round(tc.outbound_date, 'DD') as outbound_date
  from Tab_C tc     
  INNER JOIN act a ON tc.act_id = a.act_id 
  where a.channel_code IN ('FM','RM') 
    AND ROUND(tc.outbound_date, 'DD') > (ROUND(sysdate, 'DD') - 365))
group by email_addr_id;