2017-02-09 3 views
1

У нас есть таблица, где даты хранятся как VARCHAR2 (Это устаревшая таблица данных, на которую мы не имеем контроля!) в формате YYYYMMDD. У нас есть только привилегия SELECT в таблице (Невозможно написать процедуру/функции).Oracle - Inline View - Внешнее условие WHERE, примененное inline

Необходимо выбрать все строки из таблицы, где дата -> sysdate.

Мы применяем проверку регулярного выражения для действительного формата и дополнительных проверок, чтобы гарантировать, что день действителен для данного месяца. Все это отлично работает! Выбор встроенного представления гарантирует, что будут выбраны только записи с действительными строками даты.

Однако, когда мы применяем условие для проверки> sysdate как внешнего предложения - мы получаем недопустимую дату для данной ошибки месяца, даже если выбор в виде встроенного просмотра гарантирует, что такие записи не будут выбраны.

Похоже, что выполнение запроса применяет условие из внешнего предложения до применения условий внешнего вида. Оцените любые комментарии к поведению; и как мы можем обеспечить, чтобы условия извне применялись только после выполнения стандартных условий?

данных и используемых запросов:

CREATE TABLE TEST_DATA_TABLE 
(
    DATESTRING VARCHAR2(20 BYTE) 
); 

Вставка 3 строки со значениями:

19960322 --Valid Date in past 
19831131 --Invalid Date 11/31 
20180224 --Valid Date > SYSDATE 

Действительный выбор данных: (где положение 1 обеспечивает формат и пункт 2 обеспечивает действительную дату месяца):

SELECT datestring AS i_dob 
    FROM test_data_table 
WHERE  REGEXP_LIKE (TRIM (datestring), 
         '(19|20)\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])') 
     AND TRIM (datestring) <= 
       TO_CHAR (
       LAST_DAY (
        TO_DATE (SUBSTR (TRIM (datestring), 1, 6) || '01', 
          'YYYYMMDD')), 
       'YYYYMMDD') 

Выше запрос работает нормально и возвращает допустимые строки wit h строка действительной даты,

Чтобы выбрать записи, имеющие строку даты> SYSDATE, данные выше используются inline, и мы применяем условие> SYSDATE, как показано ниже.

SELECT i_dob 
    FROM (
    SELECT datestring AS i_dob 
     FROM test_data_table 
    WHERE  REGEXP_LIKE (TRIM (datestring), 
          '(19|20)\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])') 
      AND TRIM (datestring) <= 
        TO_CHAR (
        LAST_DAY (
         TO_DATE (SUBSTR (TRIM (datestring), 1, 6) || '01', 
           'YYYYMMDD')), 
        'YYYYMMDD') 
) X 
WHERE TO_DATE (X.I_DOB, 'YYYYMMDD') > SYSDATE 

Он начинается метание ошибки: ORA-01839: date not valid for month specified

Похоже, условия применяются, прежде чем все встроенные условия вид проверяются.

+0

ОК, это интересный вопрос - спасибо за размещение этого! Два наблюдения до сих пор (я буду продолжать смотреть ...) ** FIRST **: вместо предложения WHERE, как у вас есть, вы можете проверить для X.I_DOB TO_CHAR (SYSDATE, 'YYYYMMDD') '.Конечно, это не отвечает на ваш вопрос (и, возможно, вам нужна дата для других вычислений, где вам действительно нужно преобразовать ее в дату); просто указывая, что для этого конкретного запроса существует обходное решение. – mathguy

+0

** ВТОРОЙ ** В поисках намеков; Я думал, что '/ * + ORDERED_PREDICATES * /' должен работать, и это действительно так, если вы объединяете два предложения WHERE в один (без подзапроса), но с подчиненной структурой внешнего запроса это не так. Я напишу, если я смогу найти правильный намек на это (я думал, что «NO_QUERY_TRANSFORMATION» должен работать, но это не так, или я не использовал его правильно). – mathguy

ответ

0

Вы можете обойти это, сделав внутреннее представление перед внешним запросом, добавив к нему дополнительный столбец rownum (наличие столбца rownum означает, что Oracle должен вычислить этот столбец для подзапроса, к которому он относится раньше . он может дополнительно фильтровать по нему

Итак, ваш запрос станет:

SELECT i_dob 
    FROM (
    SELECT datestring AS i_dob, 
      rownum rn 
     FROM test_data_table 
    WHERE  REGEXP_LIKE (TRIM (datestring), 
          '(19|20)\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])') 
      AND TRIM (datestring) <= 
        TO_CHAR (
        LAST_DAY (
         TO_DATE (SUBSTR (TRIM (datestring), 1, 6) || '01', 
           'YYYYMMDD')), 
        'YYYYMMDD') 
) X 
WHERE TO_DATE (X.I_DOB, 'YYYYMMDD') > SYSDATE; 

Я хотел бы добавить комментарий в ваш запрос, объясняющего наличие этого столбца, в противном случае некоторые разработчик в будущем может думать «а «Это ничего не делает, я удалю его!».

(Следует также отметить, в 12.2, они добавили/измененные функции для обеспечения easier data validation, что позволит упростить запрос, когда вы дойдете до 12,2!)

+0

Это работает, спасибо за обходное решение.! – Soorjith

+0

Что это будет с работой? В то время как обходной процесс работает функционально, это взломать поверх hack .... :( – BobC

+0

Согласитесь, что производительность, но похоже, что нет другого варианта. Оптимизатор запросов может быть упорядочен на основе производительности, но мы вынуждаем порядок – Soorjith

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

  • Нет связанных вопросов^_^