Oracle SQL*Loader 使用一個控制文件裝載數據,DB2 LOAD 實用程序也是這樣。但是,這些控制文件的結構很不一樣,許多 Oracle 和 DB2 DBA 希望了解它們的差異。在本文中,要對比這兩個實用程序,討論如何使用 Perl 工具把 OracleSQL*Loader
腳本轉換為LOAD
腳本。因為在大型數據倉庫中空間總是很寶貴的,本文還解釋如何修改 DB2LOAD
的數據文件。
DB2 LOAD 與 Oracle SQL*Loader 的對比
DB2 LOAD 與 DB2 IMPORT — 使用哪種 “路徑”?
![]() |
|
實際上,DB2 有兩種把外部數據源中的數據遷移到 DB2 表的實用程序:LOAD
和 IMPORT
。LOAD
在頁面級存放數據,這會繞過觸發(fā)器和日志記錄機制,并停止約束檢查和索引構建,直到完成數據遷移。另一方面,IMPORT
基本上是執(zhí)行 INSERT,所以在把數據放到表中時,會觸發(fā)觸發(fā)器、執(zhí)行日志記錄并執(zhí)行約束檢查和索引構建。這兩個實用程序的選項之間還有其他許多差異,但是這超出了本文的范圍。
另一方面,Oracle SQL*Loader 實用程序有兩種操作模式,或者說操作路徑:直接路徑和傳統路徑。Oracle DBA 在使用這種實用程序時要指定 “路徑”,這兩種路徑的效果分別與兩個 DB2 實用程序相似。SQL*Loader
“直接路徑” 模式的功能與 DB2 LOAD
相似。SQL*Loader
“傳統路徑” 模式的功能與 DB2 IMPORT
相似。
![]() |
|
作為 DB2 遷移專家,我們發(fā)現大多數 Oracle DBA 在通常使用 SQL*Loader
的傳統模式,他們的經驗和腳本也是針對傳統路徑的。實際上,一些 Oracle DBA 從來沒有使用過 SQL*Loader
的直接路徑模式。但是,當他們開始學習 DB2 時,常常選用 DB2 LOAD
實用程序(可能是因為這個名稱);因為 LOAD
具有 SQL*Loader
直接路徑模式的許多特征,而這些 Oracle DBA 沒有使用過直接路徑,所以他們會遇到許多困難。因此,為了把問題談清楚,盡管大多數 Oracle DBA 通常使用傳統模式,本文會演示如何把所有 SQL*Loader
腳本轉換為 DB2 LOAD
實用程序腳本,無論原來的腳本采用哪個路徑。我們認為這樣做有助于 DB2 產生最佳性能。如果由于某種原因 DBA 希望把這些腳本轉換為使用 IMPORT
而不是 LOAD
,以后也可以這么做(如果情況允許的話)。
用 SQLLDR 二進制代碼調用 Oracle SQL*Loader
實用程序,使用的命令行語法與 DB2 LOAD
相似。命令行可以包含許多關鍵字,比如告訴 SQL*Loader
實用程序把消息發(fā)送到哪里、把丟棄的記錄發(fā)送到哪里等等。
SQLLDR 命令行還指定 “控制文件” 的名稱(常常具有 .CTL 擴展名)。這個控制文件也可以告訴 SQL*Loader
實用程序把消息發(fā)送到哪里、把丟棄的記錄發(fā)送到哪里等等。SQLLDR 命令行中的關鍵字設置優(yōu)先于控制文件中的設置,所以要想了解 SQL*Loader
會話的實際工作方式,必須同時關注 SQLLDR 命令行和控制文件。這樣的設計方式可能是為了提高 SQL*Loader
的靈活性和功能,但是在把腳本遷移到 DB2 時,如果在這兩個位置都使用了一些相同的關鍵字,而且各個腳本的設置不一致,就可能引起混亂。
SQL*Loader 控制文件指定裝載操作的細節(jié),所以在對比 SQL*Loader
和 DB2 LOAD
時,主要對比 SQLLDR 控制文件和 DB2 LOAD
命令行。但是,我們要先討論 SQLLDR 命令行的所有選項,并將其與 DB2 LOAD
命令行進行比較,看看它們的相似之處。然后,討論控制文件及其關鍵字和選項,再與 DB2 LOAD
命令行進行比較。
SQL*Loader
直接路徑特性 | DB2 LOAD | SQL*Loader(直接路徑) |
---|---|---|
直接路徑 | 使用 DB2 LOAD 實用程序 | 使用 SQL*Loader 直接路徑 —— 傳統路徑的許多選項不可用。 |
在裝載后生成統計數據 | 是(如果替換數據),不(如果追加數據) | 不 |
可恢復 | 可以,使用 COPY YES 選項 | 在直接路徑中不可以 |
默認(值) | 可用 | 不可用 |
使用多個輸入文件 | 可以 | 對于一個 SQLLDR,只能使用一個文件 |
異常數據 | 寫到一個異常表和/或 DUMP 文件 | 寫到一個異常表 |
從游標裝載 | 是 | 否 |
從管道裝載 | 是 | 是 |
BLOBS/CLOBS | 是 | 是 |
XML 文檔 | 是 | 是 |
在裝載時允許壓縮 | 是 | 是 |
在線裝載 | 是 —— 可以訪問表 | 在直接路徑中,不是在線裝載 |
在裝載時可以修改數據嗎? | 可以 —— 通過用戶退出 | 可以 —— 傳統路徑(SQL 字符串) 不可以 —— 直接路徑 |
在列中填充常量值 | 不可以 | 可以,使用 CONSTANT 關鍵字 |
在多個數據庫分區(qū)中裝載 | 可以 | 無 |
如何調用? | 它是一個可以從 SQL 腳本調用的 DB2 命令,也可以使用 API 通過應用程序調用 | 它是一個可以從命令行調用的獨立實用程序,可以在應用程序中通過 API 調用 |
如何監(jiān)視裝載狀態(tài)? | 從另一個連接運行 LOAD QUERY 或 LIST UTILITIES 命令 | 查看日志文件 |
并行性 | 經過充分優(yōu)化,可以使用多個 CPU、多個進程和線程 | 可以通過使用多線程實現并行 |
SQLLDR CONTROL=sample.ctl DATA=sample.dat LOG=sample.log BAD=sample.bad DISCARD=sample.dsc USERID=scott/tiger ERRORS=999 LOAD=2000 DISCARDMAX=5 |
SQLLDR
命令行關鍵字與 DB2 LOAD
關鍵字的比較Oracle SQLLDR 關鍵字 | Oracle SQLLDR 關鍵字說明 | DB2 LOAD 關鍵字 | DB2 LOAD 關鍵字說明 |
---|---|---|---|
CONTROL=filename.ctl | 包含詳細的 | 無 | 不從控制文件單獨調用 DB2 |
DIRECT=true | 調用 Oracle | LOAD | DB2 |
DIRECT=false | 如果不使用這個關鍵字或值為 “false”,就調用 Oracle |
| DB2 |
BAD=filename.bad | 存儲被拒絕的記錄的地方。 | MODIFIED BY DUMPFILE=filename | 這個 DB2 |
DATA=filename.dat | 輸入數據源文件。 | FROM sourcename | DB2 |
DISCARD=filename.dsc | 由于各種原因未裝載的異常記錄。 | FOR EXCEPTION tablename | DB2 |
DISCARDMAX=number | 定義在 SQLLDR 終止之前允許的最大丟棄記錄數。 | WARNINGCOUNT=number | 在達到這個警告數時,DB2 |
ERRORS=number | 定義在 SQLLDR 終止之前允許的最大錯誤數。 | NOROWWARNINGS | 修飾符 NOROWWARNINGS 可以關閉行警告,但是仍然保留異常記錄的警告。 |
LOAD=number | 要裝載的記錄數(ALL 是默認設置)。 | ROWCOUNT number | 指定要裝載的記錄數。如果省略這個關鍵字,默認設置是所有記錄。 |
MULTITHREADING=true | 允許在客戶端進行流構建,在服務器端進行流裝載。 | CPU_PARALLELISM number DISK_PARALLELISM number FETCH_PARALLELISM yes | DB2 |
ROWS=number | 每次數據保存存儲的行數。 | SAVECOUNT number | DB2 |
LOG=logfile | LOG 存儲裝載操作的輸出。 | MESSAGES messagefile | DB2 把消息放到這個消息文件中。如果不指定消息文件,它就不產生消息。 |
SILENT=options | SILENT=options 可以關閉操作不同部分的消息輸出。 | NOROWWARNINGS | 修飾符 NOROWWARNINGS 關閉操作不同部分的消息輸出。 |
SKIP=number | 在 n 個記錄之后開始裝載。通常,如果裝載操作提交了部分裝載,但是操作沒有完成,就使用這個關鍵字重新啟動這個操作。 | RESTART | DB2 |
SKIP_INDEX_MAINTENANCE=true | 停止索引維護并把索引標為不可用。 | INDEXING MODE DEFERRED | DB2 |
SKIP_UNUSABLE_INDEX=true | 跳過已經標為不可用的所有索引的索引維護。 | INDEXING MODE REBUILD, INCREMENTAL, AUTOSELECT | DB2 |
READSIZE=number | 在必須提交之前讀取的外部數據文件大小。 | DATA BUFFER number | DB2 |
USERID/PASSWORD | 連接數據庫所用的用戶 id。 | CONNECT TO... number | DB2 在后續(xù)的所有 |
SQL*Loader
控制文件 —— SQL*Loader 實用程序的核心
盡管 Oracle SQL*Loader
命令行允許通過許多關鍵字控制這個實用程序的工作方式,但是我們習慣于通過控制文件而不是命令行來指定大多數關鍵字。我們來研究一個典型的 SQL*Loader
控制文件以及轉換產生的 DB2 LOAD
命令腳本。
DB2 LOAD 命令文件示例(INSERT 固定數據) | Oracle SQL*Loader 控制文件示例(INSERT 固定數據) | ||
---|---|---|---|
|
|
DB2 LOAD 命令文件示例(REPLACE 可變數據) | Oracle SQL*Loader 控制文件示例(REPLACE 可變數據) | ||
---|---|---|---|
|
|
下面對比以上示例:
LOAD
這會在 DB2 中調用 LOAD
實用程序,還可以用 IMPORT
調用這個實用程序。
在 Oracle 中,使用 LOAD DATA
調用 SQL*Loader
實用程序。要想指定直接路徑裝載,必須指定 DIRECT=true。默認設置是 DIRECT=false,因此沒有在這個示例中給出。
FROM [inputfile_name]
這是包含要裝載的數據的文件。DB2 LOAD 還可以從管道、設備或游標裝載數據。
Oracle 也指定輸入文件或管道,還可以通過控制文件用 BEGIN …END 子句指定內聯數據。
OF ASC / DEL
對于 DB2 LOAD,ASC 表示不分界的 ASCII 數據,數據的劃分由位置決定。DEL 表示分界的 ASCII 數據,每行的數據長度可變。分界的數據可以使用多種修飾符,主要的兩種是 COLDEL 和 CHARDEL;COLDEL 決定列和列之間如何分界,默認設置是逗號;CHARDEL 決定字符串數據如何分界,默認設置是雙引號。
Oracle 有 FIX(默認設置,因此在這個示例中沒有給出)或 VAR 關鍵字,但是很少使用。通常使用其他關鍵字和插入列引用,插入列引用決定數據是固定的還是可變的。例如,關鍵字 FIELDS TERMINATED BY 和 FIELDS ENCLOSED BY 的作用與 DB2 LOAD 中的 COLDEL 和 CHARDEL 相似,這表示可變的分界數據。
MODIFIED BY DUMPFILE=[dumpfile_name]
DB2 把被拒絕的記錄放到這個文件中。
Oracle 使用 BADFILE 關鍵字完成同樣的工作。
METHOD P (1,2,3)
DB2 LOAD 有三個方法:
如這個示例所示,SQL*Loader
可以在同一行上組合使用列名和字段位置。
INSERT / REPLACE INTO PROD.TABLE
DB2 LOAD 在這里有四個選項。與 Oracle SQL*Loader
對應的兩個選項是 INSERT 和 REPLACE。另外兩個 DB2 LOAD 選項是 RESTART 和 TERMINATE。當 DB2 LOAD 由于任何原因未完成時,使用這些選項。
SQL*Loader
也有 INSERT,但是這只用于空表;而且 APPEND 對空表的作用與 INSERT 相似,所以 Oracle DBA 很少使用 INSERT。SQL*Loader
REPLACE 的作用與 DB2 LOAD REPLACE 相同。
(COL1, COL2, COL3) Insert Column List
DB2 LOAD 使用這個列表決定要放入數據的列。如果省略這個列列表,那么 DB2 LOAD 會嘗試按照讀取和解析數據的次序裝載數據。
如這個示例所示,SQL*Loader
可以在同一行上組合使用列名和字段位置。對于長度可變的數據,不給出位置,而是由分界符決定字段的劃分。
FOR EXCEPTION [table_name]
DB2 LOAD 把違反惟一索引規(guī)則的記錄(異常)放到以前創(chuàng)建的這個表中。
SQL*Loader
使用 DISCARDFILE 完成同樣的工作,但使用的是一個操作系統文件而不是 DB2 表。
Oracle SQLLDR 關鍵字 | Oracle SQLLDR 關鍵字說明 | DB2 LOAD 關鍵字 | DB2 LOAD 關鍵字說明 |
---|---|---|---|
DIRECT=true | 調用 Oracle | LOAD | DB2 |
DIRECT=false | 如果不使用這個關鍵字或值為 “false”,就調用 Oracle | IMPORT | DB2 |
ERRORS=number | 定義在 SQLLDR 終止之前允許的最大錯誤數。 | NOROWWARNINGS | 修飾符 NOROWWARNINGS 可以關閉行警告,但是仍然保留異常記錄的警告。 |
LOAD=number | 要裝載的記錄數(ALL 是默認設置)。 | ROWCOUNT number | 指定要裝載的記錄數。如果省略這個關鍵字,默認設置是所有記錄。 |
MULTITHREADING=true | 允許在客戶端進行流構建,在服務器端進行流裝載。 | CPU_PARALLELISM number DISK_PARALLELISM number FETCH_PARALLELISM yes | DB2 |
READSIZE=n | 在必須提交之前讀取的外部數據文件大小。 | DATA BUFFER number | DB2 |
ROWS=number | 每次數據保存存儲的行數。 | SAVECOUNT number | DB2 |
SILENT=options | SILENT=options 可以關閉操作不同部分的消息輸出。 | NOROWWARNINGS | 修飾符 NOROWWARNINGS 關閉裝載操作不同部分的消息輸出。 |
SKIP=number | 在 n 個記錄之后開始裝載。通常,如果裝載操作提交了部分裝載,但是操作沒有完成,就使用這個關鍵字重新啟動這個操作。 | RESTART | DB2 |
SKIP_INDEX_MAINTENANCE=true | 停止索引維護并把索引標為不可用。 | INDEXING MODE DEFERRED | DB2 |
SKIP_UNUSABLE_INDEX=true | 跳過已經標為不可用的所有索引的索引維護。 | INDEXING MODE REBUILD, INCREMENTAL, AUTOSELECT | DB2 |
NOLOGGING | 這個選項允許繞過日志記錄機制,但是會使這個表無法通過前滾操作恢復。 | NONRECOVERABLE | 如果使用這個選項,在裝載操作之后表空間并不處于備份未完成狀態(tài),在裝載操作期間不必復制裝載的數據。 |
CONTINUE_LOAD DATA | 重新啟動終止的裝載操作,自動尋找正確的啟始點(只適用于直接路徑模式)。 | RESTART | DB2 |
LOAD DATA | 調用 SQLLDR 二進制代碼,以任何模式(即路徑)裝載數據。 | 1. LOAD | DB2 |
INFILE filename | 輸入數據源文件。 | FROM sourcename | DB2 LOAD 的 sourcename 可以是文件、管道、設備或游標。 |
RECSIZE n | 固定的輸入記錄的大小。 | MODIFIED BY RECLEN=x | 固定的輸入記錄的大小。 |
BADFILE filename | 存儲被拒絕記錄的地方。 | MODIFIED BY DUMPFILE=filename | 這個 DB2 LOAD 修飾符用來決定在哪里存儲被拒絕的記錄。 |
DISCARDFILE filename | 由于各種原因未裝載的異常記錄。 | FOR EXCEPTION tablename | DB2 LOAD 把違反惟一索引規(guī)則的記錄(異常)放到以前創(chuàng)建的一個表中。 |
DISCARD | 由于各種原因未裝載的異常記錄。 | FOR EXCEPTION filename | DB2 LOAD 把違反惟一索引規(guī)則的記錄(異常)放到以前創(chuàng)建的一個表中。 |
DISCARDMAX | 定義在 SQLLDR 終止之前允許的最大丟棄記錄數。 | 1. WARNINGCOUNT=number | 在達到這個警告數時,DB2 LOAD 終止。丟棄僅僅是警告類型之一。 |
1. VAR n | 分別指定數據長度是可變的還是固定的。如果使用 VAR,那么 n 是位于行首用來聲明每行長度的數據的字節(jié)數。 | 1. OF DEL | DB2 可變數據是分界的,固定數據是 ASCII。 |
1. INSERT 或 APPEND | INSERT 和 APPEND 的相似之處是它們都在已經存在的數據中添加數據,但是 INSERT 要求表是空的。 | 1. INSERT | DB2 LOAD INSERT 向表中添加數據,即使表是空的。 |
INTO TABLE tablename | 要存儲數據的目標表。 | INTO TABLE tablename | 要存儲數據的目標表。 |
TERMINATED BY string | 發(fā)現這個字符串時結束數據讀取。 | MODIFIED BY COLDELx | 在所有輸入數據中以這個字符分隔各個列(默認設置是逗號)。 |
ENCLOSED BY string | 可以用這個字符串包圍數據;通常用于字符數據。 | MODIFIED BY CHARDELx | 用這個字符包圍輸入的字符數據(默認設置是雙引號)。 |
LOBFILE (filename) | 在 INSERT 列列表中指定這個關鍵字,用來從外部文件源裝載 LOB。 | 1. LOBS FROM pathnames | 尋找 LOB 文件的路徑。 |
![]() ![]() |
![]()
|
現在看看 DB2 LOAD 命令的語法。
![]() ![]() |
![]()
|
將 SQL*Loader 轉換為 DB2 LOAD 的 Perl 腳本
這里給出的 Perl 腳本用來把 SQL*Loader
控制文件轉換為等效的 DB2 LOAD
腳本。可以以傳統和直接路徑模式調用 SQL*Loader
,但是 SQL*Loader
在直接路徑模式中不使用 SQL 字符串控制數據格式。Oracle DBA 有時候會忽視這些選項并交換使用傳統和直接路徑模式,而沒有認識到產生的副作用。SQL*Loader
傳統路徑基本上相當于 DB2 IMPORT
實用程序,IMPORT
使用引擎在 DB2 中執(zhí)行批量插入。通過使用數據庫引擎,可以利用觸發(fā)器等特性,這在 SQL*Loader
直接路徑模式或 DB2 LOAD
實用程序中是不可行的。這個 Perl 腳本把 SQL*Loader
控制文件的直接和傳統路徑版本都轉換為 DB2 LOAD
腳本。如果希望使用與 SQL*Loader
傳統路徑等效的 DB2 IMPORT
腳本,應該把生成的文件中的 LOAD
關鍵字改為 IMPORT
。
要想把 SQL*Loader
腳本轉換為 DB2 LOAD
腳本 ,需要在目標平臺上安裝 Perl。本文假設您熟悉如何在目標平臺上安裝 Perl 工具。這里給出的示例適用于 Windows 平臺,但是可以在您選擇的任何平臺上使用這個工具。
如果在運行這個工具時沒有指定任何參數,它就會顯示使用方法,見清單 3:
C:\>perl ora2db2.pl USAGE: perl ora2db.pl -c controlfile [options] -o ostype (Unix|Windows - default is Unix. Other value is Windows -m message_directory_name (default is MSG_DIR) -e dump_directory_name (default is DUMP_DIR). This dir should reside on all partitions on DB2 server. -d data_file_name (default is INPUT_FILE) -f defaultif clause set to either (default|null - default is null) -s schema name. Replace with the schema name in control file -g timestamp format. Default is YYYY-MM-DD |
可以指定一些參數作為 SQLLDR 命令的參數,它們優(yōu)先于控制文件中定義的選項。如果使用一個腳本帶參數調用 SQLLDR,這可能會導致遷移問題。這些參數可以與運行工具時給出的開關匹配,讓創(chuàng)建的 DB2 LOAD
腳本使用正確的參數。
下面的示例演示如何轉換具有不同格式選項的直接和傳統路徑控制文件。
C:\>perl ora2db2.pl -c test1.ctl -d data\test1.data -m msg -e dump -o Windows -s ADMIN -f null > load1.db2 C:\>perl ora2db2.pl -c test2.ctl -d data\test2.data -m msg -e dump -o Windows -s ADMIN -f null > load2.db2 |
![]() |
|
SQL*Loader
test1.ctl UNRECOVERABLE LOAD DATA INFILE 'INPUT_FILE' APPEND INTO TABLE JOHN.TABLE1 TRAILING NULLCOLS ( BC_OFF_BCBANK POSITION(2:4) CHAR , BC_OFF_SEGMENT_TYPE POSITION(5:12) CHAR "rtrim(:BC_OFF_SEGMENT_TYPE,' ')" , BC_OFF_NUM POSITION(13:18) CHAR DEFAULTIF BC_OFF_NUM= ' ?????', BC_OFF_SQ_EFF_DATE POSITION(19:26) CHAR DEFAULTIF BC_OFF_SQ_EFF_DATE=" ???????", BC_OFF_SQ_ENT_DATE POSITION(27:40) CHAR DEFAULTIF BC_OFF_SQ_ENT_DATE = ' ?????????????', BC_OFF_DELETE POSITION(41:41) CHAR, BC_OFF_EFF_DATE POSITION(42:53) CHAR DEFAULTIF BC_OFF_EFF_DATE =' ???????????', BC_OFF_INITIALS POSITION(54:56) CHAR "rtrim(:BC_OFF_INITIALS,' ')", BC_OFF_NAME POSITION(57:76) CHAR "rtrim(:BC_OFF_NAME,' ')", BC_OFF_C_L_SECTION POSITION(77:78) CHAR, BC_OFF_PHONE_NR POSITION(79:90) CHAR DEFAULTIF BC_OFF_PHONE_NR=' ???????????', BC_OFF_SC_LND_LMT POSITION(91:98) CHAR DEFAULTIF BC_OFF_SC_LND_LMT = ' ???????', BC_OFF_UNSC_LND_LMT POSITION(99:106) CHAR DEFAULTIF BC_OFF_UNSC_LND_LMT = ' ???????', BC_OFF_NEWCOL POSITION(107:107) CHAR NULLIF (BC_OFF_NEWCOL=BLANKS), PRCS_DTE CONSTANT "PROCESSDATE", PRCS_YR_MTH_NBR CONSTANT "PROCYRMTH" ) |
-- Converting Oracle SQL*Loader Control File test1.ctl to DB2 -- ALTER Statements to take care of CONSTANT parameters ALTER TABLE TABLE2 ALTER COLUMN PRCS_DTE SET WITH DEFAULT 'PROCESSDATE'; ALTER TABLE TABLE2 ALTER COLUMN PRCS_YR_MTH_NBR SET WITH DEFAULT 'PROCYRMTH'; -- DB2 LOAD Script LOAD FROM "data\test1.data" OF ASC MODIFIED BY ANYORDER USEDEFAULTS STRIPTBLANKS TIMESTAMPFORMAT="YYYY-MM-DD" DUMPFILE="dump\admin_table1.dump" METHOD L ( 2 4 ,5 12 ,13 18 ,19 26 ,27 40 ,41 41 ,42 53 ,54 56 ,57 76 ,77 78 ,79 90 ,91 98 ,99 106 ,107 107 ) MESSAGES "msg\admin_table1.msg" INSERT INTO "ADMIN"."TABLE1" ( BC_OFF_BCBANK ,BC_OFF_SEGMENT_TYPE ,BC_OFF_NUM ,BC_OFF_SQ_EFF_DATE ,BC_OFF_SQ_ENT_DATE ,BC_OFF_DELETE ,BC_OFF_EFF_DATE ,BC_OFF_INITIALS ,BC_OFF_NAME ,BC_OFF_C_L_SECTION ,BC_OFF_PHONE_NR ,BC_OFF_SC_LND_LMT ,BC_OFF_UNSC_LND_LMT ,BC_OFF_NEWCOL ) NONRECOVERABLE INDEXING MODE AUTOSELECT ; -- UPDATE Statements for setting proper DEFAULTIF parameters UPDATE "ADMIN"."TABLE1" SET BC_OFF_NUM = NULL WHERE BC_OFF_NUM = ' ?????'; UPDATE "ADMIN"."TABLE1" SET BC_OFF_SQ_EFF_DATE = NULL WHERE BC_OFF_SQ_EFF_DATE = ' ???????'; UPDATE "ADMIN"."TABLE1" SET BC_OFF_SQ_ENT_DATE = NULL WHERE BC_OFF_SQ_ENT_DATE = ' ?????????????'; UPDATE "ADMIN"."TABLE1" SET BC_OFF_EFF_DATE = NULL WHERE BC_OFF_EFF_DATE = ' ???????????'; UPDATE "ADMIN"."TABLE1" SET BC_OFF_PHONE_NR = NULL WHERE BC_OFF_PHONE_NR = ' ???????????'; UPDATE "ADMIN"."TABLE1" SET BC_OFF_SC_LND_LMT = NULL WHERE BC_OFF_SC_LND_LMT = ' ???????'; UPDATE "ADMIN"."TABLE1" SET BC_OFF_UNSC_LND_LMT = NULL WHERE BC_OFF_UNSC_LND_LMT = ' ???????'; -- UPDATE Statements for setting proper NULLIF parameters UPDATE "ADMIN"."TABLE1" SET BC_OFF_NEWCOL = NULL WHERE BC_OFF_NEWCOL = 'BLANKS)'; |
LOAD DATA INFILE 'INPUT_FILE' APPEND INTO TABLE JOHN.TABLE2 FIELDS TERMINATED BY ' ' TRAILING NULLCOLS ( CR_BUR_PTFLO_TYP_DESC char(255) NULLIF CR_BUR_PTFLO_TYP_DESC=BLANKS, DW_PROD_SERV_FEE_PLN_RCD_ID, DW_ULT_PROD_SERV_ID, ACCT_NBR, ACCT_GRP_NBR, APPL_CDE, PRCS_GRP_NBR, FEE_CAT_CDE, FEE_PLN_NBR, FEE_DESC, FEE_TYP_CDE, FEE_EARN_CDE, CMPT_1_NXT_ASSMT_DTE DATE "YYYY-MM-DD", CMPT_2_NXT_ASSMT_DTE DATE "YYYY-MM-DD", CMPT_3_NXT_ASSMT_DTE DATE "YYYY-MM-DD", CUR_PMT_DUE_DTE DATE "YYYY-MM-DD", EARN_GOOD_THRU_1_DTE DATE "YYYY-MM-DD", EARN_GOOD_THRU_2_DTE DATE "YYYY-MM-DD", PR_PMT_DUE_DTE DATE "YYYY-MM-DD", NXT_PMT_DUE_DTE DATE "YYYY-MM-DD", DW_ASP_ID, CLNT_ID, CUR_REC_IND, SOR_EXP_DTE "NVL(:SOR_EXP_DTE,'4444-12-31')", EFF_DTE DATE "YYYY-MM-DD" ) |
-- Converting Oracle SQL*Loader Control File test2.ctl to DB2 -- DB2 LOAD Script LOAD FROM "data\test2.data" OF DEL MODIFIED BY COLDEL0x09 ANYORDER USEDEFAULTS TIMESTAMPFORMAT="YYYY-MM-DD" DUMPFILE="dump\admin_table2.dump" METHOD P ( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 ) MESSAGES "msg\admin_table2.msg" INSERT INTO "ADMIN"."TABLE2" ( CR_BUR_PTFLO_TYP_DESC ,DW_PROD_SERV_FEE_PLN_RCD_ID ,DW_ULT_PROD_SERV_ID ,ACCT_NBR ,ACCT_GRP_NBR ,APPL_CDE ,PRCS_GRP_NBR ,FEE_CAT_CDE ,FEE_PLN_NBR ,FEE_DESC ,FEE_TYP_CDE ,FEE_EARN_CDE ,CMPT_1_NXT_ASSMT_DTE ,CMPT_2_NXT_ASSMT_DTE ,CMPT_3_NXT_ASSMT_DTE ,CUR_PMT_DUE_DTE ,EARN_GOOD_THRU_1_DTE ,EARN_GOOD_THRU_2_DTE ,PR_PMT_DUE_DTE ,NXT_PMT_DUE_DTE ,DW_ASP_ID ,CLNT_ID ,CUR_REC_IND ,SOR_EXP_DTE ,EFF_DTE ) NONRECOVERABLE INDEXING MODE AUTOSELECT ; -- UPDATE Statements for setting proper NULLIF parameters UPDATE "ADMIN"."TABLE2" SET CR_BUR_PTFLO_TYP_DESC = NULL WHERE TRIM(CR_BUR_PTFLO_TYP_DESC) = ''; UPDATE "ADMIN"."TABLE2" SET SOR_EXP_DTE = COALESCE(SOR_EXP_DTE,'4444-12-31-00.00.00'); |
注意,因為 DB2 不允許在 DB2 LOAD
腳本中使用 CONSTANT
關鍵字,所以 CONSTANT
列被轉換為帶 DEFAULT
子句的 ALTER TABLE
語句。DB2 LOAD
會在裝載數據時應用 DEFAULT
值,而 SQL*Loader
直接路徑不應用默認值。
還要注意 Oracle 控制文件 test1.ctl 示例中 UNRECOVERABLE
選項(使用直接路徑)中的 SQL 字符串,但是直接路徑忽略這些 SQL 字符串。在 DB2 中可以忽略轉換產生的等效更新語句。
上面的轉換過程產生了一些 UPDATE
語句,它們根據應用的 SQL 字符串修改數據。如果由于性能問題不愿意在非常大的表上應用這些 UPDATE
語句,那么可以用另一個選項 SOURCEUSEREXIT
修改數據文件,下一節(jié)解釋這個選項。
![]() ![]() |
![]()
|
DB2 和 Oracle 在體系結構方面的主要差異之一是如何處理空字符串。Oracle 把空字符串當作 NULL 對待,而 DB2 不是這樣。如果 SQL*Loader
控制文件中使用位置列,那么在使用 LOAD
實用程序裝載數據時,這個差異可能會導致錯誤。如果這些列是空的,DB2 就認為它們是空的,而 Oracle 認為它們是 NULL。
在下面的示例數據中,在位置 23 和 32 上有 NULL 標志,它們分別針對在位置 24:27 和 28:31 上定義的數據:
FILE1 has 7 elements: ELE1 positions 01 to 20 ELE2 positions 21 to 22 ELE3 positions 23 to 23 ELE4 positions 24 to 27 ELE5 positions 28 to 31 ELE6 positions 32 to 32 ELE7 positions 33 to 40 1...5...10...15...20...25...30...35...40 Test data 1 XXN 123abcdN Test data 2 and 3 QQY wxyzN Test data 4,5 and 6 WWN6789 Y |
下面的 LOAD
腳本使用 NULL INDICATORS
選項,如果 NULL 標志設置為 Y,腳本就會把列當作 NULL:
NULL INDICATORS
選項 TABLE has 5 columns: COL1 VARCHAR 20 NOT NULL WITH DEFAULT COL2 SMALLINT COL3 CHAR 4 COL4 CHAR 2 NOT NULL WITH DEFAULT COL5 CHAR 2 NOT NULL db2 load from file1 of asc modified by striptblanks reclen=40 method L (1 20, 21 22, 24 27, 28 31) null indicators (0,0,23,32) insert into table1 (col1, col5, col2, col3) |
以 Oracle 控制腳本 test1.ctl 為例(使用我們的 Perl 腳本執(zhí)行轉換)。為了裝載 null 值,DB2 LOAD
要求專門指定 NULL INDICATORS
。這要求為數據文件中每個記錄的所有列添加 NULL 標志。對于這樣的情況,可以使用 DB2 LOAD SOURCEUSEREXIT
選項根據用戶退出程序中的邏輯修改數據文件。采用這種方法,就不需要在運行 LOAD
之前處理數據文件。使用 SOURCEUSEREXIT
選項會讓 DB2 LOAD
讀取數據文件并把數據記錄傳輸給可以處理記錄的用戶退出程序,處理之后再傳遞給 DB2 LOAD
。
LOAD FROM data\test1.data OF ASC MODIFIED BY ANYORDER USEDEFAULTS STRIPTBLANKS TIMESTAMPFORMAT="YYYY-MM-DD" DUMPFILE="dump\admin_table1.dump" METHOD L ( 2 4 ,5 12 ,13 18 ,19 26 ,27 40 ,41 41 ,42 53 ,54 56 ,57 76 ,77 78 ,79 90 ,91 98 ,99 106 ,107 107 ) NULL INDICATORS (108,109,110,111,112,113,0,114,115,116,117,118,119,120) MESSAGES "msg\admin_table1.msg" INSERT INTO "ADMIN"."TABLE1" ( BC_OFF_BCBANK ,BC_OFF_SEGMENT_TYPE ,BC_OFF_NUM ,BC_OFF_SQ_EFF_DATE ,BC_OFF_SQ_ENT_DATE ,BC_OFF_DELETE ,BC_OFF_EFF_DATE ,BC_OFF_INITIALS ,BC_OFF_NAME ,BC_OFF_C_L_SECTION ,BC_OFF_PHONE_NR ,BC_OFF_SC_LND_LMT ,BC_OFF_UNSC_LND_LMT ,BC_OFF_NEWCOL ) NONRECOVERABLE INDEXING MODE AUTOSELECT SOURCEUSEREXIT userexit.pl redirect input from buffer 'colninds:(2 4,5 12, 13 18,19 26,27 40,41 41,42 53,54 56,57 76,77 78,79 90,91 98,99 106, 107 107) nullinds:(108,109,110,111,112,113,0, 114,115,116,117,118, 119,120)' output to file userexit.log ; |
![]() |
|
![]() ![]() |
![]()
|
Oracle DBA 熟悉 SQL*Loader
,他們很容易利用這些知識學習 DB2 LOAD
和 IMPORT
實用程序。本文主要關注 LOAD
,但是許多內容也可以應用于 IMPORT
。本文討論并對比了 SQL*Loader
和 DB2 LOAD
的主要關鍵字。還提供了一個容易使用的 Perl 腳本,它可以轉換大多數 SQL*Loader
腳本。這應該能夠幫助您的組織更輕松地遷移到 DB2。
![]() ![]() |
![]()
|
本文的作者感謝 IBM 多倫多實驗室的 David Sciaraffa,他提供了在記錄中添加 NULL 標志的 userexit.pl 程序示例。
![]() ![]() |
![]()
|
描述 | 名字 | 大小 | 下載方法 |
---|---|---|---|
將 SQL*Loader 遷移到 DB2 Load 的 Perl 腳本 | db2load.zip | 10KB | HTTP |
![]() | ||||
![]() | 關于下載方法的信息 | ![]() |
![]() | ||
![]() | ![]() | Burt Vialpando 在 1984 年成為 IT 專業(yè)人員,并從 1998 年開始為 IBM 工作,從事與數據庫遷移相關的項目。他目前擔任 Oracle 到 DB2 遷移方面的技術售前專家,曾經主持差不多 80 場技術證明會,與會的 DBA 超過 1,200 人。他是許多圖書、文章、文件、PoT 和其他資料的作者或合作作者。Burt 擁有許多 DB2、Oracle 和其他 IT 認證,還擁有多項 IBM 專利。 |
![]() | ||
| ![]() | Vikram Khatri 在 IBM 的 Sales and Distribution 部門工作,是 DB2 Migration 小組的一員。Vikram 有 21 年的 IT 從業(yè)經驗,擅長把非 DB2 數據庫遷移到 DB2。Vikram 支持 DB2 技術銷售組織的工作,幫助他們完成復雜的數據庫遷移項目和數據庫性能基準測試。 |