Проблема запроса Oracle SQL за предыдущий месяц

Пока у меня есть следующее:

SELECT TO_CHAR("HOL_DEPART_DATES"."DEPART_DATE", 'MM') as "Depart_Month",
       TO_CHAR(sysdate, 'mm')-1 as "Current_Month"
  FROM "HOL_DEPART_DATES" "HOL_DEPART_DATES"
 WHERE "Depart_Month" = "Current_Month"

Однако это дает мне ошибку:

ORA-00904: "Current_Month": неверный идентификатор

Однако без предложения WHERE он работает нормально. Любые идеи?


person Coffeee    schedule 26.11.2010    source источник


Ответы (4)


К сожалению, вы не можете ссылаться на псевдонимы столбцов в предложении WHERE, поскольку они еще не доступны. Вы можете сделать это:

select  TO_CHAR("HOL_DEPART_DATES"."DEPART_DATE", 'MM') as "Depart_Month",
          TO_CHAR(sysdate, 'mm')-1 as "Current_Month"
from     "HOL_DEPART_DATES" "HOL_DEPART_DATES"
where     TO_CHAR("HOL_DEPART_DATES"."DEPART_DATE", 'MM') = TO_CHAR(sysdate, 'mm')-1

или сделать это:

select "Depart_Month", "Current_Month"
from
( select  TO_CHAR("HOL_DEPART_DATES"."DEPART_DATE", 'MM') as "Depart_Month",
          TO_CHAR(sysdate, 'mm')-1 as "Current_Month"
  from     "HOL_DEPART_DATES" "HOL_DEPART_DATES"
)
where     "Depart_Month" = "Current_Month"
person Tony Andrews    schedule 26.11.2010
comment
В точку, вы оба, теперь это имеет гораздо больше смысла! - person Coffeee; 26.11.2010

предложение SELECT оценивается после предложения WHERE в SQL. Вот почему предложение WHERE не может видеть определенные вами псевдонимы.

Либо:

  • запустить подзапрос:

    SELECT "Depart_Month", "Current_Month"
      FROM (SELECT TO_CHAR("HOL_DEPART_DATES"."DEPART_DATE", 'MM')
                      AS "Depart_Month",
                   TO_CHAR(SYSDATE, 'mm') - 1 AS "Current_Month"
              FROM "HOL_DEPART_DATES" "HOL_DEPART_DATES")
     WHERE "Depart_Month" = "Current_Month"
    
  • или используйте выражение в предложении where:

    SELECT TO_CHAR("HOL_DEPART_DATES"."DEPART_DATE", 'MM') AS "Depart_Month", 
           TO_CHAR(SYSDATE, 'mm') - 1 AS "Current_Month"
      FROM "HOL_DEPART_DATES" "HOL_DEPART_DATES"
     WHERE TO_CHAR("HOL_DEPART_DATES"."DEPART_DATE", 'MM') 
            = TO_CHAR(SYSDATE, 'mm') - 1
    
person Vincent Malgrat    schedule 26.11.2010

Я бы воздержался от выполнения арифметических операций над возвращаемым значением из TO_CHAR. При вычитании 1 из строки «01» (январь) мы не получим 12 (декабрь).

Вы должны сделать что-то вроде этого:

select *
  from hol_depart_dates
 where depart_date between trunc(add_months(sysdate, -1), 'MM')
                       and trunc(sysdate, 'MM') - interval '1' second;

Теперь запрос может использовать индекс по дате выезда. И TO_CHAR не нужно вызывать для каждой строки.

person Ronnis    schedule 26.11.2010
comment
Поскольку вы вычитаете целый день из TRUNC(SYSDATE,'MM'), вы фактически пропускаете все даты отправления, которые приходятся на последний день месяца (если только их время не составляет ровно 12 часов ночи). - person Jeffrey Kemp; 27.11.2010
comment
Упс, хорошо подмечено. Теперь это исправлено. - person Ronnis; 01.12.2010

Если вы хотите сравнить даты, вам не следует преобразовывать их в строки — Oracle имеет встроенную поддержку арифметики даты/времени.

В вашем случае кажется, что вы запрашиваете таблицу, в которой месяц даты отъезда равен предыдущему месяцу, что не имеет смысла. Если сейчас ноябрь, то запрос вернет строки за октябрь 2010 г., октябрь 2009 г., октябрь 2008 г. и т. д. Вы уверены, что это то, что вам нужно?

Один из лучших способов использовать арифметику дат для определения того, относится ли дата к предыдущему месяцу, — это использовать комбинацию TRUNC(дата,'МЕСЯЦ'), которая возвращает первый день текущего месяца, с ADD_MONTHS(дата,- 1), который получает дату на месяц раньше.

SELECT  TO_CHAR("HOL_DEPART_DATES"."DEPART_DATE", 'MM') as "Depart_Month",
        TO_CHAR(ADD_MONTHS(sysdate, -1), 'mm') as "Current_Month"
FROM    "HOL_DEPART_DATES"
WHERE   "HOL_DEPART_DATES"."DEPART_DATE"
        BETWEEN ADD_MONTHS(TRUNC(SYSDATE,'MONTH'),-1)
        AND     TRUNC(SYSDATE,'MONTH') - 0.00001;

«0,00001» вычитает одну секунду из даты, поэтому диапазон дат фактически становится (при условии, что сейчас ноябрь 2010 г.) от 01 октября 2010 г. 00:00:00 до 31 октября 2010 г. 23:59:59.

Альтернативный эквивалентный синтаксис:

SELECT  TO_CHAR("HOL_DEPART_DATES"."DEPART_DATE", 'MM') as "Depart_Month",
        TO_CHAR(ADD_MONTHS(sysdate, -1), 'mm') as "Current_Month"
FROM    "HOL_DEPART_DATES"
WHERE   "HOL_DEPART_DATES"."DEPART_DATE"
        >= ADD_MONTHS(TRUNC(SYSDATE,'MONTH'),-1)
AND     "HOL_DEPART_DATES"."DEPART_DATE" < TRUNC(SYSDATE,'MONTH');
person Jeffrey Kemp    schedule 27.11.2010