2013-03-08 3 views
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 
+1

почему 3/20/2013 идет? –

ответ

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 

С запросом адаптированный размещения Тома, вы должны знать максимальный диапазон собирается в «посеять» запрос 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 
0

В вашем внешнем запросе использовать OR, который позволяет вашей дате быть равной либо возврату Start_Date, либо End_Date

AND (date = subQuery.Start_Date 
    OR date = subQuery.End_Date) 
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 
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. Он многое делает для вас, поэтому не пытайтесь его контролировать. Это будет препятствовать его оптимизации.

Не принимайте это неправильно, у меня было такое же мышление (полагая, что я умнее машины).

Смежные вопросы