SQL*Loader的使用方法

eric0435發表於2013-10-06
SQL*Loader(SQLLDR)是Oracle的高速批次資料載入工具。這是一個非常有用的工具,可用於多種平面檔案格式向Oralce資料庫 中載入資料。SQLLDR可以在極短的時間內載入數量龐大的資料。它有兩種操作模式:
傳統路徑:(conventional path):SQLLDR會利用SQL插入為我們載入資料。
直接路徑(direct path):採用這種模式,SQLLDR不使用SQL;而是直接格式化資料庫塊。
利用直接路徑載入,能從一個平面檔案讀資料,並將其直接寫至格式化的資料庫塊,而繞過整個SQL引擎和undo生成,同時還 可能避開redo生成。要在一個沒有任何資料的資料庫中充分載入資料,最快的方法就是採用並行直接路徑載入。

如果不帶任何輸入地從命令列執行SQLLDR,它會提供以下幫助:
[oracle@jy ~]$ sqlldr

SQL*Loader: Release 10.2.0.1.0 - Production on Thu Oct 3 11:32:22 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.


Usage: SQLLDR keyword=value [,keyword=value,...]

Valid Keywords:

    userid -- ORACLE username/password
   control -- control file name
       log -- log file name
       bad -- bad file name
      data -- data file name
   discard -- discard file name
discardmax -- number of discards to allow          (Default all)
      skip -- number of logical records to skip    (Default 0)
      load -- number of logical records to load    (Default all)
    errors -- number of errors to allow            (Default 50)
      rows -- number of rows in conventional path bind array or between direct path data saves
               (Default: Conventional path 64, Direct path all)
  bindsize -- size of conventional path bind array in bytes  (Default 256000)
    silent -- suppress messages during run (header,feedback,errors,discards,partitions)
    direct -- use direct path                      (Default FALSE)
   parfile -- parameter file: name of file that contains parameter specifications
  parallel -- do parallel load                     (Default FALSE)
      file -- file to allocate extents from
skip_unusable_indexes -- disallow/allow unusable indexes or index partitions  (Default FALSE)
skip_index_maintenance -- do not maintain indexes, mark affected indexes as unusable  (Default FALSE)
commit_discontinued -- commit loaded rows when load is discontinued  (Default FALSE)
  readsize -- size of read buffer                  (Default 1048576)
external_table -- use external table for load; NOT_USED, GENERATE_ONLY, EXECUTE  (Default NOT_USED)
columnarrayrows -- number of rows for direct path column array  (Default 5000)
streamsize -- size of direct path stream buffer in bytes  (Default 256000)
multithreading -- use multithreading in direct path
 resumable -- enable or disable resumable for current session  (Default FALSE)
resumable_name -- text string to help identify resumable statement
resumable_timeout -- wait time (in seconds) for RESUMABLE  (Default 7200)
date_cache -- size (in entries) of date conversion cache  (Default 1000)

PLEASE NOTE: Command-line parameters may be specified either by
position or by keywords.  An example of the former case is 'sqlldr
scott/tiger foo'; an example of the latter is 'sqlldr control=foo
userid=scott/tiger'.  One may specify parameters by position before
but not after parameters specified by keywords.  For example,
'sqlldr scott/tiger control=foo logfile=log' is allowed, but
'sqlldr scott/tiger control=foo log' is not, even though the
position of the parameter 'log' is correct.

要使用SQLLDR,需要有一個控制檔案(control file).控制檔案中包含描述輸入資料的資訊(如輸入資料的佈局、資料型別等),另外還包含有關目標表的資訊.控制檔案甚至還可以包含要載入的資料.在下面的例子中,我們將一步一步地建立一個簡單的控制檔案,並對這些命令提供必須的解釋
(1) LOAD DATA
(2) INFILE *
(3) INTO TABLE DEPT
(4) FIELDS TERMINATED BY ','
(5) (DEPTNO, DNAME, LOC )
(6) BEGINDATA
(7) 10,Sales,Virginia
(8) 20,Accounting,Virginia
(9) 30,Consulting,Virginia
(10) 40,Finance,Virginia

[oracle@jy ~]$ vi demo1.ctl
LOAD DATA
INFILE *
INTO TABLE DEPT
FIELDS TERMINATED BY ','
(DEPTNO, DNAME, LOC )
BEGINDATA
10,Sales,Virginia
20,Accounting,Virginia
30,Consulting,Virginia
40,Finance,Virginia

~

LOAD DATA:這會告訴SQLLDR要做什麼(在這個例子中,則指示要載入資料).SQLLDR還可以執行CONTINUE_LOAD,也就是繼續載入.只有在繼續一個多表直接路徑載入時才能使用後面這個選項.

INFILE *:這會告訴SQLLDR所要載入的資料實際上包含在控制檔案本身上,如第6~10行所示.也可以指定包含資料的另一個檔案的檔名.如果願意,可以使用一個命令列引數覆蓋這個INFILE語句.要注意的是命令列選項總會涵蓋控制檔案設定.

INTO TABLE DEPT:這會告訴SQLLDR要把資料載入到哪個表中(在這個例子中,資料要載入到DEPT表中).

FIELDS TERMINATED BY ',':這會告訴SQLLDR資料的形式應該是用逗號分隔的值.為SQLLDR描述輸入資料的方式有數十種;這只是其中較為常用的方法之一.

(DEPTNO, DNAME, LOC):這會告訴SQLLDR所要載入的列,這些列在輸入資料中的順序以及資料型別.這是指輸入流中資料的資料型別,而不是資料庫中的資料型別.在這個例子中,列的資料型別預設為CHAR(255),這已經足夠了.

BEGINDATA:這會告訴SQLLDR你已經完成對輸入資料的描述,後面的行(第7~10行)是要載入到DEPT表的具體資料.

這個控制檔案採用了最簡單,最常用的格式之一:將定界資料載入到一個表.要使用這個控制檔案(名為demo1.ctl),只需建立一個空的DEPT表:
sys@JINGYONG> create table dept
  2  (deptno number(2) constraint dept_pk primary key,
  3  dname varchar2(14),
  4  loc varchar2(14)
  5  );

表已建立。


並執行以下命令:
[oracle@jy ~]$ sqlldr userid=jy/jy control=demo1.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Thu Oct 3 11:43:20 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 5

如果表非空,就會收到一個錯誤訊息:
SQLLDR-601: For INSERT option, table must be empty. Error on table DEPT

這是因為,這個控制檔案中幾乎所有選項都取預設值,而預設的載入選項是INSERT(而不是APPEND,TRUNCATE或REPLACE).要執行INSERT,SQLLDR就認為表為空.如果想向DEPT表中增加記錄,可以指定載入選項為APPEND;或者,為了替換DEPT表中的資料,可以使用REPLACE或TRUNCATE.REPLACE使用一種傳統DELETE語句;因此,如果要載入的表中已經包含許多記錄,這個操作可能執行得很慢.TRUNCATE則不同,它使用TRUNCATE SQL命令,通常會更快地執行,因為它不必物理地刪除每一行.

每個載入都會生成一個日誌檔案,以上這個簡單載入的日誌檔案如下:
[oracle@jy ~]$ cat demo1.log

SQL*Loader: Release 10.2.0.1.0 - Production on Thu Oct 3 11:43:20 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Control File:   demo1.ctl
Data File:      demo1.ctl
  Bad File:     demo1.bad
  Discard File:  none specified

 (Allow all discards)

Number to load: ALL
Number to skip: 0
Errors allowed: 50
Bind array:     64 rows, maximum of 256000 bytes
Continuation:    none specified
Path used:      Conventional

Table DEPT, loaded from every logical record.
Insert option in effect for this table: INSERT

   Column Name                  Position   Len  Term Encl Datatype
------------------------------ ---------- ----- ---- ---- ---------------------
DEPTNO                              FIRST     *   ,       CHARACTER
DNAME                                NEXT     *   ,       CHARACTER
LOC                                  NEXT     *   ,       CHARACTER

Record 5: Rejected - Error on table DEPT, column DEPTNO.
Column not found before end of logical record (use TRAILING NULLCOLS)

Table DEPT:
  4 Rows successfully loaded.
  1 Row 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.


Space allocated for bind array:                  49536 bytes(64 rows)
Read   buffer bytes: 1048576

Total logical records skipped:          0
Total logical records read:             5
Total logical records rejected:         1
Total logical records discarded:        0

Run began on Thu Oct 03 11:43:20 2013
Run ended on Thu Oct 03 11:43:21 2013

Elapsed time was:     00:00:00.38
CPU time was:         00:00:00.09
日誌檔案會告訴我們關於載入的很多方面,從中可以看到我們所用的選項(預設或預設選項);可以看到讀取了多少記錄,載入 了多少記錄等.日誌檔案指定了所有BAD檔案和DISCARD檔案的位置,甚至還會告訴我們載入用了多長時間.每個日誌檔案對於驗 證載入是否成功至關重要,另外對於診斷錯誤也很有意義.如果所載入的資料導致SQL錯誤(也就是說,輸入資料是"壞的",並在BAD檔案中建立了記錄),這些錯誤就會記錄在這個日誌檔案中.

如何載入定界資料
定界資料(delimited data)即用某個特定字元分隔的資料,可以用引號括起,這是當前平面檔案最常見的資料格式.在大型機 上,定長,固定格式的檔案可能是最可識別的檔案格式,但是在UNIX和NT上,定界檔案才是"標準".

