Oracle递归查询 - 日期

时间:2015-01-27 19:30:57

标签: oracle

我已经将两组日期传递到查询中,我想查找两组日期之间的所有月份/年份。

当我尝试这个时:

WITH CTE_Dates (cte_date)  AS (
    SELECT cast(date '2014-01-27' as date)  from dual
    UNION ALL
    SELECT cast(ADD_MONTHS(TRUNC(cte_date, 'MONTH'),1) as date)
    FROM CTE_Dates
    WHERE ( TO_DATE(ADD_MONTHS(TRUNC(cte_date, 'MONTH'), 1)) BETWEEN TO_DATE ('27-01-2014','DD-MM-YYYY') AND TO_DATE ('27-04-2014','DD-MM-YYYY'))
        OR
          ( TO_DATE(ADD_MONTHS(TRUNC(cte_date, 'MONTH'), 1)) BETWEEN TRUNC(TO_DATE('27-11-2014','DD-MM-YYYY'), 'MONTH')  AND TO_DATE ('27-01-2015','DD-MM-YYYY'))
      )
SELECT * from CTE_Dates

我明白了:

27-JAN-14
01-FEB-14
01-MAR-14
01-APR-14

我也想得到:

01-NOV-14
01-DEC-14
01-JAN-15

看起来WHERE子句的OR部分被忽略。

有关如何创建此查询的建议?

由于 科里

1 个答案:

答案 0 :(得分:0)

现在你遇到的问题(除了额外的cast()to_date()调用之外)是在第四次迭代时两个条件都是假的,所以递归停止了;什么都没有让它跳过一点然后再次回升,否则它会永远持续下去。我不认为你可以在递归中实现两个范围。

您可以在递归部分中放置所需的最新日期,然后过滤后想要的两个范围:

WITH CTE_Dates (cte_date)  AS (
    SELECT date '2014-01-27'  from dual
    UNION ALL
    SELECT ADD_MONTHS(TRUNC(cte_date, 'MONTH'), 1)
    FROM CTE_Dates
    WHERE ADD_MONTHS(TRUNC(cte_date, 'MONTH'), 1) <= date '2015-01-27'
)
SELECT * from CTE_Dates
WHERE cte_date BETWEEN date '2014-01-27' AND date '2014-04-27'
OR cte_date BETWEEN date '2014-11-27' AND date '2015-01-27';

CTE_DATE 
---------
27-JAN-14 
01-FEB-14 
01-MAR-14 
01-APR-14 
01-DEC-14 
01-JAN-15 

 6 rows selected 

您可以将硬编码值替换为您的开始日期和结束日期对。如果范围可能重叠或第二个范围可能(或结束)在第一个范围之前,您可以选择更高的日期:

    WHERE ADD_MONTHS(TRUNC(cte_date, 'MONTH'), 1)
      <= greatest(date '2015-01-27', date '2014-04-27')

......虽然这只对变量有意义,而不是固定值。