SQL Developer - Использование переменных даты начала и конца в предложении where моего запроса - PullRequest
4 голосов
/ 03 ноября 2010

У меня есть запрос, который я запускаю каждый день, требующий значений StartDate и EndDate.StartDate и EndDate были ручным вводом, но я пытаюсь уйти от этого и вычислить StartDate и EndDate для использования в запросе.Я разработал код для захвата StartDate и EndDate в переменных:

DECLARE

    c_DateMask VARCHAR2(20) := 'DD-Mon-YYYY';
    c_TimeMask VARCHAR2(20) := 'HH24:MI';

    v_Month char(4) := 'Prev'; 
    v_StartDate date; 
    v_EndDate date; 
    v_Environment char(7) := 'Prod';  

BEGIN

    if v_MONTH = 'Prev'
        THEN 
            select TO_DATE ('01-' || TO_CHAR (ADD_MONTHS (SYSDATE, -1),'mon-yyyy')) into v_StartDate from dual; 
            select Last_day(TO_DATE('01-' || TO_CHAR (ADD_MONTHS (SYSDATE, -1),'mon-yyyy'))) into v_EndDate from dual;
        ELSE
            select TO_DATE ('01-' || TO_CHAR (ADD_MONTHS (SYSDATE, 0),'mon-yyyy')) into v_StartDate from dual;
            CASE
                WHEN v_Environment = 'Prod'
                    THEN
                        -- Production Environment --
                          select 
                              to_char(sysdate, 'dd-Mon-yyyy ') ||
                              case 
                                  when to_char(sysdate, 'mi') between 00 and 20
                                    then to_char(sysdate, 'hh24')-1||':58'||':00' 
                                  when to_char(sysdate, 'mi') between 21 and 40
                                    then to_char(sysdate, ' hh24')||':18'||':00' 
                                  when to_char(sysdate, 'mi') between 41 and 60
                                    then to_char(sysdate, ' hh24')||':38'||':00'
                              END 
                          into v_EndDate from dual;
                WHEN v_Environment = 'OldTest'
                    THEN
                       -- Test Environment --
                            select 
                                to_char(sysdate, 'dd-Mon-yyyy ') ||
                                case 
                                when to_char(sysdate, 'mi') between 10 and 30
                                    then to_char(sysdate, 'hh24')||':08'||':00'
                                when to_char(sysdate, 'mi') between 31 and 50
                                    then to_char(sysdate, ' hh24')||':28'||':00' 
                                when to_char(sysdate, 'mi') between 51 and 60
                                    then to_char(sysdate, ' hh24')||':48'||':00'
                                END 
                            into v_EndDate from dual;
            end case;    
    end if;

Затем я хочу использовать переменные в своем предложении select ниже:

    -----------------
    /* KPI Figures */
    -----------------

    SELECT 
        SysDate as RunTime
        , v_StartDate
        , v_EndDate
        , TTM_OFF_CONTRIBUTOR
        , SUM(NVL(TTM_PER_OFF_FEE,0)) Fees
    FROM  [Table]
    Where 
        TTM_PROCESSED_DATE    >= v_StartDate
        AND TTM_PROCESSED_DATE    <= v_EndDate
    group by SysDate, v_StartDate, v_EndDate, TTM_OFF_CONTRIBUTOR

END;

Itвсе работает до тех пор, пока я не попытаюсь использовать значения переменных в запросе показателей KPI.Чего мне не хватает?

Обновление:

Относительно Ответ Фила : Я пытался, но это не сработало, и я получаю следующую ошибку:

PLS-00428: an INTO clause is expected in this SELECT statement.

Я уверен, что вчера я видел другой ответ, который сейчас пропал, касающийся возможности присваивать несколько значений переменным или что-то в этом роде.

Это то, что мне нужно и как мне это сделать?

Ответы [ 3 ]

1 голос
/ 05 ноября 2010

Переменные v_StartDate и v_EndDate находятся только в области видимости в блоке PL / SQL, где они объявлены. Похоже, что вы пытаетесь использовать их вне блока в отдельном запросе. Для этого вам потребуется создать переменные связывания SQL Developer вне блока PL / SQL, например:

var v_start_date varchar2(11)
var v_end_date varchar2(11)

Затем укажите их как переменные связывания как в блоке PL / SQL, так и в запросе SQL:

declare
  ...
begin
  ....
  :v_start_date := '01-' || TO_CHAR (ADD_MONTHS (SYSDATE, -1), 'mon-yyyy');
  :v_end_date := TO_CHAR(Last_day(TO_DATE('01-' 
                 || TO_CHAR (ADD_MONTHS (SYSDATE, -1),'mon-yyyy'))));
  -- (NB No need to select from dual)
  ...
end;

SQL:

...
Where 
TTM_PROCESSED_DATE    >= TO_DATE(:v_StartDate)
AND TTM_PROCESSED_DATE    <= TO_DATE(:v_EndDate)

Обратите внимание, что эти переменные не могут быть объявлены с типом DATE, поэтому их необходимо преобразовать обратно в даты в запросе (используя правильную маску формата).

1 голос
/ 11 ноября 2010

Я предлагаю вам заключить начальную дату / конечную дату в две функции (хранимые процедуры)

create or replace function get_startdate(p_month in varchar2, p_env in varchar2)
return date
is
  l_return date;
begin
   ... logic goes here ...
   return l_return;
end;

Аналогично для конечной даты.

Затем используйте эти функции в своем запросе:

SELECT 
    SysDate as RunTime
    , get_startdate('Prev', 'Prod')
    , get_enddate('Prev', 'Prod')
    , TTM_OFF_CONTRIBUTOR
    , SUM(NVL(TTM_PER_OFF_FEE,0)) Fees
FROM  [Table]
Where 
    TTM_PROCESSED_DATE    >= get_startdate('Prev', 'Prod')
    AND TTM_PROCESSED_DATE    <= get_enddate('Prev', 'Prod')
group by SysDate, get_startdate('Prev', 'Prod'), get_enddate('Prev', 'Prod'), TTM_OFF_CONTRIBUTOR

Sidenote: рассмотрите более сжатую версию, чтобы определить первый и последний день месяца.Вы также можете просто присвоить значение переменной, не используя SELECT INTO, например,

startdate := trunc(sysdate, 'MM'); -- first day of current month
enddate := last_day(trunc(sysdate, 'MM')); -- last day of current month

Чтобы рассчитать с часами, вы можете добавить / вычесть количество минут, которое более читабельно, чем все преобразования to_date / to_charвы, например,

enddate := trunc(sysdate, 'HH24');
case 
  when to_char(sysdate, 'mi') between 00 and 20 then enddate := enddate - 2/(24*60);
  when to_char(sysdate, 'mi') between 21 and 40 then enddate := enddate + 18/(24*60);
  when to_char(sysdate, 'mi') between 41 and 60 then enddate := enddate + 38/(24*60);
end; 

Удачи, Мартин

0 голосов
/ 04 ноября 2010

Я думаю, что проблема с вашим запросом и псевдонимами. Попробуйте

SELECT 
    SysDate as RunTime
    , v_StartDate AS StartDate
    , v_EndDate AS EndDate
    , TTM_OFF_CONTRIBUTOR
    , SUM(NVL(TTM_PER_OFF_FEE,0)) Fees
FROM  [Table]
Where 
    TTM_PROCESSED_DATE    >= v_StartDate
    AND TTM_PROCESSED_DATE    <= v_EndDate
group by RunTime, StartDate, EndDate, TTM_OFF_CONTRIBUTOR
...