對於定界資料,最常用的格式是逗號分隔值(comma-separated values,CSV)格式.採用這種檔案格式,資料中的每個欄位與 下一個欄位用一個逗號分隔.文字串可以用引號括起,這樣就允許串本身包含逗號.如果串還必須包含引號,一般約定是使用兩個引號(在下面的程式碼中,將使用""而不是'').要載入定界資料,相應的典型控制檔案與前面第一個例子很相似,但是FIELDS TERMINATED BY 子句通常如下指定:

FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'

它指定用逗號分隔資料欄位,每個欄位可以用雙引號括起,如果我們把這個控制檔案的最後部分修改如下:
[oracle@jy ~]$ cat demo2.ctl
LOAD DATA
INFILE *
INTO TABLE DEPT
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
(DEPTNO, DNAME, LOC )
BEGINDATA
10,Sales,"Virginia,USA"
20,Accounting,"Va,""USA"""
30,Consulting,Virginia
40,Finance,Virginia

使用這個控制檔案執行SQLLDR時,結果如下:
[oracle@jy ~]$ sqlldr userid=jy/jy control=demo2.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Thu Oct 3 12:01:03 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 5

使用這個控制檔案執行SQLLDR時,結果如下:
jy@JINGYONG> select * from dept;

    DEPTNO DNAME          LOC
---------- -------------- --------------
        10 Sales          Virginia,USA
        20 Accounting     Va,"USA"
        30 Consulting     Virginia
        40 Finance        Virginia

要注意以下幾點:
部門10中的Virginia.USA:這是因為輸入資料是"Virginia,USA".輸入資料欄位必須包括在引號裡才能保留資料中的逗號.否 則,資料中的這個逗號會被認為是欄位結束標記,這樣就會只載入Virginia,而沒有USA文字.

Va,"USA":這是因為輸入資料是"Va,""USA""".對於引號括起的串,SQLLDR會把其中"的兩次出現計為一次出現.要載入一個包含可選包圍字元(enclosure character)的串,必須保證這個包圍字元出現兩次.

另一種常用的格式是製表符定界資料(tag-delimited data),這是用製表符分隔而不是逗號分割的資料.有兩種方法使用 TERMINATED BY子句來載入這種資料:
TERMINATED BY X'09'(使用十六進位制格式的製表符;採用ASCII時,製表符為9)
TERMINATED BY WHITESPACE
這兩種方法在實現上有很大差異,下面將會說明.還是用前面的DEPT表,我們將使用以下控制檔案載入這個表:
[oracle@jy ~]$ vi demo3.ctl
LOAD DATA
INFILE *
INTO TABLE DEPT
FIELDS TERMINATED BY WHITESPACE
(DEPTNO, DNAME, LOC )
BEGINDATA
10  Sales  Virginia

從字面上不太容易看得出來,不過要知道,在這裡各部分資料之間都有兩個製表符.這裡的資料行實際上是:
10\t\tSales\t\tVirginia
在此\t是普通可識別的製表符跳脫字元.使用這個控制檔案時(包含如前所示的TERMINATED BY WHITESPACE),表DEPT中的資料將是:
jy@JINGYONG> select * from dept;

    DEPTNO DNAME          LOC
---------- -------------- --------------
        10 Sales          Virginia


TERMINATED BY WHITESPACE會解析這個串,查詢空白符(製表符,空格和換行符)的第一次出現,然後繼續查詢,直至找到下一 個非空白符.

另一方面,如果要使用FIELDS TERMINATED BY X'09',如以下控制檔案所示,這裡稍做修改:
[oracle@jy ~]$ cat demo4.ctl
LOAD DATA
INFILE *
INTO TABLE DEPT
REPLACE
FIELDS TERMINATED BY "X'09'"
TRAILING NULLCOLS
(DEPTNO,DNAME,LOC )
BEGINDATA
10      sales   virginia

[oracle@jy ~]$ sqlldr userid=jy/jy control=demo4.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Fri Oct 4 08:07:43 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 1

可以看到DEPT中載入了以下資料:
jy@JINGYONG> select * from dept_1;

DEPTNO               DNAME          LOC
-------------------- -------------- --------------
10      sales   virginia

載入這樣的定界資料時,很可能想逃過輸入記錄中的某些列.例如,你可能載入欄位1,3和5,而跳過第2列和第4列.為此SQLLDR提供了FILLER關鍵字.這允許你對映一個輸入記錄中的一列,但不把它放在資料庫中.例如,給定DEPT表以及先前的一個控制檔案,可以修改這個控制檔案,使用FILLER關鍵字正確地載入資料(跳過製表符):
[oracle@jy ~]$ vi demo3.ctl
LOAD DATA
INFILE *
INTO TABLE DEPT
FIELDS TERMINATED BY WHITESPACE
(DEPTNO, dummy1 filler, DNAME, dummy2 filler, LOC)
BEGINDATA
10  Sales  Virginia

所得到的表DEPT現在如下所示:
jy@JINGYONG> select * from dept;

    DEPTNO DNAME          LOC
---------- -------------- --------------
        10 Sales          Virginia


如何載入固定格式資料
通常會有一個有某個外部系統生成的平面檔案,而且這是一個定長檔案,其中包含著固定位置的資料(positional data).例 如,NAME欄位位於第1~10位元組,ADDRESS欄位位於地11~35位元組等.

這種定寬的固定位置資料是最適合SQLLDR載入的資料格式.要載入這種資料,使用SQLLDR是最快的處理方法,因為解析輸入資料流相當容易.SQLLDR會在資料記錄中儲存固定位元組的偏移量和長度,因此抽取某個給定欄位相當簡單.如果要載入大量資料,將其轉換為一種固定位置格式通常是最好的辦法.當然,定寬檔案也有一個缺點,它比簡單的定界檔案格式可能要大得多.

要載入定寬的固定位置資料,將會在控制檔案中使用POSITION關鍵字,例如:
[oracle@jy ~]$ vi demo5.ctl
LOAD DATA
INFILE *
INTO TABLE DEPT
(DEPTNO position(1:2),DNAME position(3:16),LOC position(17:30) )
BEGINDATA
10Accounting Virginia,USA





QL*Loader: Release 10.2.0.1.0 - Production on Thu Oct 3 12:21:04 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 2

jy@JINGYONG> select * from dept;

    DEPTNO DNAME          LOC
---------- -------------- --------------
        10 Accounting Vir ginia,USA


這個控制檔案沒有使用FIELDS TERMINATED BY子句;而是使用了POSITION來告訴SQLLDR欄位從哪裡開始,到哪裡結束.關於 POSITION子句有意思的是,我們可以使用重疊的位置,可以在記錄中來回反覆.例如,如果如下修改DEPT表:
jy@JINGYONG> alter table dept add entire_line varchar2(30);

表已更改。

並使用以下控制檔案:
[oracle@jy ~]$ vi demo6.ctl
LOAD DATA
INFILE *
INTO TABLE DEPT
REPLACE
(DEPTNO position(1:2),
DNAME position(3:16),
LOC position(17:30),
ENTIRE_LINE position(1:30)
)
BEGINDATA
10Accounting Virginia,USA

欄位ENTIRE_LINE定義的POSITION(1:30).這會從所有30位元組的輸入資料中抽取出這個欄位的資料,而其他欄位都是輸入資料的子串.這個控制檔案的輸出如下:
jy@JINGYONG> select * from dept;

    DEPTNO DNAME          LOC            ENTIRE_LINE
---------- -------------- -------------- -----------------------------
        10 Accounting Vir ginia,USA      10Accounting Virginia,USA

使用POSITION時,可以使用相對偏移量,也可以使用絕對偏移量.在前面的例子中使用了絕對偏移量,我們明確地指示了欄位從 哪裡開始,到哪裡結束.也可以把前面的控制檔案寫作:
[oracle@jy ~]$ vi demo7.ctl
LOAD DATA
INFILE *
INTO TABLE DEPT
REPLACE
(DEPTNO position(1:2),
DNAME position(*:16),
LOC position(*:30),
ENTIRE_LINE position(1:30)
)
BEGINDATA
10Accounting Virginia,USA

[oracle@jy ~]$ sqlldr userid=jy/jy control=demo7.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Thu Oct 3 12:25:53 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 2

jy@JINGYONG> select * from dept;

    DEPTNO DNAME          LOC            ENTIRE_LINE
---------- -------------- -------------- -----------------------------
        10 Accounting Vir ginia,USA      10Accounting Virginia,USA

*指示控制檔案得出上一個欄位在哪裡結束.因此,在這種情況下,(*:16)與(3:16)是一樣的.注意,控制檔案中可以混合使用相對位置和絕對位置.另外,使用*表示法時,可以把它與偏移量相加.例如,如果DNAME從DEPTNO結束之後的2個位元組處開始,可以使用(*+2:16).在這個例子中,其作用就相當於使用(5:16).

POSITION子句中的結束位置必須是資料結束的絕對列位置.有時,可能指定每個欄位的長度更為容易,特別是如果這些欄位是連 續的(就像前面的例子一樣).採用這種方式,只需告訴SQLLDR:記錄從第1個位元組開始,然後指定每個欄位的長度就行了.這樣我們就可以免於計算記錄中的開始和結束偏移量,這個計算有時可能很困難.為此,可以不指定結束位置,而是指定定長記錄中各個欄位的長度,如下:
[oracle@jy ~]$ vi demo8.ctl
REPLACE
LOAD DATA
INFILE *
INTO TABLE DEPT
(DEPTNO position(1) char(2),
DNAME position(*) char(14),
LOC position(*) char(14),
ENTIRE_LINE position(1:30)
)
BEGINDATA
10Accounting Virginia,USA

