Oracle Connect By和Date Ranges的问题

时间:2017-04-06 14:25:49

标签: oracle

假设我有一个包含数据范围的表

create table ranges (id number, date_from date, date_to date);
insert into ranges values (1, to_date('01.01.2017', 'dd.mm.rrrr'), to_date('03.01.2017', 'dd.mm.rrrr'));
insert into ranges values (2, to_date('05.02.2017', 'dd.mm.rrrr'), to_date('08.02.2017', 'dd.mm.rrrr'));

,对于这些范围内的每个日期,我的输出应为一行

id | the_date
----------------
1  | 01.01.2017
1  | 02.01.2017
1  | 03.01.2017
2  | 05.02.2017
2  | 06.02.2017
2  | 07.02.2017
2  | 08.02.2017

但是通过连接给我ORA-01436通过循环连接

SELECT connect_by_root(id), Trunc(date_from, 'dd') + LEVEL - 1 AS the_date
FROM ranges
CONNECT BY PRIOR id = id AND Trunc(date_from, 'dd') + LEVEL - 1 <= Trunc(date_to, 'dd')
ORDER BY id, the_date

怎么了?

1 个答案:

答案 0 :(得分:3)

您可以添加对非确定性函数的调用,例如

AND PRIOR dbms_random.value IS NOT NULL

所以它变成了:

SELECT connect_by_root(id), Trunc(date_from, 'dd') + LEVEL - 1 AS the_date
FROM ranges
CONNECT BY PRIOR id = id
AND PRIOR dbms_random.value IS NOT NULL
AND Trunc(date_from, 'dd') + LEVEL - 1 <= Trunc(date_to, 'dd')
ORDER BY id, the_date;

CONNECT_BY_ROOT(ID) THE_DATE 
------------------- ---------
                  1 01-JAN-17
                  1 02-JAN-17
                  1 03-JAN-17
                  2 05-FEB-17
                  2 06-FEB-17
                  2 07-FEB-17
                  2 08-FEB-17

7 rows selected. 

解释为什么有必要in this Oracle Community post;使用sys_guid()代替dbms_random.value,但原则是相同的。

如果您使用的是11gR2或更高,则可以使用recursive subquery factoring代替:

WITH rcte (root_id, the_date, date_to) AS (
  SELECT id, date_from, date_to
  FROM ranges
  UNION ALL
  SELECT root_id, the_date + 1, date_to
  FROM rcte
  WHERE the_date < date_to
)
SELECT root_id, the_date
FROM rcte
ORDER BY root_id, the_date;

   ROOT_ID THE_DATE 
---------- ---------
         1 01-JAN-17
         1 02-JAN-17
         1 03-JAN-17
         2 05-FEB-17
         2 06-FEB-17
         2 07-FEB-17
         2 08-FEB-17

7 rows selected.