Преобразование даты sqlloader: несогласованный тип данных

Я пытаюсь загрузить некоторые данные в базу данных Oracle с помощью SQLLoader, но я продолжаю получать ошибки ORA-00932: inconsistent datatypes: expected DATE got NUMBER или expecting char got date

Дата приходит в формате, например. 20130815 и хранится в базе данных со столбцом типа Date.

Логика должна заключаться в том, что если кто-то передает недопустимую дату null или говорит недопустимый месяц в строке даты, например. 20131301, то я хочу вставить дату по умолчанию, например. 19990101.

Вот код SQLLoader, который у меня есть:

COLUMN_DOB   DATE 'YYYYMMDD' "CASE:COLUMN_DOB WHEN 'isdate(:COLUMN_DOB)=1' THEN :COLUMN_DOB ELSE to_date('19000101', 'YYYYMMDD') END",,

person lukik    schedule 15.08.2013    source источник
comment
Ошибка возникает из-за кода в операторе case? Из-за вызова функции? Какой тип данных передается в функцию?   -  person David Aldridge    schedule 15.08.2013


Ответы (1)


Непосредственная проблема заключается в том, что вы вызываете to_date() для фиксированного значения. Часть then возвращает исходное строковое значение даты из файла; else возвращает date; что приводит к сообщению «ожидаемая дата получения char».

Если вы удалите часть to_date(), все значения будут загружены как 1900-01-01, потому что у вас неверный оператор case. Вы сравниваете значение :COLUMN_DOB со строкой 'isdate(:COLUMN_DOB)=1'. Это не вызов функции, это фиксированная строка, и ваше поле даты никогда не будет точно соответствовать этому тексту. Таким образом, case всегда переходит в else и получает фиксированное значение. Вы также, кажется, смешиваете две формы оператора case.

Так должно быть:

... "CASE WHEN isdate(:COLUMN_DOB)=1 THEN :COLUMN_DOB ELSE '19000101' END"

Что, если предположить, что вы создали функцию isdate() — поскольку это не встроенная функция Oracle — с маской формата по умолчанию, что-то вроде этого на основе версии AskTom:

create or replace function isdate (p_string in varchar2,
  p_fmt in varchar2 := 'YYYYMMDD')
return number as
  l_date date;
begin
  if l_date is null then
    return 0;
  end if;
  l_date := to_date(p_string, p_fmt);
  return 1;
exception
  when others then
     return 0;
end;
/

... поставит действительные даты, как указано, и недействительные даты как 1900-01-01. Нулевая проверка также означает, что нули будут вставлены как 1900-01-01; возможно, проще иметь его здесь, чем пытаться обрабатывать его отдельно в управляющем файле.

Возможно, вы могли бы еще больше упростить его, создав функцию, которая пытается преобразовать строку и вернуть дату, и просто вызывая ее в управляющем файле без маски date или оператора case. Этот подход также описан в этой ссылке AskTom.

Лично я, вероятно, предпочел бы, чтобы столбец оставался нулевым, а не присваивал ему магическое число. Нет ничего невозможного в том, чтобы иметь кого-то с действительной датой рождения 01.01.1900.


Если вы все равно создаете новую функцию, вы можете сделать это вместо этого:

create or replace function my2date(p_str in varchar2) return date is
begin
  return to_date(nvl(p_str, '19000101'), 'YYYYMMDD');
exception
  when others then -- just about acceptable here
    return date '1900-01-01';
end;
/

который вы можете выполнить из SQL * Plus, SQL Developer, Toad или любого другого клиента, который вы используете. И тогда ваш управляющий файл будет иметь:

COLUMN_DOB "my2date(:COLUMN_DOB)"

Я не думаю, что есть способ сделать это без использования функции. Если вместо этого вы использовали внешнюю таблицу, то вы могли бы использовать анонимный блок для преобразования, я полагаю, но если вы застряли с SQL * Loader, то я считаю, что функция - это единственный способ остановить неверную дату, из-за которой вся строка быть отвергнутым.

person Alex Poole    schedule 15.08.2013
comment
Спасибо за отзыв. Хотя функция isdate является функцией оракула, как показано здесь так что нет, у меня нет собственной функции, созданной в Oracle, и я не знаю, как ее создать. Есть ли альтернативное решение, не связанное с созданием функции? - person lukik; 15.08.2013
comment
@lukik - вы можете создать функцию, если у вас есть разрешение, подключившись к SQL * PLus или выбранному вами клиенту от имени того же пользователя, от имени которого вы выполняете загрузку, и просто выполнив оператор create or replace .... Если у вас еще нет isdate, то my2date (тоже от Tom Kyte) будет чище, я думаю. - person Alex Poole; 15.08.2013
comment
Работал отлично. Спасибо. Я создал функцию и изменил свой управляющий файл, чтобы отразить функцию my2date. - person lukik; 16.08.2013