4

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

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;
)

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

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

4 回答 4

5

好问题——这个问题真的吸引了我!答案或多或少地隐藏在汤姆的帖子中。这是简短版本,使用名为 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 1/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
于 2013-03-08T21:03:24.723 回答
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

从您的代码中,我可以看出您一定是一个面向对象的程序员,并且不熟悉 SQL。它对你有很大帮助,所以不要试图控制它。它会阻碍它的优化功能。

不要以错误的方式理解这一点,我有同样的心态(相信我比机器更聪明)。

于 2013-03-08T21:19:29.183 回答
0

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

AND (date = subQuery.Start_Date 
  OR date = subQuery.End_Date)
于 2013-03-08T19:27:45.257 回答
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
于 2013-03-08T20:01:11.313 回答