具有间隔的日期的 Oracle 递归 CTE

Oracle recursive CTE for date with interval

我正在尝试创建一个递归 CTE,它每 10 分钟生成一个 date/time 并在午夜停止,但我在语法上苦苦挣扎,似乎无法让它工作。

如果有人能帮助我,我将不胜感激。在此先感谢所有回答者。


ALTER SESSION SET NLS_DATE_FORMAT = 'MMDDYYYY HH24:MI:SS';


with date_rows 
(( SELECT TO_DATE('2021/08/20 18:30:25', 'YYYY/MM/DD HH24:MI:SS') as start_date  FROM DUAL ) 
union all
select start_date+interval '10' minute
 from date_rows
where start_date < 
TRUNC(start_date) + INTERVAL '1' DAY)
select * from date_rows;

Something like this, I presume.

SQL> with date_rows (datum) as
  2    (select cast (to_date('2021/08/20 18:30:25', 'YYYY/MM/DD HH24:MI:SS') as date)
  3     from dual
  4     union all
  5     select cast (datum + interval '10' minute as date)
  6     from date_rows
  7     where datum < trunc(to_date('2021/08/20 18:30:25', 'YYYY/MM/DD HH24:MI:SS')) + interval '1' day
  8    )
  9  select * from date_rows;

DATUM
-----------------
08202021 18:30:25
08202021 18:40:25
08202021 18:50:25
08202021 19:00:25
08202021 19:10:25
08202021 19:20:25
08202021 19:30:25
08202021 19:40:25
08202021 19:50:25
08202021 20:00:25
08202021 20:10:25
<snip>    
08202021 23:20:25
08202021 23:30:25
08202021 23:40:25
08202021 23:50:25
08212021 00:00:25

34 rows selected.

SQL>

您可以使用:

WITH inputs ( value ) AS (
  SELECT TO_DATE('2021/08/20 18:30:25', 'YYYY/MM/DD HH24:MI:SS')
  FROM   DUAL
),
date_rows ( start_date, end_date ) AS (
  SELECT value,
         TRUNC(value) + INTERVAL '1' DAY
  FROM   inputs
UNION ALL
  SELECT start_date + INTERVAL '10' MINUTE,
         end_date
  FROM   date_rows
  WHERE  start_date + INTERVAL '10' MINUTE < end_date
)
SELECT start_date
FROM   date_rows;

或者,如果你想复制输入值,那么你可以使用:

WITH date_rows ( start_date ) AS (
  SELECT TO_DATE('2021/08/20 18:30:25', 'YYYY/MM/DD HH24:MI:SS')
  FROM   DUAL
UNION ALL
  SELECT start_date + INTERVAL '10' MINUTE
  FROM   date_rows
  WHERE  start_date + INTERVAL '10' MINUTE
           < TRUNC(TO_DATE('2021/08/20 18:30:25', 'YYYY/MM/DD HH24:MI:SS'))
             + INTERVAL '1' DAY
)
SELECT *
FROM   date_rows;

注意:在递归子查询的每次迭代中,start_date 是前一个值,因此您需要检查 start_date + INTERVAL '10' MINUTE 是否在午夜之前(而不仅仅是 start_date) 否则你将在午夜后排到最后一行。

db<>fiddle here


你的代码有什么问题:

  1. 对于非递归子查询分解子句,语法为:

    WITH query_alias AS (
    

    WITH query_alias (column_alias) AS (
    

    您缺少 AS 关键字。

    但是,对于递归子查询分解子句,您需要使用第二个版本并指定列别名。

  2. 第一个 SELECT 周围的 () 括号是多余的(但不会导致错误)。

  3. start_date < TRUNC(start_date) + INTERVAL '1' DAY) 始终为真,即使日期超过了午夜边界;所以查询将无限递归。

db<>fiddle here