直接的问题是您正在调用to_date()
固定值。该then
部分正在从文件中返回日期的原始字符串值;正在else
返回一个date
;这导致“期望字符得到日期”消息。
如果您删除该to_date()
部分,那么它会将所有值加载为 1900-01-01,因为您的 case 语句错误。您正在将:COLUMN_DOB
value 与 string进行比较'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 链接中。
就个人而言,我可能更愿意看到该列留空,而不是给它一个幻数。拥有有效 DOB 为 1900-01-01 的人并非不可能。
如果您仍然要创建一个新函数,您可以这样做:
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,那么我相信函数是停止导致整行的错误日期的唯一方法被拒绝。