Использование Oracle Zero Date - PullRequest
       0

Использование Oracle Zero Date

7 голосов
/ 18 января 2010

У меня есть приложение с существующими данными, в столбце даты которого есть ноль.

Когда я смотрю на это из sqlplus, я вижу: 00-DECEMB

когда я использую функцию дампа в этом столбце, я получаю: Typ = 12 Len = 7: 100,100,0,0,1,1,1

Мне нужно работать с существующими данными из .Net (без изменений данных, структуры данных или даже существующих операторов sql)

Как, черт возьми, я прочитал или записал это значение?

Версия дБ варьируется от 8 до 11.

Помощь будет оценена

Ответы [ 5 ]

3 голосов
/ 19 января 2010

Не уверен, что вы на самом деле ожидаете достичь, но вы можете генерировать «грубые» дни через DBMS_STATS.CONVERT_RAW_VALUE.

create or replace function stats_raw_to_date (p_in raw) return date is
  v_date date;
  v_char varchar2(25);
begin
  dbms_stats.CONVERT_RAW_VALUE(p_in, v_date);
  return v_date;
exception
  when others then return null;
end;
/
select x, dump(x) y from (select stats_raw_to_date('64640000010101') x from dual);

Так что может помочь функция

create or replace function trash_date return date deterministic is
  v_date date;
begin
  dbms_stats.CONVERT_RAW_VALUE('64640000010101', v_date);
  return v_date;
end;
/

Тогда вы можете использовать это в запросе, как

select case when date_col = trash_date then null else date_col
from table...
1 голос
/ 23 февраля 2010

В конце концов, у меня не было решения моей проблемы.

Что я делал, всякий раз, когда бизнес-логика пыталась ввести нулевую дату, я менял ее на 01.01.100когда я получал 1/1/0001 или исключение из БД, я вел себя в бизнес-логике так, как будто получил нулевую дату.

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

Поздравляю, это хранитель!

Тип = 12 Лен = 7: 100,100,0,0,1,1,1

Элементами этой свалки являются век, год, месяц, день, час, минута, секунда. Итак, у вас есть полдень по 0-0-0000, что определенно не является действительной датой ...

SQL> create table d (d1 date)
  2  /

Table created.

SQL> insert into d values (to_date('00-00-0000', 'dd-mm-yyyy'))
  2  /
insert into d values (to_date('00-00-0000', 'dd-mm-yyyy'))
                              *
ERROR at line 1:
ORA-01847: day of month must be between 1 and last day of month


SQL>

редактировать

Я использовал отличный трюк Гэри, чтобы разбить нулевую дату в таблице ....

SQL> select * from d
  2  /

D1
---------
00-DECEMB
19-JAN-10

SQL> 

Так что, по крайней мере, мы знаем, как это сделали ваши разработчики "Magic". Теперь все, что нам нужно сделать, это обойти их ум.

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

SQL> create or replace view v_d as
  2  select case when d1 = trash_date then null else d1 end as d1
  3  from d
  4  /

View created.

SQL> select * from v_d
  2  /

D1
---------

19-JAN-10

SQL>

Не менее тревожным аспектом этого является то, что вам понадобятся триггеры INSTEAD IF, которые фактически вставляют нулевые даты в базовую таблицу (опять же, используя функцию Гэри). Кроме того, чтобы поддерживать одинаковые имена объектов, вам, вероятно, потребуется построить API в другой схеме.

Так что я не минимизирую объем работы, которая в этом задействована. Проблема в том, что предыдущие разработчики столкнулись с большими техническими проблемами. Теперь вы должны оплатить этот долг (учитывая, что вы не хотите погасить капитал, переписав базу данных).

последние новости

Я только что натолкнулся на это забавное свидание в моем собственном окружении, которое предлагает альтернативное объяснение этих забавных свиданий. Я добавил столбец DATE в таблицу, в которой были строки. Я использовал предложение DEFAULT, чтобы установить значение по умолчанию sysdate. Угадай, что случилось?

SQL> select * from t69
  2  /

        ID
----------
         1
         2

SQL> alter table t69 add col2 date default sysdate not null
  2  /

Table altered.

SQL> select * from t69
  2  /

        ID COL2
---------- ---------
         1 00-DECEMB
         2 00-DECEMB

SQL>

Для записи sysdate работает, как и ожидалось, для новых строк ...

SQL> insert into t69 (id) values (3)
  2  /

1 row created.

SQL> select * from t69
  2  /

        ID COL2
---------- ---------
         1 00-DECEMB
         2 00-DECEMB
         3 28-APR-10

SQL>
0 голосов
/ 26 января 2010

Смехотворно опасно, когда Oracle использует статистику оптимизатора.

Вы получили недопустимое, искусственно заниженное значение даты, которое почти наверняка используется в качестве суррогата NULL. Oracle не знает, что это суррогат NULL, просто значение, поэтому, когда он собирает статистику оптимизатора, он будет использовать эту недопустимую дату в качестве нижнего значения для столбца и предположит, что данные линейно распределены в пределах высокого и низкого найденные значения, и что 10% от общего объема данных лежит выше верхнего значения и ниже нижнего значения.

Если у вас есть данные NULL (отсутствуют или недействительны), запишите данные NULL в таблицу.

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

Как выяснил APC, это невозможно исправить с помощью SQL * PLUS. Я столкнулся с подобной проблемой из обновленного значения JDBC.

Единственное решение, которое я мог придумать, было ОБНОВИТЬ строку, чтобы установить разумное (если все еще неправильное) значение даты - вам нужно ссылаться на строку, используя первичный ключ (который не включает в себя рассматриваемый столбец) или используйте rowid или обновите все, где столбец даты находится за пределами допустимого диапазона, используя инструмент того же типа, который изначально создал неверные данные (т.е. не sql * plus)

(ох, попробуйте исправить ошибку, вызвавшую проблему!)

НТН

С

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