Sql 通过返回比预期多的行进行连接
我正在根据项目的预测预算查询未来月份 基本上,我将最后一个预测日期开始日期和未来日期(我希望将预测日期设置为结束日期),因此我需要用月份填充这两个日期之间的所有内容 通过一些研究,我发现“连接方式”可以帮助很多人 简单地说,查询如下所示:Sql 通过返回比预期多的行进行连接,sql,oracle,Sql,Oracle,我正在根据项目的预测预算查询未来月份 基本上,我将最后一个预测日期开始日期和未来日期(我希望将预测日期设置为结束日期),因此我需要用月份填充这两个日期之间的所有内容 通过一些研究,我发现“连接方式”可以帮助很多人 简单地说,查询如下所示: SELECT TO_CHAR (ADD_MONTHS (START_DATE, LEVEL - 1), 'fmMonth') FROM (SELECT PROJECT_ID, FORECAST_VALUE, START_DATE, END_D
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
然而,我得到了比预期多得多的月和年
我怎样才能解决这个问题
谢谢 一个简单的方法是将您的表与数字表连接起来,假设您的时间不超过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
由于除了在“连接方式”中设置的条件外,没有其他条件,因此每一级别的每一行在下一级别生成更多的行,因此每一级别都没有对每个项目ID的跟踪。您需要按PROJECT\u ID=先前的PROJECT\u ID链接行,但这将导致循环;通过…连接。。。通过仅查看受先前运算符影响的列(而不是所有列)来检测周期。您可以通过添加一个不相关的先验条件来打破循环,该条件将保证不同行的不同值;传统上使用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是唯一的键,也许是主键?在基本表项目中。这里有一种方法。我们只需取最小开始日期和最大结束日期,并生成其间的所有内容,然后加入到我们的项目表中
听起来像是简单的数据加密问题。始终发布源数据的样本和所需结果。简单地说。这是我所拥有的,这是我想要的结果,这是我写的问题。@NicholasKrasnov谢谢!刚刚添加到我的问题中。您运行的是什么版本的Oracle?@NicholasKrasnov 11g 11.2.0.4。0@NicholasKrasnov-也许这是一个简单的数据加密问题,但不是OP陈述的方式。在OP的描述中,每个项目的月份不同,仅取决于该项目的第一个月和最后一个月。在数据加密问题中,月份范围是可以同时容纳所有项目的最小范围。
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
PROJECT_ID FORECAST_VALUE FORCAST_YEAR FORECAST_MONTH
---------- -------------- ------------ --------------
1 100 2017 JANUARY
1 100 2017 FEBRUARY
1 100 2017 MARCH
2 200 2017 JANUARY
2 200 2017 FEBRUARY
2 200 2017 MARCH
2 200 2017 APRIL
2 200 2017 MAY
3 200 2017 OCTOBER
3 200 2017 NOVEMBER
3 200 2017 DECEMBER
3 200 2018 JANUARY
12 rows selected.