>-I would like to extract the streetname from the streetaddress field
>in the csv file above so that everything starting from the first
>number after position 5 would be located in the streetno field.
>This should be possible, but as I'm not too familiar with sql*loader
>rather complex control file syntax.
I think the unfamaliarity would be addressed by reading it up, and
trying to understand it. If you define an addrescode field as 'char'
would you expect Oracle strips the leading zeroes?
Also what you propose above is simply not possible: if you manage to
concatenate individual columns together, there is nothing that can
parse it, as such parsing will never be fool proof.
--
Sybrand Bakker, Senior Oracle DBA
Well, it isn't a csv (comma separated value) file, since it is
separated by semicolons, but that really doesn't matter. You can trim
the zeroes from in front of the addrcode, but why not make a number
column instead? I have been in the same situation, where you don't
have control of the structure that the data comes from or goes into and
you have to parse an address column and load the data into separate
fields in a new table. Although nothing is foolproof, most conversions
are better than not converting it, or losing the data. I like to use
functions to extract and validate. You can use such functions directly
in SQL*Loader, but I don't think you can use them directly in external
tables. However, you can load your data into a staging table, then
insert it into your other table using the functions. Please see the
demonstration below, which shows how to do it either using SQL*Loader
or an external table and an insert. The functions were created to your
specifications, but you may want to test, check your data, and see if
you need to make revisions.
-- functions:
scott@ORA92> CREATE OR REPLACE FUNCTION extract_streetname
2 (p_streetname IN VARCHAR2)
3 RETURN VARCHAR2
4 AS
5 v_int INTEGER := 6;
6 BEGIN
7 WHILE SUBSTR (p_streetname, v_int, 1)
8 NOT IN ('1', '2', '3', '4', '5', '6', '7', '8', '9')
9 LOOP
10 v_int := v_int + 1;
11 END LOOP;
12 RETURN SUBSTR (p_streetname, 1, v_int - 1);
13 EXCEPTION
14 WHEN OTHERS THEN
15 RETURN p_streetname;
16 END extract_streetname;
17 /
Function created.
scott@ORA92> SHOW ERRORS
No errors.
scott@ORA92> CREATE OR REPLACE FUNCTION extract_streetno
2 (p_streetname IN VARCHAR2)
3 RETURN VARCHAR2
4 AS
5 v_streetno VARCHAR2(25) := SUBSTR (p_streetname, 6);
6 BEGIN
7 WHILE SUBSTR (v_streetno, 1, 1) NOT IN
8 ('1', '2', '3', '4', '5', '6', '7', '8', '9')
9 LOOP
10 v_streetno := SUBSTR (v_streetno, 2);
11 END LOOP;
12 RETURN v_streetno;
13 EXCEPTION
14 WHEN OTHERS THEN
15 RETURN NULL;
16 END extract_streetno;
17 /
Function created.
scott@ORA92> SHOW ERRORS
No errors.
scott@ORA92> CREATE OR REPLACE FUNCTION my_to_date
2 (p_date IN VARCHAR2)
3 RETURN DATE
4 AS
5 BEGIN
6 RETURN TO_DATE (p_date, 'DDMMYYYY');
7 EXCEPTION
8 WHEN OTHERS THEN
9 RETURN NULL;
10 END my_to_date;
11 /
Function created.
scott@ORA92> SHOW ERRORS
No errors.
-- table:
scott@ORA92> CREATE TABLE addr_ext
2 (addrcode VARCHAR2(10),
3 streetname VARCHAR2(25),
4 streetno VARCHAR2(25),
5 addrdate DATE)
6 /
Table created.
-- SQL*Loader control file and load:
LOAD DATA
INFILE 'c:\ext_tables\addr.csv'
INTO TABLE addr_ext
FIELDS TERMINATED BY ';'
TRAILING NULLCOLS
(addrcode "LTRIM (:addrcode, '0')",
streetname "extract_streetname (:streetname)",
addrdate "my_to_date (:addrdate)",
streetno "extract_streetno (:streetname)")
scott@ORA92>-HOST SQLLDR scott/tiger CONTROL=addr.ctl LOG=addr.log
-- or external table and insert:
scott@ORA92> CREATE OR REPLACE DIRECTORY ext_tables AS 'c:\ext_tables'
2 /
Directory created.
scott@ORA92> CREATE TABLE addr_ext_load
2 (addrcode VARCHAR2(10),
3 streetname VARCHAR2(25),
4 addrdate VARCHAR2(8))
5 ORGANIZATION external
6 (TYPE ORACLE_LOADER
7 DEFAULT DIRECTORY ext_tables
8 ACCESS PARAMETERS
9 (RECORDS DELIMITED BY NEWLINE
10 FIELDS TERMINATED BY ";"
11 MISSING FIELD VALUES ARE NULL
12 (addrcode CHAR,
13 streetname CHAR,
14 addrdate CHAR))
15 LOCATION ('addr.csv'))
16 REJECT LIMIT UNLIMITED
17 /
Table created.
scott@ORA92> INSERT INTO addr_ext (addrcode, streetname, streetno,
addrdate)
2 SELECT LTRIM (addrcode, '0'),
3 extract_streetname (streetname),
4 extract_streetno (streetname),
5 my_to_date (addrdate)
6 FROM addr_ext_load
7 /
3 rows created.
-- results either way:
scott@ORA92> SELECT * FROM addr_ext
2 /
ADDRCODE STREETNAME STREETNO ADDRDATE
---------- ------------------------- -------------------------
---------
101 Fox Street 20 A
27-MAY-05
102 42nd Street 20921
25-FEB-05
105 Fox Street 21
scott@ORA92>
Kirmo Uusitalo - 31 May 2005 06:09 GMT
>Well, it isn't a csv (comma separated value) file, since it is
>separated by semicolons, but that really doesn't matter. You can trim
>the zeroes from in front of the addrcode, but why not make a number
>column instead?
I think I will use Sql*loader because of the possibility to use sql
functions for column data.
The reason why I originally started to investigate external tables was
to have a common structure for data from slightly different source and
the data could have been read very easily from a scheduled dbms_job.
After the data had been read into the specified external table, a
common pl/sql would then convert it to the actual tables and I could
skip creating slightly different code for the data conversion.
Well, it can be done using sql*loader + cron script /scheduled batch
file almost as easily.
I really wonder why the option of using an sql function to convert the
field is not supported by Oracle External Tables as the engine behind
external tables has so much in common with Oracle Sql*Loader.
>scott@ORA92> CREATE OR REPLACE FUNCTION my_to_date
> 2 (p_date IN VARCHAR2)
[quoted text clipped - 7 lines]
> 10 END my_to_date;
> 11 /
I think that reading in the date using the external tables (or
sql*loader) can be done just specifying the date format such as in my
example:
addrdate DATE "DDMMYYYY" NULLIF addrdate='00000000'
(the reason why the date was NULL in the sample was that the date
value was read into streetno field).
Thank you for your response. It was very helpful!
> Hi,
>
[quoted text clipped - 6 lines]
> I have created the following sql statement to create the table but it
> needs a few fixes.
[snip]
If you take Sybrand' advice and use a little of your own
imagination, then you might come up with something like this:
create or replace function GetAddrCode( addrcode in varchar2 )
return varchar2 as
begin
return to_char( to_number( addrcode ) );
EXCEPTION
when others then
return null;
end GetAddrCode;
/
You could of course have performed the coersion in place, but
having a function allows you to write neater code in larger
contexts, ime and imo.
Hope this help's.
Cheers,
Chris Val
Chris ( Val ) - 30 May 2005 06:01 GMT
Oop's - Appologies for my nick name.
It was meant to be Chris ( Val ), and not 'foo'.
Cheers,
Chris Val