如何动态使用connect by method
how to use connect by method dynamically
如何实现如下
我有一个问题:
select sr.source_rel_id,
sr.source_rel_start,
sr.source_rel_end,
sr.source_rel_end-sr.source_rel_start+ 1 as daycount
from (SELECT RELEASES.REL_ID as source_rel_id,
RELEASES.REL_START_DATE as source_rel_start,
RELEASES.REL_END_DATE as source_rel_end
FROM RELEASES) sr
结果如下:
我正在尝试创建一个额外的列(基于所附的屏幕截图),其中填充了给定开始和结束间隔之间递增的日期。
这是我想要完成的:
右边的数字表示每个ID应该生成多少条记录。
抱歉我的英语不好,我希望它是可以理解的。
这基本上是一个生成行的连接查询,例如生成从 1 到 10 的行使用:
select level as x
from dual connect by level <= 10;
| X |
|----|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
为了生成从 5 到 10 的行,使用:
select 5 + level - 1 as x
from dual connect by level <= 10 - 5 + 1;
| X |
|----|
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
为了生成从 2017-01-02
到 2017-01-05
的日期,请使用:
select date '2017-01-02' + level - 1 as x
from dual connect by level <= date '2017-01-05' - date '2017-01-02' + 1;
| X |
|----------------------|
| 2017-01-02T00:00:00Z |
| 2017-01-03T00:00:00Z |
| 2017-01-04T00:00:00Z |
| 2017-01-05T00:00:00Z |
如果您使用的是 Oracle 12c,那么您可以使用 LATERAL 或 CROSSAPPLY 来 运行 后一个生成器查询形成许多来自源子查询或 table 的开始+结束值,请考虑以下示例:
create table probe(
source_rel_id int,
source_rel_start date,
source_rel_end date
);
insert into probe values( 1, date '2017-01-02', date '2017-01-05' );
insert into probe values( 2, date '2017-03-01', date '2017-03-15' );
insert into probe values( 3, date '2017-05-05', date '2017-05-30' );
commit;
select * from probe p
cross apply (
select p.source_rel_start + level - 1 as my_date
from dual connect by level <= p.source_rel_end - p.source_rel_start + 1
)
SOURCE_REL_ID SOURCE_REL_START SOURCE_REL_END MY_DATE
------------- ---------------- ---------------- ----------------
1 2017/01/02 00:00 2017/01/05 00:00 2017/01/02 00:00
1 2017/01/02 00:00 2017/01/05 00:00 2017/01/03 00:00
1 2017/01/02 00:00 2017/01/05 00:00 2017/01/04 00:00
1 2017/01/02 00:00 2017/01/05 00:00 2017/01/05 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/01 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/02 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/03 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/04 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/05 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/06 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/07 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/08 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/09 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/10 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/11 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/12 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/13 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/14 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/15 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/05 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/06 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/07 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/08 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/09 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/10 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/11 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/12 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/13 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/14 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/15 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/16 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/17 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/18 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/19 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/20 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/21 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/22 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/23 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/24 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/25 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/26 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/27 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/28 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/29 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/30 00:00
编辑
What other options I've got, if I'm not having 12c? I should check the
version but I remember for 11.
只需生成1到N的一系列数字,其中N必须大于你要为一条记录生成的数字的最大数量,这样:
SELECT level as xyz FROM dual
CONNECT BY LEVEL <= 10000
然后以这种方式将上述查询的结果加入到 table --> 请参阅 this demo
SELECT source_rel_id, source_rel_start, source_rel_end,
source_rel_start + xyz - 1 As days
FROM (
SELECT level as xyz FROM dual
CONNECT BY LEVEL <= 10000
) x
JOIN probe p
ON xyz <= source_rel_end - source_rel_start + 1
ORDER BY source_rel_id, days
| SOURCE_REL_ID | SOURCE_REL_START | SOURCE_REL_END | DAYS |
|---------------|----------------------|----------------------|----------------------|
| 1 | 2017-01-02T00:00:00Z | 2017-01-05T00:00:00Z | 2017-01-02T00:00:00Z |
| 1 | 2017-01-02T00:00:00Z | 2017-01-05T00:00:00Z | 2017-01-03T00:00:00Z |
| 1 | 2017-01-02T00:00:00Z | 2017-01-05T00:00:00Z | 2017-01-04T00:00:00Z |
| 1 | 2017-01-02T00:00:00Z | 2017-01-05T00:00:00Z | 2017-01-05T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-01T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-02T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-03T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-04T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-05T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-06T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-07T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-08T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-09T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-10T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-11T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-12T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-13T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-14T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-15T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-05T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-06T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-07T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-08T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-09T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-10T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-11T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-12T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-13T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-14T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-15T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-16T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-17T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-18T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-19T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-20T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-21T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-22T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-23T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-24T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-25T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-26T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-27T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-28T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-29T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-30T00:00:00Z |
我用了 10000,应该够用了,因为 10000 天已经超过 27 年了,所以我认为你不需要为每条记录生成 27 年的日期,但如果这仍然太少,那么实际上,它可以是 100 万到 1000 万之间的某个数字。由于行是在内存中生成的,在某些时候(1~1000 万)你会遇到内存不足的错误。
您还可以使用子查询来精确计算此限制:
SELECT level as xyz FROM dual
CONNECT BY LEVEL <= (
SELECT max( source_rel_end - source_rel_start ) + 1
FROM probe
)
如果您仍在使用 Oracle 11g(在评论中建议),您可以使用 connect by
分层查询来执行此操作,但是因为您是从多个源行获取数据,所以您需要包含一个引用一个非确定性函数(我用过 `dbms_random.value 但其他函数可用...)来防止:
select rel_id as source_rel_id,
rel_start_date + level - 1 as days,
rel_end_date - rel_start_date + 1 as daycount
from releases
connect by rel_id = prior rel_id
and prior dbms_random.value is not null
and level <= rel_end_date - rel_start_date + 1;
仅使用示例数据的前三行,结果集中有 92 行:
SOURCE_REL_ID DAYS DAYCOUNT
------------- ---------- ----------
68 2016-03-01 31
68 2016-03-02 31
68 2016-03-03 31
...
68 2016-03-30 31
68 2016-03-31 31
71 2016-06-01 30
71 2016-06-02 30
...
71 2016-06-29 30
71 2016-06-30 30
73 2016-08-01 31
73 2016-08-02 31
...
73 2016-08-30 31
73 2016-08-31 31
如果您使用的是 11gR2(或更高版本),您还可以使用 recursive subquery factoring a.k.a 递归 CTE:
with rcte (source_rel_id, rel_end_date, days, daycount) as (
select rel_id, rel_end_date, rel_start_date, rel_end_date - rel_start_date + 1
from releases
union all
select source_rel_id, rel_end_date, days + 1, daycount
from rcte
where days < rel_end_date
)
select source_rel_id, days, daycount
from rcte
order by source_rel_id, days;
得到相同的结果 - 除了明确排序,这可能不是一件坏事。
CTE 的锚分支从您的基础 table 获取数据并添加两个额外的列:daycount
与之前计算相同,days
与第一组行的开始日期。 rel_end_date
需要对递归分支可用,以便包含在内,但可以跳过 rel_start_date
。
然后递归分支将 days
添加一天,直到到达结束日期。如果上一个生成行的 days
值已经是 rel_end_date
则不满足条件,因此它停止,对于该源行。
最后您只查询您希望从 CTE 中看到的列 - 在这种情况下,只排除为提供停止条件而传递的 rel_end_date
,但您实际上并不想这样做见。
如何实现如下
我有一个问题:
select sr.source_rel_id,
sr.source_rel_start,
sr.source_rel_end,
sr.source_rel_end-sr.source_rel_start+ 1 as daycount
from (SELECT RELEASES.REL_ID as source_rel_id,
RELEASES.REL_START_DATE as source_rel_start,
RELEASES.REL_END_DATE as source_rel_end
FROM RELEASES) sr
结果如下:
我正在尝试创建一个额外的列(基于所附的屏幕截图),其中填充了给定开始和结束间隔之间递增的日期。
这是我想要完成的:
右边的数字表示每个ID应该生成多少条记录。
抱歉我的英语不好,我希望它是可以理解的。
这基本上是一个生成行的连接查询,例如生成从 1 到 10 的行使用:
select level as x
from dual connect by level <= 10;
| X |
|----|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
为了生成从 5 到 10 的行,使用:
select 5 + level - 1 as x
from dual connect by level <= 10 - 5 + 1;
| X |
|----|
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
为了生成从 2017-01-02
到 2017-01-05
的日期,请使用:
select date '2017-01-02' + level - 1 as x
from dual connect by level <= date '2017-01-05' - date '2017-01-02' + 1;
| X |
|----------------------|
| 2017-01-02T00:00:00Z |
| 2017-01-03T00:00:00Z |
| 2017-01-04T00:00:00Z |
| 2017-01-05T00:00:00Z |
如果您使用的是 Oracle 12c,那么您可以使用 LATERAL 或 CROSSAPPLY 来 运行 后一个生成器查询形成许多来自源子查询或 table 的开始+结束值,请考虑以下示例:
create table probe(
source_rel_id int,
source_rel_start date,
source_rel_end date
);
insert into probe values( 1, date '2017-01-02', date '2017-01-05' );
insert into probe values( 2, date '2017-03-01', date '2017-03-15' );
insert into probe values( 3, date '2017-05-05', date '2017-05-30' );
commit;
select * from probe p
cross apply (
select p.source_rel_start + level - 1 as my_date
from dual connect by level <= p.source_rel_end - p.source_rel_start + 1
)
SOURCE_REL_ID SOURCE_REL_START SOURCE_REL_END MY_DATE
------------- ---------------- ---------------- ----------------
1 2017/01/02 00:00 2017/01/05 00:00 2017/01/02 00:00
1 2017/01/02 00:00 2017/01/05 00:00 2017/01/03 00:00
1 2017/01/02 00:00 2017/01/05 00:00 2017/01/04 00:00
1 2017/01/02 00:00 2017/01/05 00:00 2017/01/05 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/01 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/02 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/03 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/04 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/05 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/06 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/07 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/08 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/09 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/10 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/11 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/12 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/13 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/14 00:00
2 2017/03/01 00:00 2017/03/15 00:00 2017/03/15 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/05 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/06 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/07 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/08 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/09 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/10 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/11 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/12 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/13 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/14 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/15 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/16 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/17 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/18 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/19 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/20 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/21 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/22 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/23 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/24 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/25 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/26 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/27 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/28 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/29 00:00
3 2017/05/05 00:00 2017/05/30 00:00 2017/05/30 00:00
编辑
What other options I've got, if I'm not having 12c? I should check the version but I remember for 11.
只需生成1到N的一系列数字,其中N必须大于你要为一条记录生成的数字的最大数量,这样:
SELECT level as xyz FROM dual
CONNECT BY LEVEL <= 10000
然后以这种方式将上述查询的结果加入到 table --> 请参阅 this demo
SELECT source_rel_id, source_rel_start, source_rel_end,
source_rel_start + xyz - 1 As days
FROM (
SELECT level as xyz FROM dual
CONNECT BY LEVEL <= 10000
) x
JOIN probe p
ON xyz <= source_rel_end - source_rel_start + 1
ORDER BY source_rel_id, days
| SOURCE_REL_ID | SOURCE_REL_START | SOURCE_REL_END | DAYS |
|---------------|----------------------|----------------------|----------------------|
| 1 | 2017-01-02T00:00:00Z | 2017-01-05T00:00:00Z | 2017-01-02T00:00:00Z |
| 1 | 2017-01-02T00:00:00Z | 2017-01-05T00:00:00Z | 2017-01-03T00:00:00Z |
| 1 | 2017-01-02T00:00:00Z | 2017-01-05T00:00:00Z | 2017-01-04T00:00:00Z |
| 1 | 2017-01-02T00:00:00Z | 2017-01-05T00:00:00Z | 2017-01-05T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-01T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-02T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-03T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-04T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-05T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-06T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-07T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-08T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-09T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-10T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-11T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-12T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-13T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-14T00:00:00Z |
| 2 | 2017-03-01T00:00:00Z | 2017-03-15T00:00:00Z | 2017-03-15T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-05T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-06T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-07T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-08T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-09T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-10T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-11T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-12T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-13T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-14T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-15T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-16T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-17T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-18T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-19T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-20T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-21T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-22T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-23T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-24T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-25T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-26T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-27T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-28T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-29T00:00:00Z |
| 3 | 2017-05-05T00:00:00Z | 2017-05-30T00:00:00Z | 2017-05-30T00:00:00Z |
我用了 10000,应该够用了,因为 10000 天已经超过 27 年了,所以我认为你不需要为每条记录生成 27 年的日期,但如果这仍然太少,那么实际上,它可以是 100 万到 1000 万之间的某个数字。由于行是在内存中生成的,在某些时候(1~1000 万)你会遇到内存不足的错误。
您还可以使用子查询来精确计算此限制:
SELECT level as xyz FROM dual
CONNECT BY LEVEL <= (
SELECT max( source_rel_end - source_rel_start ) + 1
FROM probe
)
如果您仍在使用 Oracle 11g(在评论中建议),您可以使用 connect by
分层查询来执行此操作,但是因为您是从多个源行获取数据,所以您需要包含一个引用一个非确定性函数(我用过 `dbms_random.value 但其他函数可用...)来防止:
select rel_id as source_rel_id,
rel_start_date + level - 1 as days,
rel_end_date - rel_start_date + 1 as daycount
from releases
connect by rel_id = prior rel_id
and prior dbms_random.value is not null
and level <= rel_end_date - rel_start_date + 1;
仅使用示例数据的前三行,结果集中有 92 行:
SOURCE_REL_ID DAYS DAYCOUNT
------------- ---------- ----------
68 2016-03-01 31
68 2016-03-02 31
68 2016-03-03 31
...
68 2016-03-30 31
68 2016-03-31 31
71 2016-06-01 30
71 2016-06-02 30
...
71 2016-06-29 30
71 2016-06-30 30
73 2016-08-01 31
73 2016-08-02 31
...
73 2016-08-30 31
73 2016-08-31 31
如果您使用的是 11gR2(或更高版本),您还可以使用 recursive subquery factoring a.k.a 递归 CTE:
with rcte (source_rel_id, rel_end_date, days, daycount) as (
select rel_id, rel_end_date, rel_start_date, rel_end_date - rel_start_date + 1
from releases
union all
select source_rel_id, rel_end_date, days + 1, daycount
from rcte
where days < rel_end_date
)
select source_rel_id, days, daycount
from rcte
order by source_rel_id, days;
得到相同的结果 - 除了明确排序,这可能不是一件坏事。
CTE 的锚分支从您的基础 table 获取数据并添加两个额外的列:daycount
与之前计算相同,days
与第一组行的开始日期。 rel_end_date
需要对递归分支可用,以便包含在内,但可以跳过 rel_start_date
。
然后递归分支将 days
添加一天,直到到达结束日期。如果上一个生成行的 days
值已经是 rel_end_date
则不满足条件,因此它停止,对于该源行。
最后您只查询您希望从 CTE 中看到的列 - 在这种情况下,只排除为提供停止条件而传递的 rel_end_date
,但您实际上并不想这样做见。