Skip to Main Content
  • Questions
  • Using output value of column from function for another column in SQL*Loader

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question.

Asked: September 25, 2015 - 10:58 am UTC

Last updated: September 29, 2015 - 3:43 am UTC

Version: 11g

Viewed 1000+ times

You Asked

I am trying to define a SQL*Loader control file where col1 is determined by using a user function which takes a couple of parameters with values from the input file. This part is working fine.

I want to use the value returned by above function as a parameter for another user defined function and that does not work. The value sent to the second function is not the calculated value of the first column.

Is this possible?

Here is my control file
( col1 BOUNDFILLER POSITION(1:8),
col2 INTEGER EXTERNAL "schema_own.get_col2_val(:col1, :col6)",
col3 POSITION(29:33) CHAR,
col4 "sysdate",
col5 constant " ",
col6 POSITION(9:11) CHAR,
col7 "sysdate",
col8 POSITION(12:18) CHAR,
col9 POSITION(19:28) CHAR,
col10 POSITION(29:33) CHAR,
col11 POSITION(52:63) CHAR,
col12 "(col2)", --constant "TEST",
col13 "schema_own.get_col13_value(:col1, :col2)",
LAST_UPDATE_TS "sysdate",
LAST_UPDATE_USER_I constant "SQLLDR"
)

What seems to be happening is that the second parameter in get_col13_value seems to contain the FIRST character of the col6 instead of the number that col2 should have from the call to get_col2_val.

I tried col12 with both (col2) and (:col2) - same outcome.

Am I missing something?

Also, when to use col2 vs. :col2 in sql loader?

Thanks

and Connor said...

If you consider the following simplified control file

load data
infile *
into table T
replace
trailing nullcols
( col1 BOUNDFILLER POSITION(1:8),
  col2 INTEGER EXTERNAL "f1(:col1, :col6)",
  col3 POSITION(10:12) CHAR,
  col6 POSITION(20:22) CHAR,
  col13 "f2(:col1,:col2)"
)
BEGINDATA
ABC      A3        B6
EFG      E3        F6
HIJ      H3        I6


then what SQL Loader is doing is effectively forming the following insert statement

insert into T
( col1,
  col2,
  col3,
  col6,
  col13
values
( :col1,
  f1(:col1, :col6),
  :col3,
  :col6,
  f2(:col1,:col2)
)  


So you can see why a reference to ":col2" isnt going to really assist, because nothing has been bound into col2, at the point of time you do the insert.

I'd suggest you nest the functions

load data
infile *
into table T
replace
trailing nullcols
( col1 BOUNDFILLER POSITION(1:8),
  col2 INTEGER EXTERNAL "f1(:col1, :col6)",
  col3 POSITION(10:12) CHAR,
  col6 POSITION(20:22) CHAR,
  col13 "f2(:col1,f1(:col1, :col6))"
)
BEGINDATA
ABC      A3        B6
EFG      E3        F6
HIJ      H3        I6



I tested with the following table / functions

SQL> create table T
  2  ( col1 varchar2(20),
  3    col2 int,
  4    col3 varchar2(10),
  5    col6 varchar2(10),
  6    col13 varchar2(20)
  7  )
  8  /

Table created.

SQL>
SQL> create or replace function F1(a varchar2,b varchar2) return int is
  2  begin
  3    return ascii(a)+ascii(b);
  4  end;
  5  /

Function created.

SQL>
SQL> create or replace function F2(a varchar2,b int) return varchar2 is
  2  begin
  3    return a||b;
  4  end;
  5  /

Function created.


and then ran sqllldr and got the desired result

SQL> select * from t;

COL1                       COL2 COL3       COL6       COL13
-------------------- ---------- ---------- ---------- ----------
                            131 A3         B6         ABC131
                            139 E3         F6         EFG139
                            145 H3         I6         HIJ145


Rating

  (2 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Calling the function f1 two times

A B, September 26, 2015 - 11:46 am UTC

Hi,

Thank you. My problem here is f1, in my case, gets the next sequence, so when I call it in two places, I don't get the value that was assigned to column2. I guess, I will have to re-think my f1 or f2 so that I get the assigned value for column2. Any suggestions for how I could achieve that?
Connor McDonald
September 28, 2015 - 3:42 am UTC

You could use a trigger to fire off for the second function you need to get, and then reference :new.col2

Hope this helps.

How will that work

A B, September 28, 2015 - 1:13 pm UTC

How will I define the trigger? How will that work? The first function f1 that sets value for column2 - has a logic that either returns an existing value or a new value from the sequence.

Can you give me an example on how I would use a trigger to get the value of column 2 for next use?

Thank for your help
Connor McDonald
September 29, 2015 - 3:43 am UTC

you said (or I interpreted as such) that col2 is "ok", it it getting the value back from the function as you expect. The problem is that this value is not available for use in the second function you are using to work out col13. (I'm using the names in *my* test case here)

My suggestion is

- leave col2 as is (ie, function being called in sqlldr)
- leave col13 *out* of the sqlldr processing
- have a trigger that will populate col13, because at that point, we now know the value of col2, ie

:new.col13 := f2(:new.col1, :new.col2);

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library