查询将给出两个日期范围之间的日期列表

时间:2013-03-08 19:24:48

标签: sql oracle oracle11g

我的问题类似于以下问题:

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:14582643282111

区别在于我的内部查询返回两条记录而且我有外部查询。

我需要编写类似这样的内部查询,它会给我一个两个日期范围之间的日期列表(我正在尝试这个查询而不执行)。

Select * from outerTable where  my_date in
(   
    select to_date(r.REQ_DATE) + rownum -1
     from all_objects, (MY_INNER_QUERY Where ID =100) r 
     where rownum <= to_date(r.DUE_DATE,'dd-mon-yyyy')-to_date(r.REQ_DATE,'dd-mon-yyyy')+1;
)

我的内部查询返回以下两行:

Select * from innerTable Where ID =100


    Start date           end date 
    3/19/2013            3/21/2013 
    3/8/2013             3/8/2013

所以我需要内部查询,它会将以下日期返回到外部查询:

    3/19/2013
    3/20/2013
    3/21/2013
    3/8/2013

4 个答案:

答案 0 :(得分:4)

很棒的问题 - 这个真的吸引了我!答案或多或少地被埋在汤姆的帖子上。这是简短版本,使用名为TestDR的表来定义范围。首先是TestDR内容:

SELECT * FROM TestDR;

STARTDATE ENDDATE
--------- ---------
19-MAR-13 21-MAR-13
08-MAR-13 08-MAR-13

现在,查询为范围中的每个日期创建一行:

WITH NUMS AS (
  SELECT LEVEL-1 DaysToAdd
  FROM DUAL
  CONNECT BY LEVEL <= 60
)
SELECT StartDate + DaysToAdd TheDate
FROM TestDR
CROSS JOIN NUMS
WHERE TestDR.EndDate - TestDR.StartDate + 1 > DaysToAdd
ORDER BY 1

THEDATE
---------
08-MAR-13
19-MAR-13
20-MAR-13
21-MAR-13

根据Tom的帖子调整查询,您必须知道“种子”NUMS查询的最大范围。他在他的例子中使用了60,这就是我上面使用的。如果您认为子查询中的任何行都不会超过60天,那么这就行了。如果您认为最大值可能长达1000天(大约三年),那么将60更改为1000.我尝试了这个并查询了2年半的范围,结果是即时的。

如果您想指定确切的“种子”计数,您可以计算它,如果您愿意使查询更复杂一些。以下是我使用TestDR表格的方法:

WITH NUMS AS (
  SELECT LEVEL-1 DaysToAdd
  FROM DUAL
  CONNECT BY LEVEL <= (
    SELECT MAX(EndDate - StartDate + 1)
    FROM TestDR)
)
SELECT ... and the rest of the query as above

答案 1 :(得分:3)

对于您的问题,您无需枚举日期。一个简单的JOIN就足够了。

SELECT o.*
  FROM outerTable o
 INNER JOIN innerTable i
    ON i.ID = 100
   AND o.my_date BETWEEN i.REQ_DT and i.DUE_DT

从您的代码中,我可以说您必须是OO程序员并且不熟悉SQL。它为你做了很多,所以不要试图控制它。它会阻碍它的优化功能。

不要以错误的方式采取这种做法,我有同样的心态(相信我比机器更聪明)。

答案 2 :(得分:0)

在您的外部查询中使用OR语句,它允许您的日期等于返回Start_Date或End_Date

AND (date = subQuery.Start_Date 
  OR date = subQuery.End_Date)

答案 3 :(得分:0)

使用您的日期:

SELECT smth... FROM some_tab
 WHERE your_date IN  
( -- remove unnecessary columns, leave only what you select in outer query 
  -- or select * 
SELECT start_date
 , TRUNC(start_date, 'iw')                  wk_starts  
 , TRUNC(start_date, 'iw') + 7 - 1/86400    wk_ends
 , TO_NUMBER (TO_CHAR (start_date, 'IW'))   ISO_wk#
 FROM 
(
SELECT (start_date-1) + LEVEL AS start_date
 FROM 
( -- replace this part with selecting your start and end dates from your table --
SELECT to_date('03/21/2013', 'MM/DD/YYYY') end_date 
     , to_date('03/19/2013', 'MM/DD/YYYY')  start_date 
 FROM dual
)
CONNECT BY LEVEL <= (end_date - start_date)
)
) -- your outer query ends --
/

START_DATE    WK_STARTS    WK_ENDS                ISO_WK#
----------------------------------------------------------
3/19/2013    3/18/2013    3/24/2013 11:59:59 PM    12
3/20/2013    3/18/2013    3/24/2013 11:59:59 PM    12

年度日期表和ISO周等...使用开始日期和结束日期的任何日期。连接和之间的天数用于动态生成表。如果使用硬结构,您可以在运算符之间使用......:

SELECT start_date
 , TRUNC(start_date, 'iw')                  wk_starts  
 , TRUNC(start_date, 'iw') + 7 - 1/86400    wk_ends
 , TO_NUMBER (TO_CHAR (start_date, 'IW'))   ISO_wk#
 FROM 
 (-- This part simplifies above formatting and optional --
 SELECT (start_date-1) + LEVEL AS start_date
   FROM 
  (-- Replace start/end dated with any dates --
  SELECT TRUNC(ADD_MONTHS (SYSDATE, 12), 'Y')-1 end_date  
       , TRUNC(SYSDATE, 'YEAR')                 start_date 
   FROM dual
  )
  CONNECT BY LEVEL <= (end_date - start_date) -- number of days between dates 
 )
 /

START_DATE    WK_STARTS    WK_ENDS                  ISO_WK#
-----------------------------------------------------------
1/1/2013      12/31/2012    1/6/2013 11:59:59 PM      1
1/2/2013      12/31/2012    1/6/2013 11:59:59 PM      1
1/3/2013      12/31/2012    1/6/2013 11:59:59 PM      1
...
12/28/2013    12/23/2013    12/29/2013 11:59:59 PM    52
12/29/2013    12/23/2013    12/29/2013 11:59:59 PM    52
12/30/2013    12/30/2013    1/5/2014 11:59:59 PM      1