[oracle@jy ~]$ sqlldr userid=jy/jy control=demo8.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Thu Oct 3 12:29:01 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 2

jy@JINGYONG> select * from dept;

    DEPTNO DNAME          LOC            ENTIRE_LINE
---------- -------------- -------------- -----------------------------
        10 Accounting Vir ginia,USA      10Accounting Virginia,USA


在此只需告訴SQLLDR第一個欄位從哪裡開始及其長度.後面的每個欄位都從上一個欄位結束處開始,並具有指定的長度.直至最 後一個欄位才需要再次指定位置,因為這個欄位又要從記錄起始處開始.

如何載入日期
使用SQLLDR載入日期相當簡單,但是看起來這個方面經常導致混淆.你只需在控制檔案中使用DATE資料型別,並指定要使用的日 期格式,這個日期格式與資料庫中TO_CHAR和TO_DATE中使用的日期格式是一樣的.SQLLDR會向資料應用這個日期格式,併為你完成載入.

例如,如果再把DEPT表修改如下:
jy@JINGYONG> alter table dept add last_updated date;

表已更改。
可以用以下控制檔案載入它:
[oracle@jy ~]$ vi demo9.ctl
LOAD DATA
INFILE *
INTO TABLE DEPT
REPLACE
FIELDS TERMINATED BY ','
(DEPTNO,
DNAME,
LOC,
ENTIRE_LINE,
LAST_UPDATED date 'yyyy-mm-dd'
)
BEGINDATA
10,Sales,Virginia,USA,2000-05-01
20,Accounting,Virginia,USA,1999-06-21
30,Consulting,Virginia,USA,2000-01-05
40,Finance,Virginia,USA,2001-03-15

[oracle@jy ~]$ sqlldr userid=jy/jy control=demo9.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Thu Oct 3 12:47:17 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 5


jy@JINGYONG> select * from dept;

    DEPTNO DNAME          LOC            ENTIRE_LINE                   LAST_UPDATED
---------- -------------- -------------- ----------------------------- --------------
        10 Sales          Virginia       USA                           01-5月 -00
        20 Accounting     Virginia       USA                           21-6月 -99
        30 Consulting     Virginia       USA                           05-1月 -00
        40 Finance        Virginia       USA                           15-3月 -01

就這麼簡單,只需在控制檔案中應用格式,SQLLDR就會為我們完成日期轉換.在某些情況下可能使用一個更強大的SQL函式更為合適.例如,如果你的輸入檔案包含多種不同格式的日期:有些有時間分量,有些沒有;有些採用DD-MON-YYYY格式;有些格式為DD/MM/YYYY等等.

如果使用函式載入資料
在SQLLDR中使用函式很容易.要在SQLLDR指令碼中向某個欄位應用一個函式,只需將這個函式增加到控制檔案中(用兩個引號括起).例如,假設有前面的DEPT表,你想確保所載入的資料都是大寫的.可以使用以下控制檔案來載入:
[oracle@jy ~]$ vi demo10.ctl
LOAD DATA
INFILE *
INTO TABLE DEPT
REPLACE
FIELDS TERMINATED BY ','
(DEPTNO,
DNAME "upper(:dname)",
LOC "upper(:loc)",
ENTIRE_LINE "upper(:entire_line)",
LAST_UPDATED date 'yyyy-mm-dd'
)
BEGINDATA
10,Sales,Virginia,USA,2000-05-01
20,Accounting,Virginia,USA,1999-06-21
30,Consulting,Virginia,USA,2000-01-05
40,Finance,Virginia,USA,2001-03-15

"demo10.ctl" 17L, 342C written
[oracle@jy ~]$ sqlldr userid=jy/jy control=demo10.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Thu Oct 3 12:50:46 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 5

jy@JINGYONG> select * from dept;

    DEPTNO DNAME          LOC            ENTIRE_LINE                   LAST_UPDATED
---------- -------------- -------------- ----------------------------- --------------
        10 SALES          VIRGINIA       USA                           01-5月 -00
        20 ACCOUNTING     VIRGINIA       USA                           21-6月 -99
        30 CONSULTING     VIRGINIA       USA                           05-1月 -00
        40 FINANCE        VIRGINIA       USA                           15-3月 -01

可以注意到,只需向一個繫結變數應用UPPER函式就可以很容易地將資料變為大寫.要注意SQL函式可以引用任何列,而不論將 函式實際上應用於哪個列.這說明一個列可以是對兩個或更多其他列應用一個函式的結果.例如,如果你想載入ENTIRE_LINE 列,可以使用SQL連線運算子.不過這種情況下這樣做稍有些麻煩.現在,輸入資料集中有4個資料元素.如果只是向控制檔案中加入如下字元ENTIRE_LINE:
[oracle@jy ~]$ vi demo11.ctl
LOAD DATA
INFILE *
INTO TABLE DEPT
REPLACE
FIELDS TERMINATED BY ','
(DEPTNO,
DNAME "upper(:dname)",
LOC "upper(:loc)",
LAST_UPDATED date 'yyyy-mm-dd',
ENTIRE_LINE ":deptno||:dname||:loc||:last_updated"

)
BEGINDATA
10,Sales,Virginia,USA,2000-05-01
20,Accounting,Virginia,USA,1999-06-21
30,Consulting,Virginia,USA,2000-01-05
40,Finance,Virginia,USA,2001-03-15

~
~
~
~
~
"demo11.ctl" 18L, 360C written
[oracle@jy ~]$ sqlldr userid=jy/jy control=demo11.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Thu Oct 3 12:55:32 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 5

在demo11.log日誌檔案中可以看到:
Record 5: Rejected - Error on table DEPT, column DEPTNO.
Column not found before end of logical record (use TRAILING NULLCOLS)
在此,SQLLDR告訴你,沒等處理完所有列,記錄中就沒有資料了.這種情況下,解決方案很簡單.實際上,SQLLDR甚至已經告訴了我們該怎麼做:這就是使用TRAILING NULLCOLS.這樣一來,如果輸入記錄中不存在某一列的資料,SQLLDR就會為該列繫結一個NULL值.在這種情況下,增加TRAILING NULLCOLS會導致繫結變數:ENTIRE_LINE成為NULL,所以再嘗試這個控制檔案:
[oracle@jy ~]$ vi demo11.ctl
LOAD DATA
INFILE *
INTO TABLE DEPT
REPLACE
FIELDS TERMINATED BY ','
TRAILING NULLCOLS
(DEPTNO,
DNAME "upper(:dname)",
LOC "upper(:loc)",
ENTIRE_LINE ":deptno||:dname||:loc||:last_updated",
LAST_UPDATED date 'yyyy-mm-dd'
)
BEGINDATA
10,Sales,Virginia,USA,2000-05-01
20,Accounting,Virginia,USA,1999-06-21
30,Consulting,Virginia,USA,2000-01-05
40,Finance,Virginia,USA,2001-03-15


[oracle@jy ~]$ sqlldr userid=jy/jy control=demo11.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Thu Oct 3 13:00:49 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 5

jy@JINGYONG> select * from dept;

    DEPTNO DNAME          LOC            ENTIRE_LINE                    LAST_UPDATED
---------- -------------- -------------- ------------------------------ --------------
        10 SALES          VIRGINIA       10SalesVirginia2000-05-01      01-5月 -00
        20 ACCOUNTING     VIRGINIA       20AccountingVirginia1999-06-21 21-6月 -99
        30 CONSULTING     VIRGINIA       30ConsultingVirginia2000-01-05 05-1月 -00
        40 FINANCE        VIRGINIA       40FinanceVirginia2001-03-15    15-3月 -01


之所以可以這樣做,原因在於SQLLDR構建其INSERT語句的做法.SQLLDR會檢視前面的控制檔案,並看到控制檔案中的DEPTNO, DNAME,LOC,LAST_UPDATED和ENTIRE_LINE這幾列.它會根據這些列建立5個繫結變數.通常,如果沒有任何函式,所建立的 INSERT語句就是:
INSERT INTO DEPT ( DEPTNO, DNAME, LOC, LAST_UPDATED, ENTIRE_LINE )
VALUES ( :DEPTNO, :DNAME, :LOC, :LAST_UPDATED, :ENTIRE_LINE );

然後再解析輸入流,將值賦給相應的繫結變數,然後執行語句.如果使用函式,SQLLDR會把這些函式結合到INSERT語句中.在上 一個例子中,SQLLDR建立的INSERT語句如下所示:
INSERT INTO T (DEPTNO, DNAME, LOC, LAST_UPDATED, ENTIRE_LINE)
VALUES ( :DEPTNO, upper(:dname), upper(:loc), :last_updated,
:deptno||:dname||:loc||:last_updated );

