我要求根据收入贡献期限让一个月内的客户活跃。
原始数据:
ACCOUNT_ID REVENUE_START_DATE REVENUE_END_DATE
1234 1/14/2010 0:00 4/13/2010 23:59
4567 2/9/2010 0:00 3/8/2010 23:59
1234 5/9/2010 0:00 6/8/2010 23:59
预期结果
Month Count
Dec-09 0
Jan-10 1
Feb-10 2
Mar-10 2
Apr-10 1
May-10 1
Jun-10 1
Jul-10 0
Aug-10 0
Sep-10
Oct-10
下面是我工作的oracle代码(在google的帮助下),但由于日期重叠,我得不到正确的结果。我请专家帮我解决这个问题。 (先谢谢)
当前结果:
YEAR_ MONTH_ ACT
2010 January 2
2010 February 3
2010 March 3
2010 April 3
ORACLE CODE:
with tab as
(
select distinct ACCOUNT_ID, billing_start_date as revenue_start_date, billing_end_date as revenue_end_date
from accounts
),
year_tab as
(
select
add_months(min_date, level -1) m
from
(
select min(trunc(revenue_start_date,'YYYY')) min_date, add_months(max(trunc(revenue_end_date,'YYYY')), 12) max_date
from tab
)
connect by level <= months_between(max_date, min_date)
)
select to_char(m,'YYYY') year_,
to_char(m,'Month') month_,
nvl(act, 0) act
from year_tab,
(
select m date_,count(*) act
from tab, year_tab
where m between trunc(revenue_start_date,'MM') and trunc(revenue_end_date,'MM')
group by m
) month_tab
where m = date_(+)
order by m;
答案 0 :(得分:0)
我花了一段时间才知道您认为存在问题的原因。使用您提供的原始三行数据,运行查询可准确提供“预期结果”。使用CSV文件中的54行数据,结果为48行(包括4年),从2010年1月到2013年1月,非零总计。返回的前几行是:
YEAR_ MONTH_ ACT
----- ------------------------------------ ----------
2010 January 2
2010 February 3
2010 March 3
2010 April 3
2010 May 2
但这看起来是正确的:
select * from accounts
where not (billing_start_date > date '2010-02-01'
or billing_end_date < date '2010-01-01');
ACCOUNT_ID BILLING_START_DATE BILLING_END_DATE
---------- ------------------ ------------------
1234 09/01/2010 00:00 08/02/2010 23:59
4567 14/01/2010 00:00 13/04/2010 23:59
2 rows selected
select * from accounts
where not (billing_start_date > date '2010-03-01'
or billing_end_date < date '2010-02-01');
ACCOUNT_ID BILLING_START_DATE BILLING_END_DATE
---------- ------------------ ------------------
1234 09/01/2010 00:00 08/02/2010 23:59
4567 14/01/2010 00:00 13/04/2010 23:59
1234 09/02/2010 00:00 08/03/2010 23:59
3 rows selected
select * from accounts
where not (billing_start_date > date '2010-04-01'
or billing_end_date < date '2010-03-01');
ACCOUNT_ID BILLING_START_DATE BILLING_END_DATE
---------- ------------------ ------------------
4567 14/01/2010 00:00 13/04/2010 23:59
1234 09/02/2010 00:00 08/03/2010 23:59
1234 09/03/2010 00:00 08/04/2010 23:59
3 rows selected
但我认为你想要的并没有在问题中强调:'让客户数量活跃'。假设“客户”是指唯一的帐户ID,您只需要修改计数:
select m date_,count(distinct account_id) act
from tab, year_tab
...
...将前几行显示为:
YEAR_ MONTH_ ACT
----- ------------------------------------ ----------
2010 January 2
2010 February 2
2010 March 2
2010 April 2
2010 May 1
您错误的是尝试在distinct
子查询中应用tab
;但不同的返回不同的行,并且由于日期不同,实际上并没有减少返回的行数。
这仍然与您的预期结果不完全匹配,但似乎与数据匹配(如果我对您想要的假设是正确的),并且仍然确实为您提供了三行样本的预期结果。
编写查询的另一种方法,我发现它更容易理解,并使用ANSI连接语法:
with t as (
select add_months(min_date, level - 1) month_start,
add_months(min_date, level) next_month_start
from (
select trunc(min(billing_start_date),'YYYY') min_date,
add_months(trunc(max(billing_start_date),'YYYY'), 12) max_date
from accounts
)
connect by level <= months_between(max_date, min_date)
)
select to_char(t.month_start,'YYYY') year_,
to_char(t.month_start,'Month') month_,
count(distinct a.account_id) act
from t
left join accounts a on not (billing_start_date > t.next_month_start
or billing_end_date < t.month_start)
group by t.month_start
order by t.month_start;