Excellent Technique
Robert, January 24, 2002 - 1:32 pm UTC
Tom,
What would you do if you were given a sql loader file with the dates of the following formats?
1/10/2001 16:39:22
02/1/2001 10:12:33
01/22/2000 21:00:19
January 25, 2002 - 8:27 am UTC
...
that_column date "dd/mm/yyyy hh24:mi:ss",
....
is what I would use.
Thanks
Robert, January 25, 2002 - 9:33 am UTC
Tom,
First of all, Thank You!
We assumed the date formats were causing the problem. However, this date column had about 7,000 values of #EMPTY out of the 600,000 + rows. Since the file was over 200mb we decided to load it into all varchars, replace the invalid values with nulls and then insert into the target table with the date format as you suggested.
January 25, 2002 - 1:51 pm UTC
well, if its just '#EMPTY' -- i would have used decode:
....
x "decode( :x, '#EMPTY', null, to_date(:x,'dd-mon-yyyy') )"
....
Sweet
Rodney Patterson, April 09, 2002 - 6:07 pm UTC
Loading from a pipe seems like a terrific way to Direct Loader (still the best enhancement ever) on real world files
April 09, 2002 - 7:12 pm UTC
And in 9i -- you can direct path load using SQL functions as well -- never a need to "awk" the file again (and probably lets you just skip that pipe in 99.99% of the cases)
$ cat t.ctl
LOAD DATA
INFILE t.dat
INTO TABLE NXBenefit
FIELDS TERMINATED BY ","
(plan,
effective "todate_pkg.thedate(:effective)"
)
$ cat t.dat
dental plan, 01-11-01
vision plan, 03/05/01
vision plan, 03.05.01
vision plan, jan-01-01
vision plan, 01-jan-01
vision plan, 01-jan-2001
$ sqlldr / t direct=true
SQL*Loader: Release 9.0.1.2.0 - Production on Tue Apr 9 19:10:26 2002
(c) Copyright 2001 Oracle Corporation. All rights reserved.
Load completed - logical record count 6.
$ plus
SQL*Plus: Release 9.0.1.0.0 - Production on Tue Apr 9 19:10:30 2002
(c) Copyright 2001 Oracle Corporation. All rights reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.0.1.2.0 - Production
With the Partitioning option
JServer Release 9.0.1.2.0 - Production
ops$tkyte@ORA9I.WORLD> select * from nxbenefit
2 /
PLAN EFFECTIVE
------------------------- ---------
dental plan 01-NOV-01
vision plan 03-MAY-01
vision plan 03-MAY-01
vision plan 01-JAN-01
vision plan 01-JAN-01
vision plan 01-JAN-01
6 rows selected.
External tables take this to a WHOLE another level -- don't even need sqlldr! Just insert /*+ append */ into table select * from flat_file -- direct path load without the muss.
how about decimals
Oracle-Leo, November 13, 2002 - 7:39 am UTC
Hi Tom,
I have a strange doubt and you are the only one i can fall back on. thanks for all the support.
I am generating a temp.dat file by doing a 'select * ' from a particular query. A couple of columns there will have data in 7 decimals (999999.1234567). when i upload that temp.dat file using sql*loader (positional), SQL*loader is rounding off the 7 decimals to 4 decimals while loading the data on to the table. What could be the problem???.
The desc of table structure is below for that column.
DURATION NOT NULL NUMBER(8,7)
Thanks for all the support.
Cheers
November 13, 2002 - 1:55 pm UTC
example please (you are not using 999999.1234567 -- that won't fit in a number(8,7).
Here is my example:
ops$tkyte@ORA920.LOCALHOST> create table t ( n number(8,7) );
Table created.
ops$tkyte@ORA920.LOCALHOST> !cat t.ctl
LOAD DATA
INFILE *
INTO TABLE T
FIELDS TERMINATED BY ","
(n)
BEGINDATA
999999.1234567
9.1234567
ops$tkyte@ORA920.LOCALHOST> !sqlldr / t
SQL*Loader: Release 9.2.0.1.0 - Production on Wed Nov 13 10:56:01 2002
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Commit point reached - logical record count 2
ops$tkyte@ORA920.LOCALHOST> select * from t;
N
----------
9.1234567
ops$tkyte@ORA920.LOCALHOST>
<b>one row rejected -- the other loaded just fine. A thought I have is that it is not a number(8,7) but something bigger and you are loading 99999.1234567 and SQLPlus's default format isn't showing you all of the decimals. consider:</b>
ops$tkyte@ORA920.LOCALHOST> create table t ( n number );
Table created.
ops$tkyte@ORA920.LOCALHOST> !sqlldr / t
SQL*Loader: Release 9.2.0.1.0 - Production on Wed Nov 13 10:57:18 2002
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Commit point reached - logical record count 2
ops$tkyte@ORA920.LOCALHOST> select * from t;
N
----------
999999.123
9.1234567
<b>appears truncated, but it is not:</b>
ops$tkyte@ORA920.LOCALHOST> set numformat 9999999.999999999
ops$tkyte@ORA920.LOCALHOST> /
N
------------------
999999.123456700
9.123456700
ops$tkyte@ORA920.LOCALHOST>
Dave, November 13, 2002 - 4:04 pm UTC
Quote:
"
21 exception
22 when others then null;
23 end;
"
Who are you, and what have you done with the real Tom? You know, the one who wrote ..."I truly wish we didn't even support WHEN OTHERS"?
Be careful what you wish for ;)
Thanks
falguni, November 13, 2002 - 11:28 pm UTC
Thanks Tom this was one of my Question which I am waiting from last 3 months to ask you.
Thats really clever!
Jim, November 14, 2002 - 1:16 am UTC
Tom
I have a file which has rows with the date in diff formats
12/9/02 16:29 3125 3000 3001 302
13/9/02 11:21 3000 3001 3002 400
14/9/02 09:53:11 AM 3000 3001 3002 400
Your solution is brilliant
Number problem with example
Oracle-Leo, November 14, 2002 - 1:20 am UTC
Sorry, I showed the next column. The problematic columns are event_data_time,start_date_time and not duration one.
Here is the example.
tigger:~/sched> sqlplus /
SQL*Plus: Release 8.1.6.0.0 - Production on Fri Nov 15 14:03:25 2002
(c) Copyright 1999 Oracle Corporation. All rights reserved.
Connected to:
Oracle8i Release 8.1.6.0.0 - Production
JServer Release 8.1.6.0.0 - Production
system@SKYNEW on tig> desc test;
Name Null? Type
----------------------------------------- -------- ----------------------------
SERVICE_KEY NOT NULL NUMBER(4)
EVENT_DATE_TIME NOT NULL NUMBER(12,7)
EVENT_NUM NOT NULL NUMBER(1)
TRAFFIC_KEY VARCHAR2(20)
SYNC_CHAN_ID NOT NULL NUMBER(4)
START_DATE_TIME NOT NULL NUMBER(12,7)
DURATION NOT NULL NUMBER(8,7)
DETAIL_KEY NOT NULL VARCHAR2(20)
EVENT_ID NUMBER(5)
VIDEOPLUS_CODE NUMBER(16)
CA_RQST_KEY VARCHAR2(20)
OPPV_PURCHASE_FLAG NUMBER(1)
IPPV_PURCHASE_FLAG NUMBER(1)
FECM_ID NUMBER(5)
FREE_CA_MODE NOT NULL NUMBER(1)
NAME_ID NUMBER(3)
system@SKYNEW on tig> !cat test.ctl
load data
infile *
into table ssr.test
fields terminated by ","
trailing nullcols
(service_key ,
event_date_time,
event_num ,
traffic_key ,
sync_chan_id ,
start_date_time ,
duration ,
detail_key ,
event_id ,
videoplus_code ,
ca_rqst_key ,
oppv_purchase_flag,
ippv_purchase_flag,
fecm_id ,
free_ca_mode )
BEGINDATA
2,52592.8437444,0,0,0,52592.8437444,00000000.0104166,2_82,,,,,,,0
2,52592.8541611,0,0,0,52592.8541611,00000000.0104166,2_83,,,,,,,0
system@SKYNEW on tig> !sqlldr / test
SQL*Loader: Release 8.1.6.0.0 - Production on Fri Nov 15 14:05:21 2002
(c) Copyright 1999 Oracle Corporation. All rights reserved.
Commit point reached - logical record count 2
system@SKYNEW on tig> select * from ssr.test;
SERVICE_KEY EVENT_DATE_TIME EVENT_NUM TRAFFIC_KEY SYNC_CHAN_ID START_DATE_TIME DURATION DETAIL_KEY EVENT_ID VIDEOPLUS_CODE CA_RQST_KEY OPPV_PURCHASE_FLAG IPPV_PURCHASE_FLAG FECM_ID FREE_CA_MODE NAME_ID
-------------- ------------------ ------------ -------------------- ------------ --------------- ---------- -------------------- ----------- -------------- -------------------- ------------------ ------------------ ---------- ------------ ----------
2 52592.8437 0 0 0 52592.8437 .0104166 2_82 259 0
2 52592.8542 0 0 0 52592.8542 .0104166 2_83 260 0
2 rows selected.
The columns have rounded off to four decimals. Am I missing something. Any clues.
Cheers,
November 14, 2002 - 6:59 pm UTC
:)
go back, reread my response (i guessed right!!!)
<quote>
...A thought I have is that it
is not a number(8,7) but something bigger and you are loading 99999.1234567 and
SQLPlus's default format isn't showing you all of the decimals. consider:....
</quote>
the answer and solution is above (look for numformat)
Another case
Adrian, January 28, 2003 - 8:23 pm UTC
Dear Tom, actually i'm loading a flat file via text i/o from forms but is too slow, can u help me to make a ctl file who can handle this format in a flat file
12/01/02 00:15;414;0;303;0;0;0;0;0
00:30;420;0;318;0;0;0;0;0
00:45;432;0;318;0;0;0;0;0
01:00;372;0;309;0;0;0;0;0
....
23:30;159;0;177;0;0;0;0;0
23:45;165;0;165;0;0;0;0;0
12/01/02 24:00;168;0;183;0;0;0;0;0
12/02/02 00:15;159;0;162;0;0;0;0;0
00:30;156;0;117;0;0;0;0;0
where the time header is the day until change the header as u can see
Thanks in advance
January 28, 2003 - 8:33 pm UTC
how much data are we talking about here -- how big are these here files?
Hi
Adrian, January 28, 2003 - 8:45 pm UTC
Well here is a 96 record ina day for a month 2976 aprox but here is a 194 files to load every one belongs to a specific electronic meter
January 28, 2003 - 9:01 pm UTC
HUH?
Well here is a 96 record ina day for a month 2976 aprox but here is a 194 files
to load
can you translate that back into something "parseable"?
Ok
Adrian, January 28, 2003 - 9:10 pm UTC
i have 2976 records in every flat file
I have too 194 flat files to load every month
I mean every month i receive the 194 flat files then i have to upload it to the db. ( oracle 8i standard edition ).
January 29, 2003 - 7:25 am UTC
suppose you had this table to load into:
create table t
( dt date,
c1 number,
c2 number,
c3 number,
c4 number,
c5 number,
c6 number,
c7 number,
c8 number );
Then create this view:
create or replace view v
as
select to_char(dt) dt, c1, c2, c3, c4, c5, c6, c7, c8
from t;
and this trigger on it
create or replace trigger v_trigger
instead of insert on v
begin
if ( length(:new.dt) > 5 )
then
dbms_application_info.set_client_info( substr(:new.dt,1,8) );
insert into t ( dt, c1, c2, c3, c4, c5, c6, c7, c8 )
values ( to_date( :new.dt, 'mm/dd/rr hh24:mi' ),
:new.c1, :new.c2, :new.c3, :new.c4, :new.c5, :new.c6, :new.c7, :new.c8 );
else
insert into t ( dt, c1, c2, c3, c4, c5, c6, c7, c8 )
values ( to_date(userenv('client_info')||:new.dt,'mm/dd/rrhh24:mi'),
:new.c1, :new.c2, :new.c3, :new.c4, :new.c5, :new.c6, :new.c7, :new.c8 );
end if;
end;
/
and then this ctl file will load t
options (rows=1)
LOAD DATA
INFILE *
INTO TABLE v
REPLACE
fields terminated by ';'
(
dt,c1,c2,c3,c4,c5,c6,c7,c8
)
BEGINDATA
12/01/02 00:15;414;0;303;0;0;0;0;0
00:30;420;0;318;0;0;0;0;0
00:45;432;0;318;0;0;0;0;0
01:00;372;0;309;0;0;0;0;0
23:30;159;0;177;0;0;0;0;0
23:45;165;0;165;0;0;0;0;0
12/01/02 23:00;168;0;183;0;0;0;0;0
12/02/02 00:15;159;0;162;0;0;0;0;0
00:30;156;0;117;0;0;0;0;0
Excellent Answer
Adrian, January 29, 2003 - 10:10 am UTC
Thanks Tom...!!!
Very useful...!!
Checksum?
A reader, February 08, 2003 - 8:52 am UTC
Hi Tom,
My load file contains one header record (the name of the file), and one trailor (the number of records and the checksum). I would like load using 9i running SQL on external files (not loading the header and trailor but checking the name of the file and checksum). Would this be possible? Please give an idea, how best to do this, the file contains about 20 million records.
Thanks
February 08, 2003 - 9:33 am UTC
You can use a BFILE or even UTL_FILE (now that it supports seeking in a file) to read the first and last record of the file (seek to the end of the file and look "backwards" with dbms_lob.instr for the prior newline).
PRAGMA RESTRICT_REFERENCES
David, March 27, 2003 - 12:11 pm UTC
In 8.0.6, this function is throwing a ORA-06571, which instructs me to use the pragma restrict references. I'm having a tough time placing the pragma. Can you tell me a) will this package work in 8.0.6. and b) if I need the pragma, where does it go?
As always, thanks
March 27, 2003 - 12:38 pm UTC
create or replace package todate_pkg
as
function thedate
( p_string in varchar2 )
return date;
pragma restrict_references( todate_pkg, wnds, rnds, wnps, rnps );
pragma restrict_references( thedate, wnds, rnds, wnps );
end;
/
and yes, I just tested on 806
having trouble matching format string in array to the forms of dates I'm encountering
David, March 27, 2003 - 3:14 pm UTC
I have rrrr-mm-dd, mm-dd-rr, m-dd-rr, mm-d-rr, etc. And I can't seem to get a complete ist into the array. I you mask 4/12/2003 with dd/mm/rrrr, won't that reject?
March 27, 2003 - 3:24 pm UTC
I don't understand your comments.
Sorry, it was late in the day for me....
David, March 28, 2003 - 8:45 am UTC
I was asking about single-digit days and single-digit months. I wanted to know if both 1/1/2003 and 01/01/2003 could be handled with a mask like mm-dd-yyyy.
I've moved past that, though, to other problems to solve!
Thanks.
March 28, 2003 - 9:21 am UTC
yes, they can
sql loader
Somdeb Majumdar, April 26, 2003 - 1:47 am UTC
Hi there...
Can we use group functions in the control file?
Suppose we are inserting data in 2 tables through a conrol file. (Please consider the emp table for eg) In the first insert statement the data is coming from some emp.dat file. And in the second I want to have the sum of salaries entered for all the employees in the emp table. Is this possible to achieve through a Control File?
I am citing an example :-
OPTIONS
(ERRORS = 50)
LOAD DATA
INFILE "D:\Emp.dat"
APPEND
INTO TABLE EMP
(EMPNO "EMP_SEQ.NEXTVAL"
SALARY POSITION(1:10) INTEGER
FILE_NM CONSTANT 'EMP.DAT')
INTO TABLE TRAILER
** (TOTAL_SALARY "SELECT SUM(SALARY) FROM EMP WHERE
FILE_NM='EMP.DAT'"
FILE_NM CONSTANT 'EMP.DAT'
PRCSS_DT SYSDATE)
You can easily see that I am getting stuck in '**' marked line. How to incorporate this?
Please explain.
April 26, 2003 - 8:24 am UTC
That would be a materialized view -- it would be done for you in the database.
No, you cannot do it in sqlldr like that -- it doesn't make sense.
why you dont have to specify datatype in this column?
A reader, July 11, 2003 - 5:05 am UTC
Hi
I extracted two lines from your examples
that_column date "dd/mm/yyyy hh24:mi:ss", 01/22/2000 21:00:19
effective "todate_pkg.thedate(:effective)"
why in the first column we have to specify data and the second not when both of them use date datatype???????
July 11, 2003 - 10:22 am UTC
the second does NOT use a date:
ops$tkyte@ORA8I.WORLD> create or replace package todate_pkg
2 as
3 function thedate
4 ( p_string in varchar2 )
5 return date;
6 end;
theDate function expects a string.
a questeion about your package
A reader, July 11, 2003 - 5:30 am UTC
Hello
I have a question about this package
create or replace package todate_pkg
as
function thedate
( p_string in varchar2 )
return date;
end;
/
create or replace package body todate_pkg
as
type fmtArray is table of varchar2(30);
g_fmts fmtArray :=
fmtArray( 'dd-mm-rr', 'dd/mm/rr',
'dd.mm.rr', 'mon-dd-rr',
'dd-mon-rrrr' );
function thedate( p_string in varchar2 )
return date
is
return_value date;
begin
for i in 1 .. g_fmts.count
loop
begin
return_value := to_date(p_string,g_fmts(i) );
exit;
exception
when others then null;
end;
end loop;
if ( return_value is null ) then
raise PROGRAM_ERROR;
end if;
return return_value;
end;
end;
/
it seems it only treats input string of formats
'dd-mm-rr', 'dd/mm/rr', 'dd.mm.rr', 'mon-dd-rr', 'dd-mon-rrrr'
however I pass anything to this package it can comvert to proper date format how so? For example
SQL>select todate_pkg.thedate('01@01@99') from dual;
TODATE_PKG.THEDAT
-----------------
19990101 00:00:00
SQL>select todate_pkg.thedate('01012003') from dual;
TODATE_PKG.THEDAT
-----------------
20030101 00:00:00
I dont get it....... also why you use an ext statement inside the loop :-?
July 11, 2003 - 10:24 am UTC
because those formats are rather forgiving
1* select to_date( '01~01~99', 'dd/mm/rr' ) from dual
ops$tkyte@ORA817DEV> /
TO_DATE('01
-----------
01-JAN-1999
as far as separators go.
I exit the loop as soon as we get a format that "worked". If I did not, we would either
o return the date as translated by the last format
o return an error
if any of the intermediate formats worked, we would miss that fact if I did not exit the loop.
Can this be done ?
Anand, July 12, 2003 - 8:42 am UTC
Hi Tom,
I am a Avid fan of your excellent service to Oracle developer community, even though this is my first post. I have a doubt, even though i am not facing this problem, For example, if the flat file has records with formats like this
Date
----------
08-13-2003 --------------> mm-dd-yyyy
12-30-2003 --------------> dd-mm-yyyy
Is there any way by which I can identify the format and use it in the sql*loader control file ? Just asking out of curiosity !!! I hope you have a answer to this question (even though it sounds silly ;-)!)
Anand
July 12, 2003 - 9:37 am UTC
only if the input file HAS the format in it -- does each record in the input file have its corresponding date format in the record?
Oooooppppsss...
Anand, July 12, 2003 - 8:44 am UTC
The format mask has to be interchanged between the first and second records.. sorry for the inconvenience..
Is there a roundabout way of doing that ?
Anand, July 13, 2003 - 3:22 am UTC
Hi Tom,
As i had mentioned earlier it is just a hypothetical situation...But cant that be handled within the function which we are creating and refering in SQL*Loader. May be like finding out what is the format in which the date is stored in... any way i agree that it will not work for dates like "12-12-2003" or dates like that... but otherwise... shouldnt there be a way ?
July 13, 2003 - 9:39 am UTC
umm, think about it
01-02-03
is that jan 2cnd 2003
feb 1st 2003
mar 2cnd 2001
and so on.
NO, without a format, anything is fair game isn't it.
No there "shouldn't" be a way.
Converting from external table to SQL*Loader
Martin, January 08, 2004 - 11:34 am UTC
Tom,
i've got a load of data which we've got the 9i external table definitions for, but we need to load this into an 8i database. Is it possible to do the reverse of the sqlloader external_table=generate_only trick and create sqlloader control files from an external table definition?
Note, the 9i and 8i databases are seperate clients and we have no mechanism for database links etc. (unfortunately)
Thanks in advance
January 08, 2004 - 2:52 pm UTC
i have no tools for doing so, no.
most of the work should be "done" as the bottom of the external table is close to a control file already.
expected behavior?
Susan, May 04, 2004 - 8:00 pm UTC
Tom,
We have asc files that have dates in this format: 050404
I added mmddyy to your package array. I thought everything was working nicely, but, I noticed that it's transposing certain dates -- for eg. 010604 was loaded as 06/01/2004, 110503 was loaded as 5/11/2003. I haven't fully diagnosed it, but, I think the problem occurs when the day begins with a zero. Any thoughts? Thanks for the help.
May 04, 2004 - 9:04 pm UTC
order of formats in the array.
tell me, what is 010604
is that
01-jun-2004
06-jan-2004
04-jun-2001
etc etc etc etc etc etc.
if your date is mmddyy -- you should use THAT format and that format alone.
doh!
Susan, May 05, 2004 - 10:48 am UTC
Thanks Tom
help with this?
Susan, May 05, 2004 - 12:26 pm UTC
Our upload asc file records missing dates as MMMMMM,
Our application records missing dates as 02/02/0202. In my ctl file I'm using:
DATEFLD "replace(:dateintr, 'MMMMMM', to_date('02/02/0202', 'MM/DD/YYYY'))"
these dates, however, are getting loaded as 02/02/2002.
I'm confused because if I do this from sqlplus:
SQL> select to_date('02/02/0202', 'MM/DD/YYYY') from dual;
TO_DATE('0
----------
02/02/0202
what obvious thing am I missing here :) Thanks Tom.
May 05, 2004 - 2:53 pm UTC
replace returns a string.
there is an implicit to_char in there:
replace(:dateintr, 'MMMMMM', to_char(to_date('02/02/0202', 'MM/DD/YYYY')))
so, that implicit conversion must be returning something "you were not expecting".
why not use:
"decode( :dateintr, 'MMMMMM', to_date( .... ), to_date(:dateintr,'format') )"
that way, decode returns A DATE, not a string.
Thanks Tom!
Susan, May 05, 2004 - 3:50 pm UTC
As usual, most helpful.
rounding the date which is in timestamp with local timezone datatype
Hisham, May 25, 2004 - 1:24 am UTC
Hi Tom,
The above information was very helpful. In my need the coloumn is in timestamp with local time zone. i want to round the value to the date.
i.e '7/26/1999 8:47:30 AM' date should be rounded as 7/26/1999 and to be compared with the date & timestamp column for loading the data into flat file. Please guide me how to do that.
May 25, 2004 - 7:14 am UTC
just call round
round(time_stamp)
How control file (SQL*LOADER) handle multiple different format date
lamya, June 02, 2004 - 12:49 pm UTC
Tom I read your above reply , I have a question
MY data file consists of data like
2003-03-16 00:00:00
2003-04-14 00:00:00
My ctl file is like this
load data
INFILE 'lv2_circadian_rhythms.dat' "str '
@%@%@%@%@@^&$%;%$^&@'"
INTO TABLE LV2DTA.LV2_CIRCADIAN_RHYTHM
REPLACE
FIELDS TERMINATED BY '@^&$%;%$^&@'
TRAILING NULLCOLS
(
CREATED date 'yyyy-mm-dd HH24:MI:SS',
)
but when I load data in ORacle , my data is loaded
as 3/16/2004 . I want to load it as 3/16/2004 00:00:00
How can I do it ?
Thanks
Lamya
June 02, 2004 - 1:29 pm UTC
dates are always stored with times. you just have to ask to have them shown
select to_char( date_field, 'dd/mm/yyyy hh24:mi:ss' ) from t;
or
alter session set nls_date_format='dd/mm/yyyy hh24:mi:ss';
select date_field from t;
Thanks
Lamya, June 03, 2004 - 4:06 pm UTC
Tnaks a million tom ...it satisifed my manager
TIMESTAMP datatype in control file
Jianhui, August 13, 2004 - 6:00 pm UTC
Tom,
I've got something wired happening when i use sqlldr to load data in WINDOWS and UNIX platforms.
(1)The defination of the table is:
SQL> desc test
Name Null? Type
----------------------------------------- -------- -----------------
ID NUMBER(10)
TXT VARCHAR2(30)
DT TIMESTAMP(0)
C CHAR(3)
D DATE
(2)In UNIX platform, this is the Cut&Paste of my telnet session:
<<<
zhangdba@dwrdb1dv:/home/zhangdba/adhoc
->ls
ts.ctl ts.dat
zhangdba@dwrdb1dv:/home/zhangdba/adhoc
->cat ts.dat
1,Hello World,2004-06-01 10:11:12.000000,T,2004-06-01,
2,Hello World,2004-06-01 10:11:12.000000,F,2004-06-01,
zhangdba@dwrdb1dv:/home/zhangdba/adhoc
->cat ts.ctl
LOAD DATA
INFILE 'ts.dat'
APPEND
INTO TABLE test
FIELDS TERMINATED BY ','
(
ID,
TXT,
DT "to_timestamp(substr(:DT, 1, 19), 'YYYY-MM-DD HH24:MI:SS')",
C,
D "CASE WHEN instr(:D, ':')>0
THEN to_date(substr(:D, 1, 19), 'YYYY-MM-DD HH24:MI:SS')
ELSE to_date(substr(:D, 1, 10), 'YYYY-MM-DD')
END"
)
zhangdba@dwrdb1dv:/home/zhangdba/adhoc
->sqlldr userid=u/p@tns control=ts.ctl
SQL*Loader: Release 9.2.0.5.0 - Production on Fri Aug 13 17:34:31 2004
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Commit point reached - logical record count 2
zhangdba@dwrdb1dv:/home/zhangdba/adhoc
->ls
ts.bad ts.ctl ts.dat ts.log
zhangdba@dwrdb1dv:/home/zhangdba/adhoc
->cat ts.bad
1,Hello World,2004-06-01 10:11:12.000000,T,2004-06-01,
2,Hello World,2004-06-01 10:11:12.000000,F,2004-06-01,
zhangdba@dwrdb1dv:/home/zhangdba/adhoc
->more ts.log
...
Record 1: Rejected - Error on table TEST, column DT.
ORA-01843: not a valid month
Record 2: Rejected - Error on table TEST, column DT.
ORA-01843: not a valid month
Table TEST:
0 Rows successfully loaded.
2 Rows not loaded due to data errors.
0 Rows not loaded because all WHEN clauses were failed.
0 Rows not loaded because all fields were null.
...
>>>
(3)In WINDOW's session, this is the cut&paste:
<<<
C:\DOCUME~1\JIANHU~1>dir t.*
Volume in drive C has no label.
Volume Serial Number is C829-8FDE
Directory of C:\DOCUME~1\JIANHU~1
08/13/2004 05:35 PM 319 t.ctl
08/13/2004 05:13 PM 132 t.dat
2 File(s) 451 bytes
0 Dir(s) 6,168,063,488 bytes free
C:\DOCUME~1\JIANHU~1>type t.dat
1,Hello World,2004-06-01 10:11:12.000000,T,2004-06-01,
2,Hello World,2004-06-01 10:11:12.000000,F,2004-06-01,
C:\DOCUME~1\JIANHU~1>type t.ctl
LOAD DATA
INFILE 't.dat'
APPEND
INTO TABLE test
FIELDS TERMINATED BY ','
(
ID,
TXT,
DT "to_timestamp(substr(:DT, 1, 19), 'yyyy-mm-dd hh24:mi:ss')",
C,
D "CASE WHEN instr(:D, ':')>0
THEN to_date(substr(:D, 1, 19), 'yyyy-mm-dd hh24:mi:ss')
ELSE to_date(substr(:D, 1, 10), 'yyyy-mm-dd')
END"
)
C:\DOCUME~1\JIANHU~1>sqlldr userid=u/p@tns control=t.ctl
SQL*Loader: Release 9.2.0.1.0 - Production on Fri Aug 13 17:36:38 2004
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Commit point reached - logical record count 2
C:\DOCUME~1\JIANHU~1>more t.log
...
Table TEST:
2 Rows successfully loaded.
0 Rows not loaded due to data errors.
0 Rows not loaded because all WHEN clauses were failed.
0 Rows not loaded because all fields were null.
...
>>>
So the question is why the load fails in unix but succeeds in WINDOW? The control file and the data file are the same(FTP them from UNIX to WINDOWS in ASC mode), could that be CHARACTER SET related? If so , how to fix it in UNIX? I tried to use SUBSTRC in UNIX, but not luck.
Thanks for your help as aways,
August 13, 2004 - 6:53 pm UTC
what i would do -- to help you see how i would figure this out -- is load into a table full of varchar2's and see what you see!
(loaded right up for me in unixland)
result of load in UNIX for all varchar2 type
Jianhui, August 16, 2004 - 3:31 pm UTC
Tom,
here we go
<<<UNIX
->sqlldr userid=u/p@db control=test_all_varchar2.ctl
SQL*Loader: Release 9.2.0.5.0 - Production on Mon Aug 16 14:52:10 2004
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Commit point reached - logical record count 2
zhangdba@dwrdb1dv:/home/zhangdba/adhoc
->cat test_all_varchar2.ctl
LOAD DATA
INFILE 'ts.dat'
APPEND
INTO TABLE test_all_varchar2
FIELDS TERMINATED BY ','
(
ID,
TXT,
DT,
C,
D
)
zhangdba@dwrdb1dv:/home/zhangdba/adhoc
->cat ts.dat
1,Hello World,2004-01-01 10:11:12.000000,T,2004-06-01,
2,Hello World,2004-01-01 10:11:12.000000,F,2004-06-01,
END of UNIX>>>
<<< SQL*PLUS
SQL> desc test_all_varchar2;
Name Null? Type
----------------------------------------- -------- ----------------------------
ID VARCHAR2(30)
TXT VARCHAR2(30)
DT VARCHAR2(30)
C VARCHAR2(3)
D VARCHAR2(30)
SQL> select * from test_all_varchar2;
ID TXT
------------------------------ ------------------------------
DT C D
------------------------------ --- ------------------------------
1 Hello World
2004-01-01 10:11:12.000000 T 2004-06-01
2 Hello World
2004-01-01 10:11:12.000000 F 2004-06-01
SQL> select dump(dt), dt from test_all_varchar2;
DUMP(DT)
--------------------------------------------------------------------------------
DT
------------------------------
Typ=1 Len=26: 50,48,48,52,45,48,49,45,48,49,32,49,48,58,49,49,58,49,50,46,48,48,
48,48,48,48
2004-01-01 10:11:12.000000
Typ=1 Len=26: 50,48,48,52,45,48,49,45,48,49,32,49,48,58,49,49,58,49,50,46,48,48,
48,48,48,48
2004-01-01 10:11:12.000000
END of SQL* PLUS>>>
really freaky, are you able to reproduce the error in your environment?
BTW, NLS_LANG is unset.
i have figured this out
Jianhui, August 16, 2004 - 4:56 pm UTC
I did couple tests and when i set NLS_LANG(=AMERICAN_AMERICA.UTF8) to the same as database character set, it succeeded. Which i unset NLS_LANG, it failed.
August 16, 2004 - 8:08 pm UTC
makes sense - multi-byte will get you everytime when you mix them.
Commit in direct path sqlldr
A reader, September 02, 2004 - 10:08 am UTC
Tom,
I believe that in sqlldr direct=true, commit occurs only after all the rows are loaded.
so if for some reason my load fails in between, not a single record will get loaded.
Please correct me if i'm wrong.
September 02, 2004 - 10:12 am UTC
there are savepoints with direct path loads.
rows -- Number of rows in conventional path bind array or between direct path data saves
Splendid
vrd, February 26, 2005 - 8:14 pm UTC
Hi Tom,
The discussion is splendid. However, I am facing a rather peculiar problem. I have a delimited file and have to load its data into 9 different tables, for which I have written 9 different control files. One of the tables has a date column and the date in the INFILE is of the format MM/DD/YYYY hh24:mi:ss. But the strange thing is when I use
StatementDate Date "MM/DD/YYYY hh24:mi:ss"
I get the error message : Rejected - error on table xxxx , column cccc
ORA-01858: a non-numeric character was found where a numeric was expected.
SO, I thught, maybe the incoming date was not in the proper format and I tried using the to_date(to_char()) sql and I get the message as invalid number or sometimes, I get a invalid month or the hour should be between 0 and 23.
I assure you, I'm using only 10 records (as a sample), but stil get these errors. I don't know what's wrong. PLEASE HELP..........
February 27, 2005 - 8:21 am UTC
how about the example?
a create table (with just the necessary columns -- not all of them)
the ctl file
the data....
Date Field Loading - Storage
MA Reader, March 03, 2005 - 7:52 am UTC
All of the discussions and responses on this issue (as well as most others) have been helpful but here are 2 very basic questions on SQL Loader. In loading dates:
1. Via SQL Loader, is there any 'requirement' that the format include HH:MM:sec or can the date be loaded as MM/DD/YYYY, if that format is specified?
2. After the date has been loaded/updated/inserted in MM/DD/YYYY format, is there any storage savings vs. the long Oracle format which includes the time?
Thank you for a very enjoyable and useful site.
March 03, 2005 - 8:08 am UTC
1) as long as the data being loaded is mm/dd/yyyy sure -- you use the format that actually matches the data you have to load...
2) all dates, ALL DATES are stored in a 7 byte format
YYYYMMDDhh24miss
and the hh24miss would just be "zero"
mm/dd/yyyy is just a format, you can use it to convert a string into a date, or a date back into a string, but all dates are stored exactly the same.
loading unix date using external table
NR, May 05, 2005 - 11:02 pm UTC
Tom,
I have data which contains date in unix timestamp "1115333572". I am trying to load and all of the data being rejected because of the date format. And same data I can load using sqlldr using date 'yyyymmdd hh:mm:ss"
in control file but not in external tables. Might be something very small but I don't know what I am missing. Help me out here.
Thanks
NR
May 06, 2005 - 7:21 am UTC
you would map that as a number (since it is) and use a function such as:
</code>
http://asktom.oracle.com/Misc/CTime.html <code>
in your select statement to convert the number into a date.
Direct path, SQL functions, roles vs direct grants
AB, October 04, 2005 - 10:14 am UTC
Following up on SQL functions being possible in sqlldr 9i. True and almost never had a problem with them. But do you have any idea why the following happens on my 9.2.0.6 DB?
* USER_A has a table T. USER_A grants ALL on T to an T_UPDATE role.
* T_UPDATE role is granted to USER_B.
* USER_B can insert happily into USER_A.T.
* USER_B can direct path sql*load USER_A.T
* USER_B can conventional path sql*load USER_A.T with SQL functions in the .ctl script
* ...but, when USER_B tries to direct path sql*load USER_A.T with SQL functions in the .ctl script (9.0.1 new feature), the logfile shows insufficient privileges and every row is rejected (actually the 6 source rows generate 51 recursive SQL error messages in the log file).
* ...however, when the ALL on T is granted directly to USER_B, the problem goes away and the combination of table-in-other-schema, direct path and SQL functions works happily.
I can't find anything about this as a direct path restriction in the docs... Any clue? Bug? The logfile showing 51 rejects from a 6-record .dat file is a clue that something might be amiss.
Thanks
October 04, 2005 - 4:40 pm UTC
sounds like either
a) an undocumented restriction
b) a product issue
either way, it sounds like a bug - either doc or implementation wise.
Please help!!
A reader, March 03, 2006 - 12:52 pm UTC
Tom,
I am getting this after I sql loaded into my table
2006-03-03¿¿07:32:46 how can I get rid of the space??
thanks,
March 03, 2006 - 2:09 pm UTC
er? no idea what you've done, how you've done it, or anything...
follow up
A reader, March 03, 2006 - 2:13 pm UTC
I copy the text file from windows and paste into
a file in linux. That's all I did..
March 03, 2006 - 5:20 pm UTC
missing the point, I don't know what your data looks like, what your table it, what you control file looks like, etc.
Up to you to take care of date formats you want to deal with
jon waterhouse, March 06, 2006 - 12:44 pm UTC
The package as written deals with 5 types of date format, as copied and pasted from above.
g_fmts fmtArray :=
7 fmtArray( 'dd-mm-rr', 'dd/mm/rr',
8 'dd.mm.rr', 'mon-dd-rr',
9 'dd-mon-rrrr' );
If you have other formats to deal with, such as the date/time format, then you need to add it to the list.
Is it a bug ?
Jeeves, December 19, 2006 - 6:57 am UTC
Hi Tom,
I added one more format i.e rrrrmmdd
and when I call the function it is giving different result :
SQL> select todate_pkg.thedate('20061223') from dual;
TODATE_PKG
----------
20-06-1223
1 row selected.
( I expected 23-12-2006 )
SQL> select todate_pkg.thedate('20361223') from dual;
TODATE_PKG
----------
23-12-2036
1 row selected.
( Got what I expected !!!)
The create package script is copied for your convenience.
Thanks
Jeeva
create or replace package todate_pkg
as
function thedate
( p_string in varchar2 )
return date;
end;
/
create or replace package body todate_pkg
as
type fmtArray is table of varchar2(30);
g_fmts fmtArray :=
fmtArray( 'dd-mm-rr', 'dd/mm/rr',
'dd.mm.rr', 'mon-dd-rr',
'dd-mon-rrrr', 'rrrrmmdd' );
function thedate( p_string in varchar2 )
return date
is
return_value date;
begin
for i in 1 .. g_fmts.count
loop
begin
return_value := to_date(p_string,g_fmts(i) );
exit;
exception
when others then null;
end;
end loop;
if ( return_value is null ) then
raise PROGRAM_ERROR;
end if;
return return_value;
end;
end;
/
December 19, 2006 - 8:41 am UTC
but don't you see that if a given format is "acceptable" (and they are processed in a given order), it is acceptable.
20061223
is
20-06-1223
ops$tkyte%ORA10GR2> select to_date( '20061223', 'dd-mm-rr' ) from dual;
TO_DATE('20061223','
--------------------
20-jun-1223 00:00:00
You need to be really careful when your dates could match multiple formats!
consider
010203
what is that date - could be one of many...
Thanks... its solved now
A reader, December 19, 2006 - 9:15 am UTC
Thanks Tom,
I solved it by putting the 'rrrrmmdd' first in the list of array.
g_fmts fmtArray :=
fmtArray( 'rrrrmmdd','dd-mm-rr',
'dd/mm/rr','dd.mm.rr',
'mon-dd-rr','dd-mon-rrrr' );
Its now returning the date as required.
Thanks once again..
Jeeva
A reader, July 13, 2007 - 5:51 am UTC
Hi,
When there is not null constraints in XNAME ,records are loding into table .When define not null constraint giving the below error and however have 10 valid records in my csv but when invoking sqlldr from cmd displaying the below message.Why it showing 42 ,it suppose to read 10
and XCREATED_ON datatype is string and getting the below error
Record 5: Rejected - Error on table "DEL_TYPE", column XCREATED_ON.
ORA-01858: a non-numeric character was found where a numeric was expected
Commit point reached - logical record count 42
Field in data file exceeds maximum length
Record 5: Rejected - Error on table DEL_TYPE.
ORA-01400: cannot insert NULL into ("SCOTT"."DEL_TYPE"."XNAME")
Record 6: Rejected - Error on table DEL_TYPE, column XLOCALE_NAME.
ORA-01401: inserted value too large for column
Record 5: Rejected - Error on table "DEL_TYPE", column XCREATED_ON.
ORA-01858: a non-numeric character was found where a numeric was expected
control file
=======
load data infile
'c:\Delivery_Type.csv'
into table DEL_TYPE
fields terminated by "," optionally enclosed by ' " '
TRAILING NULLCOLS
(
XLOCALE_NAME,
XNAME_ENGLISH,
XNAME,
XDELIVERY,
XLABEL0,
XLABEL1,
XLABEL2,
XLABEL3,
XLABEL4,
XID CONSTANT "1",
XCREATED_BY CONSTANT "admin",
XCREATED_ON CONSTANT "sysdate",
XUPDATED_BY CONSTANT "admin",
XUPDATED_ON CONSTANT "sysdate",
XNEWTS CONSTANT "sysdate",
XTIME_STAMP CONSTANT "sysdate")
Thanks and Regards,
Mohan
July 13, 2007 - 10:33 am UTC
are you as confused as I am by:
... When there is not null constraints in XNAME ,records are loding into table .When define not null constraint giving the below error ...
no example, no look.
A reader, July 13, 2007 - 11:42 am UTC
Ho Tom,
Sorry for not proper explanation.
1)Successfully Loaded into DEL_TYPE(without any constraints) using sqlloader ,But problem is when defined not null constraints on xname column ,no data being loaded into Table(xname has a values) and below is the contents of the log file
Field in data file exceeds maximum length
Record 5: Rejected - Error on table DEL_TYPE.
ORA-01400: cannot insert NULL into ("SCOTT"."DEL_TYPE"."XNAME")
Record 5: Rejected - Error on table "SCOTT"."DEL_TYPE", column XCREATED_ON.
ORA-01858: a non-numeric character was found where a numeric was expected
2) My csv files only 10 records and suppose to load 10
records but the target having 210 records(without any
constraints)
C:\Documents and Settings\xx>sqlldr scott/tiger control='c:\a1.ctl'
SQL*Loader: Release 9.2.0.1.0 - Production on Fri Jul 13 23:30:35 2007
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Commit point reached - logical record count 73
Commit point reached - logical record count 137
Commit point reached - logical record count 203
Commit point reached - logical record count 253
C:\Documents and Settings\akil>exit
SQL> select count(*) from del_type;
COUNT(*)
----------
210
control file
=======
load data infile
'c:\Delivery_Type.csv'
into table DEL_TYPE
fields terminated by "," optionally enclosed by ' " '
TRAILING NULLCOLS
( XLOCALE_NAME,
XNAME_ENGLISH,
XNAME,
XDELIVERY,
XLABEL0,
XLABEL1,
XLABEL2,
XLABEL3,
xLABEL4,
XID CONSTANT "1",
XCREATED_BY CONSTANT "admin",
XCREATED_ON CONSTANT "sysdate",
XUPDATED_BY CONSTANT "admin",
XUPDATED_ON CONSTANT "sysdate",
XNEWTS CONSTANT "sysdate",
XTIME_STAMP CONSTANT "sysdate")
Thanks and Regards,
Mohan
July 13, 2007 - 12:01 pm UTC
sigh
still - no example to work with. oh well. onto the next question.
you should be (HAVE TO actually) above to provide a create table, the necessary alter tables and a controlfile with begindata (inline data) to demonstrate the issue with (and you need about 2 rows of data - from your bad file - to do this)