然後再做好準備,把輸入繫結到這個語句,再執行語句.所以SQL中能做的事情都可以結合到SQLLDR指令碼中.由於SQL中增加了 CASE語句,所以這樣做不僅功能極為強大,而且相當容易.例如,假設你的輸入檔案有以下格式的日期:
HH24:MI:SS:只有一個時間;日期預設為SYSDATE.
DD/MM/YYYY:只有一個日期;時間預設為午夜0點.
HH24:MI:SS DD/MM/YYYY:日期和時間都要顯式提供。
可以使用如下的一個控制檔案:
[oracle@jy ~]$ vi demo12.ctl
LOAD DATA
INFILE *
INTO TABLE DEPT
REPLACE
FIELDS TERMINATED BY ','
TRAILING NULLCOLS
(DEPTNO,
DNAME "upper(:dname)",
LOC "upper(:loc)",
ENTIRE_LINE ":deptno||:dname||:loc||:last_updated",
LAST_UPDATED
"case
when length(:last_updated)>9
then to_date(:last_updated,'yyyy-mm-dd hh24:mi:ss')
when instr(:last_updated,':')>0
then to_date(:last_updated,'hh24:mi:ss')
else to_date(:last_updated,'yyyy-mm-dd')
end"
)
BEGINDATA
10,Sales,Virginia,USA,2000-05-01 12:03:03
20,Accounting,Virginia,USA,02:23:54
30,Consulting,Virginia,USA,2000-01-05 01:24:00
40,Finance,Virginia,USA,2001-03-15

[oracle@jy ~]$ sqlldr userid=jy/jy control=demo12.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Thu Oct 3 13:06:49 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 5

jy@JINGYONG> alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss';

會話已更改。

jy@JINGYONG> select * from dept;

    DEPTNO DNAME          LOC            ENTIRE_LINE                                LAST_UPDATED
---------- -------------- -------------- --------------------------------------- ---------------------
        10 SALES          VIRGINIA       10SalesVirginia2000-05-01 12:03:03      2000-05-01 12:03:03
        20 ACCOUNTING     VIRGINIA       20AccountingVirginia02:23:54            2013-10-01 02:23:54
        30 CONSULTING     VIRGINIA       30ConsultingVirginia2000-01-05 01:24:00 2000-01-05 01:24:00
        40 FINANCE        VIRGINIA       40FinanceVirginia2001-03-15             2001-03-15 00:00:00


如何載入有內嵌換行符的資料
過去,如果要載入可能包含換行符的自由格式的資料,這對於SQLLDR來說很成問題.換行符是SQLLDR的預設行結束符,要載入有內嵌換行符的資料有以下方法:
載入資料,其中用非換行符的其他字元來表示換行符(例如,在文字中應該出現換行符的位置上放上串\n),並在載入時使用一個SQL函式用一個CHR(10)替換該文字.

在INFILE指令上使用FIX屬性,載入一個定長平面檔案.

在INFILE指令上使用VAR屬性,載入一個定寬檔案,在該檔案使用的格式中,每一行的前幾個位元組指定了這一行的長度(位元組數 ).

在INFILE指令上使用STR屬性,載入一個變寬檔案,其中用某個字元序列來表示行結束符,而不是用換行符來表示.

使用一個非換行符的字元
如果你能對如何生成輸入資料加以控制,這就是一種很容易的方法.如果建立資料檔案時能很容易地轉換資料,這種方法就能奏 效.其思想是,就資料載入到資料庫時對資料應用一個SQL函式,用某個字串來替換換行符.下面向DEPT表再增加另一個列:
jy@JINGYONG> alter table dept add comments varchar2(4000);

表已更改。

將使用這一列來載入文字,下面是一個有內聯資料的示例控制檔案:
[oracle@jy ~]$vi demo13.ctl
LOAD DATA
INFILE *
INTO TABLE DEPT
REPLACE
FIELDS TERMINATED BY ','
TRAILING NULLCOLS
(DEPTNO,
DNAME "upper(:dname)",
LOC "upper(:loc)",
ENTIRE_LINE ":deptno||:dname||:loc||:last_updated",
LAST_UPDATED
"case
when length(:last_updated)>9
then to_date(:last_updated,'yyyy-mm-dd hh24:mi:ss')
when instr(:last_updated,':')>0
then to_date(:last_updated,'hh24:mi:ss')
else to_date(:last_updated,'yyyy-mm-dd')
end",
COMMENTS "replace(:comments,'\\n',chr(10))"
)
BEGINDATA
10,Sales,Virginia,USA,2000-05-01 12:03:03,This is the Sales\nOffice in Virginia
20,Accounting,Virginia,USA,02:23:54,This is the Accountin\nOffice in Virginia
30,Consulting,Virginia,USA,2000-01-05 01:24:00,This is the Consulting\nOffice in Virginia
40,Finance,Virginia,USA,2001-03-15,This is the Finance\nOffice in Virginia

[oracle@jy ~]$ sqlldr userid=jy/jy control=demo13.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Thu Oct 3 14:45:48 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 5
注意,呼叫中必須使用\\n來替換換行符,而不只是\n.這是因為\n會被SQLLDR識別為一個換行符,而且SQLLDR會把它轉換為一 個換行符,而不是一個兩字元的串.利用以上控制檔案執行SQLLDR時,DEPT表中將載入以下資料:
jy@JINGYONG> select * from dept;

    DEPTNO DNAME          LOC            ENTIRE_LINE                        LAST_UPDATED            COMMENTS
--------------------------------------------------------------------------------------------------------------- -------------------------------------------------
        10 SALES          VIRGINIA       10SalesVirginia2000-05-01 12:03:03 2000-05-01 12:03:03  This is the  Sales Office in Virginia

        20 ACCOUNTING     VIRGINIA       20AccountingVirginia02:23:54       2013-10-01 02:23:5   This is the  Accountin Office in Virginia

        30 CONSULTING     VIRGINIA       30ConsultingVirginia2000-01-05 01:24:00 2000-01-05 01:24:00 This is the  Consulting Office in Virginia

        40 FINANCE        VIRGINIA       40FinanceVirginia2001-03-15             2001-03-15 00:00:00 This is the  Finance Office in Virginia

使用IFX屬性
另一種可用的方法是使用FIX屬性.如果使用這種方法,輸入資料必須出現在定長記錄中.每個記錄與輸入資料集中所有其他記 錄的長度都相同,即有相同的位元組數.對於固定位置的資料,使用FIX屬性就特別適合.這些檔案通常是定長輸入檔案.使用自由格式的定界資料時,則不太可能是一個定長檔案,因為這些檔案通常是變長的(這正是定界檔案的關鍵:每一行不會不必要地過長).
使用FIX屬性時,必須使用一個INFILE子句,因為FIX屬性是INFILE的一個選項.另外,如果使用這個選項,資料必須在外部儲存 ,而並非儲存在控制檔案本身.因此,假設有定長的輸入記錄,可以使用如下的一個控制檔案:
[oracle@jy ~]$ vi demo14.ctl
LOAD DATA
INFILE demo14.dat "fix 80"
INTO TABLE DEPT
REPLACE
FIELDS TERMINATED BY ','
TRAILING NULLCOLS
(DEPTNO,
DNAME "upper(:dname)",
LOC "upper(:loc)",
ENTIRE_LINE ":deptno||:dname||:loc||:last_updated",
LAST_UPDATED
"case
when length(:last_updated)>9
then to_date(:last_updated,'yyyy-mm-dd hh24:mi:ss')
when instr(:last_updated,':')>0
then to_date(:last_updated,'hh24:mi:ss')
else to_date(:last_updated,'yyyy-mm-dd')
end",
COMMENTS
)

[oracle@jy ~]$ vi demo14.dat
10,Sales,Virginia,USA,2000-05-01 12:03:03,This is the Sales\nOffice in Virginia
20,Accounting,Virginia,USA,02:23:54,This is the Accountin\nOffice in Virginia\n
30,Consulting,Virginia,USA,2000-01-05 01:24:00,This is the Consulting\nOffice\n
40,Finance,Virginia,USA,2001-03-15,This is the Finance\nOffice in Virginia   \n


這個檔案指定了一個輸入資料檔案(domo14.dat),這個檔案中每個記錄有80位元組,這包括尾部的換行符(每個記錄最後可能有換行符,也可能沒有).在這種情況下,輸入資料檔案中的換行符並不是特殊字元.這只是要載入(或不載入)的另一個字元而已.要知道:記錄的最後如果有換行符,它會成為這個記錄的一部分.為了充分理解這一點,我們需要一個實用程式將檔案的內容轉儲在螢幕上,以便我們看到檔案中到底有什麼.使用Linux(或任何Unix版本)利用od就很容易做到,這個程式可以將檔案以八進位制(和其他格式)轉儲到螢幕上.我們將使用下面的demo.dat檔案.注意以下輸入中的第一列實際上是八進位制,所以第2行上的數字0000012是一個八進位制數,不是十進位制數10.由此我們可以知道所檢視的檔案中有哪些位元組.我對這個輸出進行了格式化,使得每行顯示10個字元(使用-w10),所以0,12,24和36實際上就是0,10,20和30.
[oracle@jy ~]$ od -c -w10 -v demo14.dat
0000000   a   l   e   s   ,   V   i   r   g   i
0000012   n   i   a   ,   U   S   A   ,   2   0
0000024   0   0   -   0   5   -   0   1       1
0000036   2   :   0   3   :   0   3   ,   T   h
0000050   i   s       i   s       t   h   e
0000062   S   a   l   e   s   \   n   O   f   f
0000074   i   c   e       i   n       V   i   r
0000106   g   i   n   i   a  \n   2   0   ,   A
0000120   c   c   o   u   n   t   i   n   g   ,
0000132   V   i   r   g   i   n   i   a   ,   U
0000144   S   A   ,   0   2   :   2   3   :   5
0000156   4   ,   T   h   i   s       i   s
0000170   t   h   e       A   c   c   o   u   n
0000202   t   i   n   \   n   O   f   f   i   c
0000214   e       i   n       V   i   r   g   i
0000226   n   i   a  \n   3   0   ,   C   o   n
0000240   s   u   l   t   i   n   g   ,   V   i
0000252   r   g   i   n   i   a   ,   U   S   A
0000264   ,   2   0   0   0   -   0   1   -   0
0000276   5       0   1   :   2   4   :   0   0
0000310   ,   T   h   i   s       i   s       t
0000322   h   e       C   o   n   s   u   l   t
0000334   i   n   g   \   n   O   f   f   i   c
0000346   e       i   n       V   i   r   g   i
0000360   n   i   a  \n   4   0   ,   F   i   n
0000372   a   n   c   e   ,   V   i   r   g   i
0000404   n   i   a   ,   U   S   A   ,   2   0
0000416   0   1   -   0   3   -   1   5   ,   T
0000430   h   i   s       i   s       t   h   e
0000442       F   i   n   a   n   c   e   \   n
0000454   O   f   f   i   c   e       i   n
0000466   V   i   r   g   i   n   i   a  \n
0000477

