我正在查询根据项目的预测预算检索“未来月份”。
基本上我正在考虑最后一个预测日期(START_DATE)以及我希望将预测发布到(END_DATE)的未来日期,所以我需要填写几个月之间的所有内容。
通过一些研究,我发现“CONNECT BY”可以提供很多帮助。
简单地说,查询看起来像这样:
SELECT TO_CHAR (ADD_MONTHS (START_DATE, LEVEL - 1), 'fmMonth')
FROM (SELECT PROJECT_ID, FORECAST_VALUE, START_DATE, END_DATE
FROM PROJECTS
WHERE PROJECT_ID = 001)
CONNECT BY LEVEL <=
MONTHS_BETWEEN (TRUNC (END_DATE, 'MM'),
TRUNC (START_DATE, 'MM')
)
* +1
在选择一个项目时,查询工作得很好,但是当选择多个或所有项目/行时,查询会中断并返回比预期更多的行。
源数据看起来像这样:
PROJECT_ID | FORECAST_VALUE | START_DATE | END_DATE
-----------+----------------+------------+-----------
001 | 100 | 2017-01-01 | 2017-03-01
002 | 200 | 2017-01-01 | 2017-05-01
003 | 200 | 2017-10-01 | 2018-01-01
我期望看到的是这样的
PROJECT_ID | FORECAST_VALUE | FORECAST_YEAR | FORECAST_MONTH
-----------+----------------+---------------+-----------
001 | 100 | 2017 | JANUARY
001 | 100 | 2017 | FEBRUARY
001 | 100 | 2017 | MARCH
002 | 200 | 2017 | JANUARY
002 | 200 | 2017 | FEBRUARY
002 | 200 | 2017 | MARCH
002 | 200 | 2017 | APRIL
002 | 200 | 2017 | MAY
003 | 200 | 2017 | OCTOBER
003 | 200 | 2017 | NOVEMBER
003 | 200 | 2017 | DECEMBER
003 | 200 | 2018 | JANUARY
然而,我得到了比预期更多的月份和年份。
我该如何解决这个问题?
谢谢!
答案 0 :(得分:1)
由于您没有放入CONNECT BY
中的条件以外的条件,因此每个级别的每一行都会在下一级生成更多行(每个级别都没有跟踪每个PROJECT_ID
)。您需要按PROJECT_ID = PRIOR PROJECT_ID
链接行。但这会导致“周期”; CONNECT BY...
仅通过查看受PRIOR
运算符影响的列来检测周期,而不是查看所有列。您可以通过添加不相关的PRIOR
条件来中断周期,该条件将保证不同行的不同值;传统上SYS_GUID()
用于此。
按如下方式修改您的查询:
SELECT TO_CHAR (ADD_MONTHS (START_DATE, LEVEL - 1), 'fmMonth')
FROM (SELECT PROJECT_ID, FORECAST_VALUE, START_DATE, END_DATE
FROM PROJECTS
WHERE PROJECT_ID = 001)
CONNECT BY LEVEL <=
MONTHS_BETWEEN (TRUNC (END_DATE, 'MM'),
TRUNC (START_DATE, 'MM')
)
* +1 -- whatever that means (copied from original post)
AND PROJECT_ID = PRIOR PROJECT_ID
AND PRIOR SYS_GUID() IS NOT NULL
当然,我假设PROJECT_ID
是基表PROJECTS
中的唯一键(可能是主键?)。
答案 1 :(得分:0)
一种简单的方法可能是将您的表格与数字表联系起来,假设您的时间不超过1000个月:
select PROJECT_ID, FORECAST_VALUE, START_DATE, END_DATE, TO_CHAR (ADD_MONTHS (START_DATE, num - 1), 'fmMonth')
from PROJECTS
inner join (
select level as num
from dual
connect by level <= 1000
) nums
on (num -1 <= months_between( TRUNC (END_DATE, 'MM'),
TRUNC (START_DATE, 'MM')) )
order by 1, num
答案 2 :(得分:0)
这是一种方法。我们只需使用最小export interface MyDate{
time: string;
milliseconds_since_epoch: number;
date: string;
}
export class AppComponent{
private data :MyDate = {}; // initialise the data here
}
getDatas() :Observable<MyDate>{
//return this._http.get('/app/test.json')
return this._http.get('http://date.jsontest.com')
.map(res => res.json());
}
和最大start_date
并生成其中的所有内容,然后加入我们的end_date
表。
projects
结果:
create table projects(project_id, forecast_value, start_date, end_date) as(
select 001, 100, date '2017-01-01', date '2017-03-01' from dual union all
select 002, 200, date '2017-01-01', date '2017-05-01' from dual union all
select 003, 200, date '2017-10-01', date '2018-01-01' from dual
);
with
dates(dt) as(
select add_months(s_date, level - 1) as dt
from (
select min(start_date) as s_date
, max(end_date) as e_date
from projects
)
connect by add_months(s_date , level - 1) <= e_date
)
select p.project_id
, p.forecast_value
, extract(year from d.dt) as forcast_year
, to_char(d.dt, 'MONTH') as forecast_month
from projects p
join dates d
on (trunc(d.dt, 'mm') between trunc(p.start_date, 'mm')
and trunc(p.end_date, 'mm'))
order by p.project_id, d.dt