使用 CTE Oracle 生成日期范围
Generate range of dates using CTE Oracle
我想在 Oracle 中使用递归 WITH 子句生成两个不同日期之间的天数范围。
WITH CTE_Dates (cte_date) AS
( SELECT CAST(TO_DATE('10-02-2017', 'DD-MM-YYYY') AS DATE) cte_date FROM dual
UNION ALL
SELECT CAST( (cte_date + 1) AS DATE) cte_date
FROM CTE_Dates
WHERE TRUNC(cte_date) + 1 <= TO_DATE('20-02-2017', 'DD-MM-YYYY')
)
SELECT * FROM CTE_Dates
返回结果与预期完全不同:
10-02-2017
09-02-2017
08-02-2017
07-02-2017
06-02-2017
... (unlimited)
预期结果:
10-02-2017
11-02-2017
...
19-02-2017
20-02-2017
Oracle 数据库 11g 快捷版版本 11.2.0.2.0 - 64 位生产。
编辑:
据我了解,这是 Oracle 中的一个已知错误,该错误存在于 Oracle 11.2.0.2 中,并已在 11.2.0.3 中修复。
备选方案:
SELECT TRUNC (TO_DATE('10-02-2017', 'DD-MM-YYYY') + ROWNUM -1) dt
FROM DUAL
CONNECT BY ROWNUM <= (TO_DATE('20-02-2017', 'DD-MM-YYYY') - (TO_DATE('10-02-2017', 'DD-MM-YYYY')))
您不需要递归 WITH 子句,您只需要 table 其中行数 > 您要生成的日期数:
WITH
dates
AS
(SELECT
TO_DATE('10-02-2017', 'DD-MM-YYYY') + (rownum - 1)
FROM
all_tables
WHERE 1=1
AND rownum < (TO_DATE('20-02-2017', 'DD-MM-YYYY') - TO_DATE('10-02-2017', 'DD-MM-YYYY')) + 2
)
SELECT
*
FROM
dates
除非您确实需要使用 WITH 子句,否则还有另一种解决方案可以通过使用 CONNECT BY 子句获得预期结果。
SELECT TO_DATE('10-02-2017', 'DD-MM-YYYY') AS date_range
FROM dual
UNION ALL
SELECT TO_DATE('10-02-2017', 'DD-MM-YYYY') + LEVEL
FROM dual
CONNECT BY LEVEL <= (TO_DATE('20-02-2017', 'DD-MM-YYYY') - TO_DATE('10-02-2017', 'DD-MM-YYYY'));
这是 Oracle 11 中递归 CTE 中的一个已知错误(特别是关于日期算法)。已在 Oracle 12 中修复。正是这种行为:无论您在代码中添加还是减去,引擎总是减去,它从不添加。
编辑:实际上,正如 Alex Poole 在对原始 post 的评论中指出的那样,该错误存在于 Oracle 11.2.0.2 中,并已在 11.2 中修复.0.3。 结束编辑
唉,我不是付费客户,所以我不能引用章节和诗句,但是通过一点谷歌搜索你会找到指向这个的链接(包括在 OTN 上,我参与了一些讨论这个话题的话题和递归 CTE 中的其他错误 - 一些已修复,一些仍然是 Oracle 12.1 中的错误)。
已添加 - 这是其中一个讨论:https://community.oracle.com/thread/3974408
也许递归的逆序解决了问题:
with cte_dates (cte_date) as (
select cast(to_date('20-02-2017', 'DD-MM-YYYY') as date) cte_date from dual
union all
select cast((cte_date - 1) as date) cte_date
from cte_dates
where cast(cte_date as date) > to_date('10-02-2017', 'DD-MM-YYYY')
)
select * from cte_dates
order by cte_date
;
2017-02-10
2017-02-11
2017-02-12
...
2017-02-18
2017-02-19
2017-02-20
注意:由于 RCTE 在 11gR2 中的另一个错误
,因此将日期投射为需要的日期
Old discussion here
我想在 Oracle 中使用递归 WITH 子句生成两个不同日期之间的天数范围。
WITH CTE_Dates (cte_date) AS
( SELECT CAST(TO_DATE('10-02-2017', 'DD-MM-YYYY') AS DATE) cte_date FROM dual
UNION ALL
SELECT CAST( (cte_date + 1) AS DATE) cte_date
FROM CTE_Dates
WHERE TRUNC(cte_date) + 1 <= TO_DATE('20-02-2017', 'DD-MM-YYYY')
)
SELECT * FROM CTE_Dates
返回结果与预期完全不同:
10-02-2017
09-02-2017
08-02-2017
07-02-2017
06-02-2017
... (unlimited)
预期结果:
10-02-2017
11-02-2017
...
19-02-2017
20-02-2017
Oracle 数据库 11g 快捷版版本 11.2.0.2.0 - 64 位生产。
编辑: 据我了解,这是 Oracle 中的一个已知错误,该错误存在于 Oracle 11.2.0.2 中,并已在 11.2.0.3 中修复。
备选方案:
SELECT TRUNC (TO_DATE('10-02-2017', 'DD-MM-YYYY') + ROWNUM -1) dt
FROM DUAL
CONNECT BY ROWNUM <= (TO_DATE('20-02-2017', 'DD-MM-YYYY') - (TO_DATE('10-02-2017', 'DD-MM-YYYY')))
您不需要递归 WITH 子句,您只需要 table 其中行数 > 您要生成的日期数:
WITH
dates
AS
(SELECT
TO_DATE('10-02-2017', 'DD-MM-YYYY') + (rownum - 1)
FROM
all_tables
WHERE 1=1
AND rownum < (TO_DATE('20-02-2017', 'DD-MM-YYYY') - TO_DATE('10-02-2017', 'DD-MM-YYYY')) + 2
)
SELECT
*
FROM
dates
除非您确实需要使用 WITH 子句,否则还有另一种解决方案可以通过使用 CONNECT BY 子句获得预期结果。
SELECT TO_DATE('10-02-2017', 'DD-MM-YYYY') AS date_range
FROM dual
UNION ALL
SELECT TO_DATE('10-02-2017', 'DD-MM-YYYY') + LEVEL
FROM dual
CONNECT BY LEVEL <= (TO_DATE('20-02-2017', 'DD-MM-YYYY') - TO_DATE('10-02-2017', 'DD-MM-YYYY'));
这是 Oracle 11 中递归 CTE 中的一个已知错误(特别是关于日期算法)。已在 Oracle 12 中修复。正是这种行为:无论您在代码中添加还是减去,引擎总是减去,它从不添加。
编辑:实际上,正如 Alex Poole 在对原始 post 的评论中指出的那样,该错误存在于 Oracle 11.2.0.2 中,并已在 11.2 中修复.0.3。 结束编辑
唉,我不是付费客户,所以我不能引用章节和诗句,但是通过一点谷歌搜索你会找到指向这个的链接(包括在 OTN 上,我参与了一些讨论这个话题的话题和递归 CTE 中的其他错误 - 一些已修复,一些仍然是 Oracle 12.1 中的错误)。
已添加 - 这是其中一个讨论:https://community.oracle.com/thread/3974408
也许递归的逆序解决了问题:
with cte_dates (cte_date) as (
select cast(to_date('20-02-2017', 'DD-MM-YYYY') as date) cte_date from dual
union all
select cast((cte_date - 1) as date) cte_date
from cte_dates
where cast(cte_date as date) > to_date('10-02-2017', 'DD-MM-YYYY')
)
select * from cte_dates
order by cte_date
;
2017-02-10
2017-02-11
2017-02-12
...
2017-02-18
2017-02-19
2017-02-20
注意:由于 RCTE 在 11gR2 中的另一个错误
,因此将日期投射为需要的日期Old discussion here