ORACLE(11.2.0.1.0) - 带有日期表达式的递归CTE

时间:2017-11-28 07:49:52

标签: sql oracle common-table-expression

关于以下问题的正确答案:

  • 如果我没记错的话,那是11.2.0.3或更高版本中修复的错误。 (无论如何不再支持11.2.0.1.11.2.0.4是唯一仍然支持的11.2版本) - @a_horse_with_no_name
  • 错误号是11840579,它在11.2.0.3和12.1.0.1中修复 - @a_horse_with_no_name

问题

我有一张桌子

CREATE TABLE test(
  from_date date,
  to_date date
);

INSERT INTO test(from_date,to_date)
--VALUES('20171101','20171115');
VALUES(TO_DATE('20171101','YYYYMMDD'),TO_DATE('20171115','YYYYMMDD'));

Oracle中的以下查询只返回一行(预计15行)

WITH dateCTE(from_date,to_date,d,i) AS(
  SELECT from_date,to_date,from_date AS d,1 AS i
  FROM test

  UNION ALL

  SELECT from_date,to_date,d+INTERVAL '1' DAY,i+1
  FROM dateCTE
  WHERE d<to_date
)
SELECT d,i
FROM dateCTE

SQL小提琴 - http://sqlfiddle.com/#!4/36907/8

对于测试我将条件更改为i<10

WITH dateCTE(from_date,to_date,d,i) AS(
  SELECT from_date,to_date,from_date AS d,1 AS i
  FROM test

  UNION ALL

  SELECT from_date,to_date,d+INTERVAL '1' DAY,i+1
  FROM dateCTE
  --WHERE d<to_date
  WHERE i<10 -- exit condition
)
SELECT d,i
FROM dateCTE

获得下一个结果

| D          | I  |
|------------|----|
| 2017-11-01 |  1 |
| 2017-10-31 |  2 |
| 2017-10-30 |  3 |
| 2017-10-29 |  4 |
| 2017-10-28 |  5 |
| 2017-10-27 |  6 |
| 2017-10-26 |  7 |
| 2017-10-25 |  8 |
| 2017-10-24 |  9 |
| 2017-10-23 | 10 |

为什么这个递归查询在Oracle中返回了错误的结果?

SQL小提琴 - http://sqlfiddle.com/#!4/36907/5

我在SQLServer中运行了类似的查询,得到了正确的结果

WITH dateCTE(from_date,to_date,d,i) AS(
  SELECT from_date,to_date,from_date AS d,1 AS i
  FROM test

  UNION ALL

  SELECT from_date,to_date,DATEADD(DAY,1,d),i+1
  FROM dateCTE
  WHERE d<to_date
)
SELECT d,i
FROM dateCTE

正确的结果

d           i
2017-11-01  1
2017-11-02  2
2017-11-03  3
2017-11-04  4
2017-11-05  5
2017-11-06  6
2017-11-07  7
2017-11-08  8
2017-11-09  9
2017-11-10  10
2017-11-11  11
2017-11-12  12
2017-11-13  13
2017-11-14  14
2017-11-15  15

为什么它在Oracle中不起作用?您可以建议哪些替代变体?谢谢!

来自真实系统的屏幕截图:

enter image description here

enter image description here

enter image description here

2 个答案:

答案 0 :(得分:1)

如果您想拥有从日期到最新的顺序,请使用以下选项:

SELECT  DATE '2017-11-01' + LEVEL - 1 AS D, LEVEL AS I
FROM DUAL
CONNECT BY LEVEL <= DATE '2017-11-15' - DATE '2017-11-01' + 1;

答案 1 :(得分:0)

它在Oracle 11.2 Enterprise中适用于我。然而,你的SQL小提琴显然表明它并不是每个Oracle版本。

我记得我在递归查询中有类似的日期问题。所以有一个错误,已在新版本中修复。您的Oracle版本很可能存在此错误。

解决方法:只获取递归查询中的整数偏移量,然后将它们添加到from_date:

WITH dateCTE(from_date, i, iend) AS
(
  SELECT from_date, 1 AS i, to_date - from_date as iend
  FROM test
  UNION ALL
  SELECT from_date, i + 1, iend
  FROM dateCTE
  WHERE i <= iend
)
, dates as (select i, from_date + i - 1 as d from dateCTE)
SELECT d, i
FROM dates;