注意,在這個輸入檔案中,並沒有用換行符(\n)來指示SQLLDRE記錄在哪裡結束;這裡的換行符只是要載入的資料而已.SQLLDR使用FIX寬度(80位元組)來得出要讀取多少資料.實際上,如果檢視輸入資料,可以看到,輸入檔案中提供給SQLLDR的記錄甚至並非以\n結束.部門20的記錄之前的字元是一個空格,而不是換行符.
[oracle@jy ~]$ sqlldr userid=jy/jy control=demo14.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Thu Oct 3 15:03:05 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 4
我們知道了每個記錄的長度為80位元組,現在就可以用前面有FIX80子句的控制檔案來載入這些資料了.完成載入後,可以看到以 下結果:
jy@JINGYONG> select * from dept;

DEPTNO DNAME      LOC     ENTIRE_LINE                             LAST_UPDATED        COMMENTS
--------------------------------------------------------------------------------------------------------------- -------------------
    10 SALES      VIRGINIA10SalesVirginia2000-05-01 12:03:03      2000-05-01 12:03:03 This is the Sales\nOffice  in Virginia

    20 ACCOUNTING VIRGINIA20AccountingVirginia02:23:54            2013-10-01 02:23:54 This is the  Accountin\nOffice in Virginia\n

    30 CONSULTING VIRGINIA30ConsultingVirginia2000-01-05 01:24:00 2000-01-05 01:24:00 This is the  Consulting\nOffice\n

    40 FINANCE    VIRGINIA40FinanceVirginia2001-03-15             2001-03-15 00:00:00 This is the  Finance\nOffice in Virginia   \n


你可能需要截斷這個資料,因為尾部的空白符會保留.可以在控制檔案中使用TRIM內建SQL函式來完成截斷.
Linux上 ,行結束標記就是\n(SQL中的CHR(10)).在Windows NT上,行結束標記卻是\r\n(SQL中的CHR(13)||CHR(10)).一般來講,如果使用FIX方法,就要確保是在同構平臺上建立和載入檔案(Linux上建立,Linux上載入;或者Windows上建立,Windows上載入)

使用VAR屬性
要載入有內嵌換行符的資料,另一種方法是使用VAR屬性.使用這種格式時,每個記錄必須以某個固定的位元組數開始,這表示這 個記錄的總長度.透過使用這種格式,可以載入包含內嵌換行符的變長記錄,但是每個記錄的開始處必須有一個記錄長度欄位. 因此,如果使用如下的一個控制檔案:
[oracle@jy ~]$ vi demo15.ctl
LOAD DATA
INFILE 'demo15.dat' "var 3"
INTO TABLE DEPT
REPLACE
FIELDS TERMINATED BY ','
TRAILING NULLCOLS
(DEPTNO,
DNAME "upper(:dname)",
LOC "upper(:loc)",
ENTIRE_LINE ":deptno||:dname||:loc||:last_updated",
LAST_UPDATED
"case
when length(:last_updated)>9
then to_date(:last_updated,'yyyy-mm-dd hh24:mi:ss')
when instr(:last_updated,':')>0
then to_date(:last_updated,'hh24:mi:ss')
else to_date(:last_updated,'yyyy-mm-dd')
end",
COMMENTS
)
VAR 3指出每個輸入記錄的前3個位元組是輸入記錄的長度,如果取以下資料檔案:
[oracle@jy ~]$ cat demo15.dat
07910,Sales,Virginia,USA,2000-05-01 12:03:03,This is the Sales Office in Virginia
07820,Accounting,Virginia,USA,02:23:54,This is the Accounting Office in Virginia
08930,Consulting,Virginia,USA,2000-01-05 01:24:00,This is the Consulting Office in Virginia
07440,Finance,Virginia,USA,2001-01-15,This is the Finance Office in Virginia

可以使用該控制檔案來載入.在輸入資料檔案中有4行資料.第一行從079開始,這說明接下來79位元組是第一個輸入記錄.這79字 節包括單詞Virginia後的結束換行符.下一行從078開始,這一行有78位元組的文字,依此類推.使用這種格式資料檔案,可以很 容易地載入有內嵌換行符的資料.
同樣,如果在使用Linux和Windows(前面的例子都在Linux上完成,其中換行符只是一個字元長),就必須調整每個記錄的長度字 段.在Windows上,前例.dat檔案中的長度欄位應該是80,79,90和75.
oracle@jy ~]$ sqlldr userid=jy/jy control=demo15.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Fri Oct 4 05:40:10 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 4

jy@JINGYONG> select * from dept;

DEPTNO DNAME      LOC      ENTIRE_LINE                             LAST_UPDATED        COMMENTS
--------------------------------------------------------------------------------------------------------------- -----------------
    10 SALES      VIRGINIA 10SalesVirginia2000-05-01 12:03:03      2000-05-01 12:03:03 This is the Sales Office  in Virginia

    20 ACCOUNTING VIRGINIA 20AccountingVirginia02:23:54            2013-10-01 02:23:54 This is the Accounting  Office in Virginia

    30 CONSULTING VIRGINIA 30ConsultingVirginia2000-01-05 01:24:00 2000-01-05 01:24:00 This is the Consulting  Office in Virginia

    40 FINANCE    VIRGINIA 40FinanceVirginia2001-01-15             2001-01-15 00:00:00 This is the Finance  Office in Virginia


使用STR屬性
要載入有內嵌換行符的資料,這可能是最靈活的一種方法.透過使用STR屬性,可以指定一個新的行結束符(或字元序列).就能建立一個輸入資料檔案,其中每一行的最後有某個特殊字元,換行符不再有特殊含義.
我更喜歡使用字元序列,通常會使用某個特殊標記,然後再加一個換行符.這樣,在一個文字編輯器或某個實用程式中檢視輸入 資料時,就能很容易地看到行結束符,因為每個記錄的最後仍然有一個換行符.STR屬性以十六進位制指定,要得到所需的具體十 六進位制串,最容易的方法是使用SQL和UTL_RAW來生成十六進位制串.例如,假設使用的是Linux平臺,行結束標記是CHR(10)(換行 ),我們的特殊標記字元是一個管道符號(|),則可以寫為:
jy@JINGYONG>select utl_raw.cast_to_raw('|'||chr(10)) from dual;

