Табличные операции SQL To_Date - PullRequest
0 голосов
/ 29 января 2010

В основном у меня есть следующий запрос , который работает , но не дает правильных данных:

SELECT a.* FROM 
  ( SELECT a.*, rownum rnum FROM ( 

     SELECT 

      edate.expiration_date

      FROM 
      ...

      ( SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') expiration_date 
       FROM  ... ) edate
  ) a WHERE rownum <= 20) 
 a WHERE rnum >= 1 AND 
 expiration_date < to_date('1/29/2010', 'MM/DD/YYYY HH24:MI:SS')

Причина, по которой это не работает, состоит в том, что, поскольку оценки rownum / rnum выполняются одновременно с проверкой даты, он получает только rownums (например, 1, 4, 6, 9, которые имеют даты до 29.01.2010). вместо первых 20 дат с датой менее 1/29/2010.

Так что в основном площадь

expiration_date < to_date('1/29/2010', 'MM/DD/YYYY HH24:MI:SS')

должен быть помещен во внутренние SELECT, но всякий раз, когда я пытаюсь это сделать, я получаю недопустимая ошибка месяца . Как я могу привести селекты или подзапросы в to_date s, чтобы они работали?

Ответы [ 4 ]

2 голосов
/ 29 января 2010

Мне кажется, что c.value содержит значения, которые не являются датами. Просто никто из них не в первых двадцати рядах. Таким образом, запрос успешно выполняется, когда TO_DATE () применяется во внешнем запросе, потому что преобразование применяется только к первым двадцати значениям. Однако применение преобразования во внутреннем запросе означает попытку преобразования всех строк, включая те, которые содержат значения, которые не являются датами.

Это одна из ловушек при использовании структуры базы данных, которая хранит данные в общих строковых столбцах вместо использования соответствующих типов данных.

Что с этим делать? Разумеется, вы можете изменить модель данных, чтобы даты содержались в столбцах, определенных с использованием типа данных DATE, но я подозреваю, что это может потребовать больше усилий, чем вы ищете. Альтернативой может быть использование клуджа, подобного этому

create or replace function is_a_date 
    (p_str in varchar2
     , p_mask in varchar2 := 'MM/DD/YYYY HH24:MI:SS')
    return date
is
    return_value date;
begin
    begin
        return_value := to_date(p_str, p_mask);
    exception
        when others then
            return_value := null;
    end;
    return return_value;
end;
/

Это берет строку и пытается преобразовать ее в дату, используя маску формата. Если это дата в соответствующем формате, она возвращает дату, в противном случае она возвращает ноль:

SQL> select is_a_date('01/01/2000 23:56:07') from dual
  2  /

IS_A_DATE
---------
01-JAN-00

SQL> select is_a_date('APC is not a date') from dual
  2  /

IS_A_DATE
---------


SQL>
1 голос
/ 29 января 2010

Исходя из информации в вашем вопросе, первых трех ответов и последующих комментариев, на самом деле это звучит так, как будто не имеет ничего общего с первыми 20 значениями, то есть с красной сельдью. Похоже, это может быть связано со скрытой логикой во внутреннем избранном. Я считаю, что что-то там - это удаление записей из таблицы C, так что TO_DATE в C.Value не встречается в полях, которые не являются действительными датами, но когда вы добавляете To_Date (c.Value, 'MM / DD / YYYY HH24: MI: SS ') для вашего внутреннего SQL-кода, он встречается во всех полях таблицы C. Вы должны быть можно избежать этого, просто переключая внешние и первые встроенные предложения WHERE

SELECT a.* FROM 
  ( SELECT a.*, rownum rnum FROM 

      ( SELECT 

               edate.expiration_date

        FROM 
        ...

          ( SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') expiration_date 
            FROM  ... ) edate
      ) a 
    WHERE expiration_date < to_date('1/29/2010', 'MM/DD/YYYY HH24:MI:SS')
  )  a 
WHERE rnum >= 1 AND 
      rownum <= 20

Если это невозможно из-за другой логики, которая не может быть изменена, вы должны иметь возможность добавить предложение WHERE внутри самого внутреннего "a" для expiration_date

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

1 голос
/ 29 января 2010

Итак, оставив в стороне все, что связано с нумерацией страниц, вы захотите этот запрос:

SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') expiration_date 
  FROM ... 
 WHERE To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS')
       < to_date('1/29/2010', 'MM/DD/YYYY')

Просто запустить его самостоятельно, не получится ли?

0 голосов
/ 29 января 2010

Я действительно рекомендую вам исправить модель данных и хранить значения даты в отдельном столбце. В противном случае вы можете попробовать добавить

where ltrim(substr(c.value,1,3),'0 ') in ('1/','2/',...'12/')

Если входящее значение «31.01.2010», а не «31.01.2010» или «31.01.2010», необходимо соответствующим образом изменить фильтр. Посмотрите на соответствие REGEX.

Но если вы не исправите эту модель, вы потратите гораздо больше времени на эту

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...