如何在 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;
不使用 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;