UTL_RAW.CAST_TO_RAW('|'||CHR(1
--------------------------------------------------------------------------------
7C0A

由此可知,在Linux上我們需要使用的STR是X'7C0A'.
在Windows上,要使用UTL_RAW.CAST_TO_RAW('|'||chr(13)||chr(10))
為了使用這個方法,要有以下控制檔案:
[oracle@jy ~]$ vi demo16.ctl
LOAD DATA
INFILE demo16.dat "str X'7C0A'"
INTO TABLE DEPT
REPLACE
FIELDS TERMINATED BY ','
TRAILING NULLCOLS
(DEPTNO,
DNAME "upper(:dname)",
LOC "upper(:loc)",
ENTIRE_LINE ":deptno||:dname||:loc||:last_updated",
LAST_UPDATED
"case
when length(:last_updated)>9
then to_date(:last_updated,'yyyy-mm-dd hh24:mi:ss')
when instr(:last_updated,':')>0
then to_date(:last_updated,'hh24:mi:ss')
else to_date(:last_updated,'yyyy-mm-dd')
end",
COMMENTS
)


因此,如果輸入資料如下:
[oracle@jy ~]$ cat demo16.dat
10,Sales,Virginia,USA,2000-05-01 12:03:03,This is the Sales Office in Virginia|
20,Accounting,Virginia,USA,02:23:54,This is the Accounting Office in Virginia|
30,Consulting,Virginia,USA,2000-01-05 01:24:00,This is the Consulting Office in Virginia|
40,Finance,Virginia,USA,2001-01-15,This is the Finance Office in Virginia|

其中,資料檔案中的每個記錄都以|\n結束,前面的控制檔案就會正確地載入這些資料.
[oracle@jy ~]$ sqlldr userid=jy/jy control=demo16.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Fri Oct 4 07:45:30 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 4

jy@JINGYONG> select * from dept;

DEPTNO DNAME      LOC      ENTIRE_LINE                             LAST_UPDATED        COMMENTS
--------------------------------------------------------------------------------------------------------------- -----------------
    10 SALES      VIRGINIA 10SalesVirginia2000-05-01 12:03:03      2000-05-01 12:03:03 This is the Sales Office  in Virginia

    20 ACCOUNTING VIRGINIA 20AccountingVirginia02:23:54            2013-10-01 02:23:54 This is the Accounting  Office in Virginia

    30 CONSULTING VIRGINIA 30ConsultingVirginia2000-01-05 01:24:00 2000-01-05 01:24:00 This is the Consulting  Office in Virginia

    40 FINANCE    VIRGINIA 40FinanceVirginia2001-01-15             2001-01-15 00:00:00 This is the Finance  Office in Virginia


如果載入LOB
現在來考慮在LOB的一些方法.這不是一個LONG或LONG RAW欄位,而是更可取的資料型別BLOB和CLOB.這些資料型別是Oracle  8.0及以後版本中引入的,與遺留的LONG和LONG RAW型別相比,它們支援更豐富的介面/功能集.

將分析兩種載入這些欄位的方法:SQLLDR和PL/SQL.
透過PL/SQL載入LOB
DBMS_LOB包的入口點為LoadFromFile,LoadBLOBFromFile和LoadCLOBFromFile.透過這些過程,我們可以使用一個BFILE(用於讀取作業系統檔案)來填充資料庫中的BLOB或CLOB.LoadFromFile和LoadBLOBFromFile例程之間沒有顯著的差別,只不過後者會返回一些OUT引數,指示已經向BLOB列中載入了多少資料.不過,LoadCLOBFromFile例程還提供了一個突出的特性:字符集轉換.使用LoadCLOBFromFile時,我們可以告訴資料庫:這個檔案將以另外某種字符集(不同於資料庫正在使用的字符集)來載入,而且要執行必要的字符集轉換.例如,可能有一個UTF8相容的資料庫,但是收到的要載入的檔案卻以WE8ISO8859P1字符集編碼,或反之利用這個函式就能成功地載入這些檔案.

要使用這些過程,需要在資料庫中建立一個DIRECTORY物件.這個物件允許我們建立並開啟BFILE(BFILE指向檔案系統上資料庫 伺服器能訪問的一個現有檔案).DBMS_LOB包完全在伺服器中執行.它只能看到伺服器能看到的檔案系統.特別是,如果你透過 網路訪問Oracle,DBMS_LOB包將無法看到你的本地檔案系統.

所以,需要先在資料庫中建立一個DIRECTORY物件.
jy@JINGYONG> create or replace directory dir1 as '/home/oracle';

目錄已建立。

jy@JINGYONG> create or replace directory "dir2" as '/home/oracle';

目錄已建立。

SQL> select * from dba_directories;

OWNER  DIRECTORY_NAME  DIRECTORY_PATH
------ --------------- -----------------
SYS    dir2            /home/oracle
SYS    DIR1            /home/oracle

我們建立的dir1在資料字典中為大寫

下面,將一些資料載入到BLOB或CLOB中:
jy@JINGYONG> create table demo
  2  (id int primary key,
  3  theClob clob
  4  );

表已建立。

[oracle@jy ~]$ echo 'Hello World!'>/home/oracle/demo.txt

jy@JINGYONG> declare
  2   l_clob clob;
  3   l_bfile bfile;
  4  begin
  5   insert into demo values(1,empty_clob()) returning theclob into l_clob;
  6   l_bfile:=bfilename('DIR1','demo.txt');
  7   dbms_lob.fileopen(l_bfile);
  8   dbms_lob.loadfromfile(l_clob,l_bfile,dbms_lob.getlength(l_bfile));
  9   dbms_lob.fileclose(l_bfile);
 10  end;
 11  /

PL/SQL 過程已成功完成。

jy@JINGYONG> select dbms_lob.getlength(theClob), theClob from demo;

DBMS_LOB.GETLENGTH(THECLOB) THECLOB
--------------------------- ----------------------------------------------------
                         13 Hello World!

在第5行我們在表中建立了一行,將CLOB設定為一個EMPTY_CLOB(),並從一個呼叫獲取其值.除了臨時LOB外,其餘的LOB都住在資料庫中,如果沒有指向一個臨時LOB的指標,或者指向一個已經在資料庫中的LOB,將無法寫至LOB變數.EMPTY_CLOB()不是一個NULL CLOB;而是指向一個空結構的合法指標(非NULL),它還有一個作用,可以得到一個LOB定位器,指向已鎖定行中的資料.如果要選擇這個值,而沒有鎖定底層的行,寫資料就會失敗,因為LOB在寫之前必須鎖定(不同於其他結構化資料).透過插入一行,當然我們也就鎖定了這一行.如果我們要修改一個現有的行而不是插入新行,則可以使用SELECT FOR UPDATE來獲取和鎖定這一行.

在第6行上,我們建立了一個BFILE物件.注意,這裡DIR1用的是大寫,稍後就會看到,這是一個鍵.這是因為我們向BFILENAME() 傳入了一個物件的名稱,而不是物件本身.因此,必須確保這個名稱與Oracle所儲存的物件名稱大小寫匹配.

第7行開啟了LOB,以便讀取.

在第8行將作業系統檔案/home/oracle/demo.txt的完整內容載入到剛插入的LOB定位器.這裡使用DBMS_LOB.GETLENGTH()告訴LOADFROMFILE()例程要載入多少位元組的BFILE(這裡就是要載入全部位元組).
最後,在第9行我們關閉了所開啟的BFILE,CLOB已載入.

如果需要在載入檔案的同時處理檔案的內容,還可以在BFILE上使用DBMS_LOB.READ來讀取資料.如果讀取的資料實際上是文字,而不是RAW,那麼使用UTL_RAW.CAST_TO_VARCHAR2會很方便.然後可以使用DBMS_LOB.WRITE或WRITEAPPEND將資料放入一個CLOB或BLOB.

透過SQLLDR載入LOB資料
現在我們來分析如何透過SQLLDR向LOB載入資料.對此方法不止一種,但是我們主要討論兩種最常用的方法:
資料內聯在其他資料中。
資料外聯儲存(在外部儲存),輸入資料包含一個檔名,指示該行要載入的資料在哪個檔案中.在SQLLDR術語中,這也稱為二級資料檔案(secondary data file,SDF).
先從內聯資料談起.
載入內聯的LOB資料,這些LOB通常內嵌有換行符和其他特殊字元.

下面先來修改dept表,使COMMENTS列是一個CLOB而不是一個大的VARCHAR2欄位:
jy@JINGYONG> truncate table dept;

表被截斷。

jy@JINGYONG> alter table dept drop column comments;

表已更改。

jy@JINGYONG> alter table dept add comments clob;

表已更改。

例如,假設有一個資料檔案(demo17.dat),它有以下內容:
[oracle@jy ~]$ cat demo17.dat
10,Sales,Virginia,USA,2000-05-01 12:03:03,This is the Sales Office in Virginia|
20,Accounting,Virginia,USA,02:23:54,This is the Accounting Office in Virginia|
30,Consulting,Virginia,USA,2000-01-05 01:24:00,This is the Consulting Office in Virginia|
40,Finance,Virginia,USA,2001-01-15,"This is the Finance
Office in Virginia, it has embedded commas and is
much longer than the other comments field. If you
feel the need to add double quoted text in here like
this: ""You will need to double up those quotes!"" to
preserve them in the string. This field keeps going for up to
1000000 bytes (because of the control file definition I used)
or until we hit the magic end of record marker,
the | followed by an end of line - it is right here ->"|

每個記錄最後都是一個管道符號(|),後面是行結束標記.部門40的文字比其他部門的文字長得多,有多個換行符,內嵌的引號以及逗號.給定這個資料檔案,可以建立一個如下的控制檔案:
[oracle@jy ~]$ cat demo17.ctl
LOAD DATA
INFILE demo17.dat "str X'7C0A'"
INTO TABLE DEPT
REPLACE
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
TRAILING NULLCOLS
(DEPTNO,
DNAME "upper(:dname)",
LOC "upper(:loc)",
ENTIRE_LINE ":deptno||:dname||:loc||:last_updated",
LAST_UPDATED
"case
when length(:last_updated)>9
then to_date(:last_updated,'yyyy-mm-dd hh24:mi:ss')
when instr(:last_updated,':')>0
then to_date(:last_updated,'hh24:mi:ss')
else to_date(:last_updated,'yyyy-mm-dd')
end",
COMMENTS char(1000000)
)

注意:這個例子在Linux上執行,Linux平臺上行結束標記長度為1位元組,因此可以使用以上控制檔案中的STR設定.在Windows上,STR設定則必須是'7C0D0A'.

要載入這個資料檔案,我們在COMMENTS列上指定了CHAR(1000000),因為SQLLDR預設所有人們欄位都為CHAR(255).CHAR (1000000)則允許SQLLDR處理多達1,000,000位元組的輸入文字.可以把這個長度值設定為大於輸入檔案中任何可能文字塊的大小.透過檢視所載入的資料,可以看到以下結果:

[oracle@jy ~]$ sqlldr userid=jy/jy control=demo17.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Fri Oct 4 09:08:31 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 1
Commit point reached - logical record count 2
Commit point reached - logical record count 3
Commit point reached - logical record count 4

SQL> set long 999;
SQL> select comments from jy.dept;

COMMENTS
--------------------------------------------------------------------------------
This is the Sales Office in Virginia
This is the Accounting Office in Virginia
This is the Consulting Office in Virginia
This is the Finance
Office in Virginia, it has embedded commas and is
much longer than the other comments field. If you
feel the need to add double quoted text in here like
this: "You will need to double up those quotes!" to
preserve them in the string. This field keeps going for up to
1000000 bytes (because of the control file definition I used)
or until we hit the magic end of record marker,
the | followed by an end of line - it is right here ->

這裡可以觀察到:原來重複兩次的引號不再重複,SQLLDR去除了在此放置的額外的引號.


載入外聯的LOB資料,可能要把包含有一些檔名的資料檔案載入在LOB中,而不是讓LOB資料與結構化資料混在一起,這種情況 很常見.這提供了更大程度的靈活性,因為提供給SQLLDR的資料檔案不必使用上述的4種方法之一來避開輸入資料中的內嵌換行 符問題,而這種情況在大量的文字或二進位制資料中會頻繁出現.SQLLDR稱這種額外的資料檔案為LOBFILE.

SQLLDR還可以支援載入結構化資料檔案(指向另外單獨一個資料檔案).我們可能告訴SQLLDR如何從另外這個檔案分析LOB資料 ,這樣就可以載入其中的一部分作為結構化資料中的每一行.這種模式的用途很有限.SQLLDR把這種外部引用的檔案稱為複雜二級資料檔案(complex secondary  data file).

LOBFILE是一種相對簡單的資料檔案,旨在簡化LOB載入.在LOBFILE中,沒有記錄的概念,因此換行符不會成為問題,正是這個 性質使得LOBFILE與主要資料檔案有所區別.在LOBFILE中,資料總是採用以下某種格式:
定長欄位(例如,從LOBFILE載入位元組100到1,000)
定界欄位(以某個字元結束,或者用某個字元括起)
長度/值對,這是一個變長欄位

其中最常見的型別是定界欄位,實際上就是以一個檔案結束符(EOF)結束.一般來講,可能有這樣一個目錄,其中包含你想載入到LOB列中的檔案,每個檔案都要完整地放在一個BLOB中.此時,就可以使用帶TERMINATED BY EOF子句的LOBFILE語句.

假設我們有一個目錄,其中包含想要載入到資料庫中的檔案.我們想載入檔案的OWNER,檔案的TIME_STAMP,檔案的NAME以及文 件本身.要載入資料的表如下所示:
jy@JINGYONG> create table lob_demo
  2  (owner varchar2(255),
  3  time_stamp date,
  4  filename varchar2(255),
  5  data blob
  6  );

表已建立。

在Linux上使用一個簡單的ls -l來捕獲輸出(或者在Windows上使用dir/q/n),我們就能生成輸入檔案,並使用如下的一個控制檔案載入:
[oracle@jy ~]$ cat demo19.ctl
LOAD DATA
INFILE *
INTO TABLE LOB_DEMO
REPLACE
(owner position(14:28),
time_stamp position(36:46) date "MM DD HH24:MI",
filename position(48:100),
data LOBFILE(filename) TERMINATED BY EOF
)
BEGINDATA
-rw-r--r-- 1 oracle oinstall 18432 10  3 10:42 bifile.bbd
-rw-r--r-- 1 oracle oinstall     1 10  3 12:50 demo10.bad
-rw-r--r-- 1 oracle oinstall   342 10  3 12:50 demo10.ctl
-rw-r--r-- 1 oracle oinstall  1948 10  3 12:50 demo10.log
-rw-r--r-- 1 oracle oinstall   144 10  3 12:59 demo11.bad
-rw-r--r-- 1 oracle oinstall   377 10  3 13:00 demo11.ctl
-rw-r--r-- 1 oracle oinstall  1913 10  3 13:00 demo11.log
-rw-r--r-- 1 oracle oinstall    89 10  3 13:06 demo12.bad
-rw-r--r-- 1 oracle oinstall   582 10  3 13:05 demo12.ctl
-rw-r--r-- 1 oracle oinstall  2147 10  3 13:06 demo12.log
-rw-r--r-- 1 oracle oinstall   790 10  3 14:45 demo13.ctl
-rw-r--r-- 1 oracle oinstall  2289 10  3 14:45 demo13.log
-rw-r--r-- 1 oracle oinstall    80 10  3 15:01 demo14.bad
-rw-r--r-- 1 oracle oinstall   441 10  3 15:00 demo14.ctl
-rw-r--r-- 1 oracle oinstall   320 10  3 15:02 demo14.dat
-rw-r--r-- 1 oracle oinstall  2230 10  3 15:03 demo14.log
-rw-r--r-- 1 oracle oinstall   332 10  4 05:42 demo15_bak.dat
-rw-r--r-- 1 oracle oinstall   442 10  4 05:31 demo15.ctl
-rw-r--r-- 1 oracle oinstall   332 10  4 05:45 demo15.dat
-rw-r--r-- 1 oracle oinstall   256 10  4 05:36 demo15.dat.bak
-rw-r--r-- 1 oracle oinstall  2229 10  4 05:45 demo15.log
-rw-r--r-- 1 oracle oinstall     3 10  4 07:44 demo16.bad
-rw-r--r-- 1 oracle oinstall   446 10  4 07:44 demo16.ctl
-rw-r--r-- 1 oracle oinstall   324 10  4 07:45 demo16.dat
-rw-r--r-- 1 oracle oinstall  2235 10  4 07:45 demo16.log
-rw-r--r-- 1 oracle oinstall   487 10  4 09:07 demo17.ctl
-rw-r--r-- 1 oracle oinstall   741 10  4 09:02 demo17.dat
-rw-r--r-- 1 oracle oinstall  2321 10  4 09:08 demo17.log
-rw-r--r-- 1 oracle oinstall   213 10  4 09:05 demo18.ctl
-rw-r--r-- 1 oracle oinstall   665 10  4 09:05 demo18.dat
-rw-r--r-- 1 oracle oinstall  1860 10  4 09:06 demo18.log
-rw-r--r-- 1 oracle oinstall     1 10  3 11:43 demo1.bad
-rw-r--r-- 1 oracle oinstall   177 10  3 11:43 demo1.ctl
-rw-r--r-- 1 oracle oinstall  1648 10  3 11:43 demo1.log
-rw-r--r-- 1 oracle oinstall     1 10  3 12:01 demo2.bad
-rw-r--r-- 1 oracle oinstall   214 10  3 12:00 demo2.ctl
-rw-r--r-- 1 oracle oinstall  1648 10  3 12:01 demo2.log
-rw-r--r-- 1 oracle oinstall     2 10  4 07:59 demo3.bad
-rw-r--r-- 1 oracle oinstall   121 10  4 07:59 demo3.ctl
-rw-r--r-- 1 oracle oinstall  1525 10  4 07:59 demo3.log
-rw-r--r-- 1 oracle oinstall    18 10  4 08:07 demo4.bad
-rw-r--r-- 1 oracle oinstall   141 10  4 08:11 demo4.ctl
-rw-r--r-- 1 oracle oinstall  1657 10  4 08:11 demo4.log
-rw-r--r-- 1 oracle oinstall   137 10  3 12:20 demo5.ctl
-rw-r--r-- 1 oracle oinstall  1560 10  3 12:21 demo5.log
-rw-r--r-- 1 oracle oinstall   175 10  3 12:23 demo6.ctl
-rw-r--r-- 1 oracle oinstall  1641 10  3 12:23 demo6.log
-rw-r--r-- 1 oracle oinstall   174 10  3 12:25 demo7.ctl
-rw-r--r-- 1 oracle oinstall  1641 10  3 12:25 demo7.log
-rw-r--r-- 1 oracle oinstall   184 10  3 12:28 demo8.ctl
-rw-r--r-- 1 oracle oinstall  1640 10  3 12:29 demo8.log
-rw-r--r-- 1 oracle oinstall     1 10  3 12:47 demo9.bad
-rw-r--r-- 1 oracle oinstall   290 10  3 12:47 demo9.ctl
-rw-r--r-- 1 oracle oinstall  1809 10  3 12:47 demo9.log
-rw-r--r-- 1 oracle oinstall    13 10  4 08:22 demo.txt
-rw-r--r-- 1 oracle oinstall   547 10  3 10:44 log.bbd

[oracle@jy ~]$ sqlldr userid=jy/jy control=demo19.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Fri Oct 4 10:26:54 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 56

現在,執行SQLLDR之後檢查LOB_DEMO表的內容,會發現以下結果:
SQL> select owner, time_stamp, filename, dbms_lob.getlength(data) from jy.lob_demo;

OWNER             TIME_STAMP  FILENAME            DBMS_LOB.GETLENGTH(DATA)
----------------------------- --------------------------------------------
oracle oinstall   2013-10-4 9 demo17.log                              2321
oracle oinstall   2013-10-4 9 demo18.dat                               665
oracle oinstall   2013-10-4 9 demo18.log                              1860
oracle oinstall   2013-10-3 1 demo1.log                               1648
oracle oinstall   2013-10-3 1 bifile.bbd                             18432
oracle oinstall   2013-10-3 1 demo10.bad                                 1
oracle oinstall   2013-10-3 1 demo10.ctl                               342
oracle oinstall   2013-10-3 1 demo10.log                              1948
oracle oinstall   2013-10-3 1 demo11.bad                               144
oracle oinstall   2013-10-3 1 demo11.ctl                               377
oracle oinstall   2013-10-3 1 demo12.bad                                89
oracle oinstall   2013-10-3 1 demo12.ctl                               582
oracle oinstall   2013-10-3 1 demo14.bad                                80
oracle oinstall   2013-10-3 1 demo14.ctl                               441
oracle oinstall   2013-10-4 5 demo15.dat.bak                           256
oracle oinstall   2013-10-4 7 demo16.bad                                 3
oracle oinstall   2013-10-4 9 demo18.ctl                               213
oracle oinstall   2013-10-3 1 demo1.bad                                  1
oracle oinstall   2013-10-3 1 demo1.ctl                                177
oracle oinstall   2013-10-3 1 demo2.bad                                  1
oracle oinstall   2013-10-3 1 demo2.ctl                                214
oracle oinstall   2013-10-4 7 demo3.bad                                  2
oracle oinstall   2013-10-4 7 demo3.ctl                                121
oracle oinstall   2013-10-4 8 demo4.bad                                 18
oracle oinstall   2013-10-3 1 demo5.ctl                                137
oracle oinstall   2013-10-3 1 demo6.ctl                                175
oracle oinstall   2013-10-3 1 demo8.ctl                                184
oracle oinstall   2013-10-3 1 demo9.bad                                  1
oracle oinstall   2013-10-4 8 demo.txt                                  13
oracle oinstall   2013-10-3 1 demo11.log                              1913
oracle oinstall   2013-10-3 1 demo12.log                              2147
oracle oinstall   2013-10-3 1 demo13.ctl                               790
oracle oinstall   2013-10-3 1 demo13.log                              2289
oracle oinstall   2013-10-3 1 demo14.dat                               320
oracle oinstall   2013-10-3 1 demo14.log                              2230
oracle oinstall   2013-10-4 5 demo15_bak.dat                           332
oracle oinstall   2013-10-4 5 demo15.ctl                               442
oracle oinstall   2013-10-4 5 demo15.dat                               332
oracle oinstall   2013-10-4 7 demo16.ctl                               446
oracle oinstall   2013-10-4 5 demo15.log                              2229
oracle oinstall   2013-10-4 7 demo16.dat                               324
oracle oinstall   2013-10-4 7 demo16.log                              2235
oracle oinstall   2013-10-4 9 demo17.ctl                               487
oracle oinstall   2013-10-4 9 demo17.dat                               741
oracle oinstall   2013-10-3 1 demo2.log                               1648
oracle oinstall   2013-10-4 7 demo3.log                               1525
oracle oinstall   2013-10-4 8 demo4.ctl                                141
oracle oinstall   2013-10-4 8 demo4.log                               1657
oracle oinstall   2013-10-3 1 demo5.log                               1560
oracle oinstall   2013-10-3 1 demo6.log                               1641
oracle oinstall   2013-10-3 1 demo7.ctl                                174
oracle oinstall   2013-10-3 1 demo7.log                               1641
oracle oinstall   2013-10-3 1 demo8.log                               1640
oracle oinstall   2013-10-3 1 demo9.ctl                                290
oracle oinstall   2013-10-3 1 demo9.log                               1809
oracle oinstall   2013-10-3 1 log.bbd                                  547

這不光適用於BLOB,也適用於CLOB.以這種方式使用SQLLDR來載入文字檔案的目錄會很容易.

將LOB資料載入到物件列.既然知道了如何將資料載入到我們自己建立的一個簡單表中,可能會發現,有時需要將資料載入到一 個複雜的表中,其中可能有一個包含LOB的複雜物件型別(列).使用影像功能時這種情況最為常見.影像功能使用一個複雜的物件型別ORDSYS.ORDIMAGE來實現,我們需要告訴SQLLDR如何向其中載入資料.

要把一個LOB載入到一個ORDIMAGE型別的列中,首先必須對ORDIMAGE型別的結構有所瞭解.在SQL*Plus中使用要載入的一個目標表以及該表上的DESCRIBE,可以發現表中有一個名為IMAGE的ORDSYS.ORDIMAGE列,最終我們想在這一列中載入 IMAGE.SOURCE.LOCALDATA,只有安裝並配置好interMedia,專案的例子才能正常工作;否則,資料型別ORDSYS.ORDIMAGE將是一 個未知型別:
jy@JINGYONG> create table image_load
  2  (id number,
  3  name varchar2(255),
  4  image ordsys.ordimage
  5  );

表已建立。

SQL> desc jy.image_load
Name  Type            Nullable Default Comments
----- --------------- -------- ------- --------
ID    NUMBER          Y
NAME  VARCHAR2(255)   Y
IMAGE ORDSYS.ORDIMAGE Y

SQL> desc ordsys.ordimage
Element              Type
-------------------- ----------------
SOURCE               ORDSYS.ORDSOURCE
HEIGHT               INTEGER
WIDTH                INTEGER
CONTENTLENGTH        INTEGER
FILEFORMAT           VARCHAR2(4000)
CONTENTFORMAT        VARCHAR2(4000)
COMPRESSIONFORMAT    VARCHAR2(4000)
MIMETYPE             VARCHAR2(4000)
INIT                 FUNCTION
COPY                 PROCEDURE
PROCESS              PROCEDURE
PROCESSCOPY          PROCEDURE
SETPROPERTIES        PROCEDURE
CHECKPROPERTIES      FUNCTION
GETHEIGHT            FUNCTION
GETWIDTH             FUNCTION
GETFILEFORMAT        FUNCTION
GETCONTENTFORMAT     FUNCTION
GETCOMPRESSIONFORMAT FUNCTION
GETMETADATA          FUNCTION
PUTMETADATA          PROCEDURE
SETLOCAL             PROCEDURE
CLEARLOCAL           PROCEDURE
ISLOCAL              FUNCTION
GETUPDATETIME        FUNCTION
SETUPDATETIME        PROCEDURE
GETMIMETYPE          FUNCTION
SETMIMETYPE          PROCEDURE
GETCONTENTLENGTH     FUNCTION
GETCONTENT           FUNCTION
GETBFILE             FUNCTION
DELETECONTENT        PROCEDURE
GETDICOMMETADATA     FUNCTION
SETSOURCE            PROCEDURE
GETSOURCE            FUNCTION
GETSOURCETYPE        FUNCTION
GETSOURCELOCATION    FUNCTION
GETSOURCENAME        FUNCTION
IMPORT               PROCEDURE
IMPORTFROM           PROCEDURE
EXPORT               PROCEDURE
PROCESSSOURCECOMMAND FUNCTION
OPENSOURCE           FUNCTION
CLOSESOURCE          FUNCTION
TRIMSOURCE           FUNCTION
READFROMSOURCE       PROCEDURE
WRITETOSOURCE        PROCEDURE
GETPROPERTIES        PROCEDURE

SQL> desc ordsys.ordsource
Element              Type
-------------------- --------------
LOCALDATA            BLOB
SRCTYPE              VARCHAR2(4000)
SRCLOCATION          VARCHAR2(4000)
SRCNAME              VARCHAR2(4000)
UPDATETIME           DATE
LOCAL                NUMBER
SETLOCAL             PROCEDURE
CLEARLOCAL           PROCEDURE
ISLOCAL              FUNCTION
GETUPDATETIME        FUNCTION
SETUPDATETIME        PROCEDURE
SETSOURCEINFORMATION PROCEDURE
GETSOURCEINFORMATION FUNCTION
GETSOURCETYPE        FUNCTION
GETSOURCELOCATION    FUNCTION
GETSOURCENAME        FUNCTION
GETBFILE             FUNCTION
IMPORT               PROCEDURE
IMPORTFROM           PROCEDURE
EXPORT               PROCEDURE
GETCONTENTLENGTH     FUNCTION
GETSOURCEADDRESS     FUNCTION
GETLOCALCONTENT      FUNCTION
GETCONTENTINTEMPLOB  PROCEDURE
DELETELOCALCONTENT   PROCEDURE
OPEN                 FUNCTION
CLOSE                FUNCTION
TRIM                 FUNCTION
READ                 PROCEDURE
WRITE                PROCEDURE
PROCESSCOMMAND       FUNCTION


載入這種資料的控制檔案可能如下所示:
[oracle@jy ~]$ cat demo20.ctl
LOAD DATA
INFILE *
INTO TABLE image_load
REPLACE
FIELDS TERMINATED BY ','
(ID,
NAME,
file_name FILLER,
IMAGE column object
(
   SOURCE column object
   (
     LOCALDATA LOBFILE(file_name) TERMINATED BY EOF
     NULLIF file_name='NONE'
   )
)
)
BEGINDATA
1,psu3,psu3.jpg

這裡引入了兩個新構造:
COLUMN OBJECT:這會告訴SQLLDR這不是一個列名;而是列名的一部分.它不會對映到輸入檔案中的一個欄位,只是用來構建正 確的物件列引用,從而在載入中使用.在前面的檔案中有兩個列物件標記,其中一個SOURCE嵌入在另一個SOURCE嵌入在 另一個IMAGE中.因此,根據我們的需要,要使用的列名是IMAGE.SOURCE.LOCALDATA.注意,我們沒有載入這兩個物件型別 的任何其他屬性(例如,IMAGE.HEIGHT,IMAGE.CONTENTLENGTH和IMAGE.SOURCE.SRCTYPE).

NULL IF FILE_NAME = 'NONE':這會告訴SQLLDR,如果欄位FILE_NAME包含單詞NONE,則向物件列中載入一個NULL.
[oracle@jy ~]$ sqlldr userid=jy/jy control=demo20.ctl

SQL*Loader: Release 10.2.0.1.0 - Production on Fri Oct 4 10:38:14 2013

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Commit point reached - logical record count 1

SQL> select * from jy.image_load ;

 ID NAME    IMAGE
--- ------- -----
  1 psu3    

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26015009/viewspace-773791/,如需轉載,請註明出處,否則將追究法律責任。

相關文章