批量生成sqlldr文件,高速卸载数据

SQL*Loader 是用于将外部数据进行批量高速加载的数据库的最高效工具,可用于将多种平面格式文件加载到Oracle数据库。SQL*Loader支持传统路径模式以及直接路径这两种加载模式。关于SQL*Loader的具体用法可以参考Oracle Utilities 手册或者SQL*Loader使用方法。那么如何以SQL*Loader能识别的方式高效的卸载数据呢? Tom大师为我们提供了一个近乎完美的解决方案,是基于exp/imp,Datapump方式迁移数据的有力补充。本文基于此给出描述,并通过批量的方式来卸载数据。
有关本文涉及到的参考链接:
    SQL*Loader使用方法 
    数据泵 EXPDP 导出工具的使用
    数据泵IMPDP 导入工具的使用
    PL/SQL-->UTL_FILE包的使用介绍
 
1、单表卸载数据
1. --首先查看你的数据库是否存在相应的dump目录,如果没有,则应先使用create or replace directory dir_name as '/yourpath'创建  
2. scott@SYBO2SZ> @dba_directories  
3.  
4. Owner      Directory Name                 Directory Path  
5. ---------- ------------------------------ -------------------------------------------------  
6. SYS        DB_DUMP_DIR                    /u02/database/SYBO2SZ/BNR/dump  
7.  
8. --下面是用匿名的pl/sql块来卸载单表数据  
9. DECLARE  
10.   l_rows   NUMBER;  
11. BEGIN  
12.   l_rows :=  
13.      unloader.run (p_query        => 'select * from scott.emp order by empno',    --->定义你的查询  
14.                    p_tname        => 'emp',                                       --->定义放入控制文件的表名  
15.                    p_mode         => 'replace',                                   --->定义装载到目标表时使用的方式     
16.                    p_dir          => 'DB_DUMP_DIR',                               --->定义卸载数据存放目录  
17.                    p_filename     => 'emp',                                       --->定义生成的文件名  
18.                    p_separator    => ',',                                         --->字段分隔符  
19.                    p_enclosure    => '"',                                         --->封装每个字段的符合  
20.                    p_terminator   => '~');                                        --->行终止符  
21.  
22.   DBMS_OUTPUT.put_line (TO_CHAR (l_rows) || ' rows extracted to ascii file');  
23. END;  
24. /  
25.  
26. 14 rows extracted to ascii file  
27.  
28. PL/SQL procedure successfully completed.  
29.  
30. --查看刚刚卸载数据生成的文件  
31. scott@SYBO2SZ> ho ls -hltr /u02/database/SYBO2SZ/BNR/dump  
32. total 8.0K  
33. -rw-r--r-- 1 oracle oinstall  913 2014-01-14 15:04 emp.dat  
34. -rw-r--r-- 1 oracle oinstall  261 2014-01-14 15:04 emp.ctl  
35.  
36. --查看卸载文件的内容   
37. scott@SYBO2SZ> ho more /u02/database/SYBO2SZ/BNR/dump/emp.dat  
38. "7369","SMITH","CLERK","7902","17121980000000","800","","20"~  
39. "7499","ALLEN","SALESMAN","7698","20021981000000","1600","300","30"~  
40. "7521","WARD","SALESMAN","7698","22021981000000","1250","500","30"~  
41. "7566","JONES","MANAGER","7839","02041981000000","2975","","20"~  
42. "7654","MARTIN","SALESMAN","7698","28091981000000","1250","1400","30"~  
43. "7698","BLAKE","MANAGER","7839","01051981000000","2850","","30"~  
44. "7782","CLARK","MANAGER","7839","09061981000000","2650","","10"~  
45. "7788","SCOTT","ANALYST","7566","19041987000000","3000","","20"~  
46. "7839","KING","PRESIDENT","","17111981000000","5200","","10"~  
47. "7844","TURNER","SALESMAN","7698","08091981000000","1500","0","30"~  
48. "7876","ADAMS","CLERK","7788","23051987000000","1100","","20"~  
49. "7900","JAMES","CLERK","7698","03121981000000","950","","30"~  
50. "7902","FORD","ANALYST","7566","03121981000000","3000","","20"~  
51. "7934","MILLER","CLERK","7782","23011982000000","1500","","10"~  
52.  
53. --下面是生成的控制文件,有了数据文件和控制文件可以直接进行导入目标表  
54. scott@SYBO2SZ> ho more /u02/database/SYBO2SZ/BNR/dump/emp.ctl  
55. load data  
56. infile 'emp.dat' "str x'7E0A'"  
57. into table emp  
58. replace  
59. fields terminated by X'2c' enclosed by X'22'   
60. (  
61. EMPNO char(44 ),  
62. ENAME char(20 ),  
63. JOB char(18 ),  
64. MGR char(44 ),  
65. HIREDATE date 'ddmmyyyyhh24miss' ,  
66. SAL char(44 ),  
67. COMM char(44 ),  
68. DEPTNO char(44 )  
69. )  
70.  
71. --下面我们先truncate表emp,然后尝试使用sqlldr来装载数据  
72. scott@SYBO2SZ> truncate table emp;  
73.  
74. Table truncated.  
75.  
76. --装载数据到emp  
77. robin@SZDB:/u02/database/SYBO2SZ/BNR/dump> sqlldr scott/tiger control=emp.ctl data=emp.dat direct=true  
78.  
79. SQL*Loader: Release 10.2.0.3.0 - Production on Tue Jan 14 15:45:39 2014  
80.  
81. Copyright (c) 1982, 2005, Oracle.  All rights reserved.  
82.  
83. Load completed - logical record count 14.  
2、批量卸载数据
1. --使用下面的匿名pl/sql块可以实现批量卸载数据,此处不演示  
2. DECLARE  
3.   l_rows   NUMBER;  
4.   v_sql    VARCHAR2 (200);  
5.  
6.   CURSOR cur_tab  
7.   IS  
8.      SELECT table_name FROM user_tables;-->这里定义需要卸载的表,可以单独指定一个表用于存放需要卸载的对象,此处直接查询数据字典  
9. BEGIN  
10.   FOR tab_name IN cur_tab  
11.   LOOP  
12.      v_sql := 'select * from ' || tab_name.table_name;  
13.      l_rows :=  
14.         unloader.run (p_query        => v_sql,  
15.                       p_tname        => tab_name.table_name,  
16.                       p_mode         => 'replace',  
17.                       p_dir          => 'DB_DUMP_DIR',  
18.                       p_filename     => tab_name.table_name,  
19.                       p_separator    => ',',  
20.                       p_enclosure    => '"',  
21.                       p_terminator   => '~');  
22. -- Author : Leshami  
23. -- Blog   : http://blog.csdn.net/leshami  
24.  
25.      DBMS_OUTPUT.put_line (TO_CHAR (l_rows) || ' rows extracted to ascii file');  
26.   END LOOP;  
27. END;  
28. /  
3、卸载数据原始脚本
1. robin@SZDB:~/dba_scripts/custom/tom> more unloader_pkg.sql   
2. CREATE OR REPLACE PACKAGE unloader  
3.   AUTHID CURRENT_USER  
4. AS  
5.   /* Function run -- unloads data from any query into a file  
6.   and creates a control file to reload that  
7.   data into another table  
8.   --注释信息给出了比较详细的描述  
9.   p_query = SQL query to "unload". May be virtually any query.  
10.   p_tname = Table to load into. Will be put into control file.  
11.    p_mode = REPLACE|APPEND|TRUNCATE -- how to reload the data  
12.    p_dir = directory we will write the ctl and dat file to.  
13.    p_filename = name of file to write to. I will add .ctl and .dat  
14.    to this name  
15.    p_separator = field delimiter. I default this to a comma.  
16.    p_enclosure = what each field will be wrapped in  
17.    p_terminator = end of line character. We use this so we can unload  
18.    and reload data with newlines in it. I default to  
19.    "|\n" (a pipe and a newline together) and "|\r\n" on NT.  
20.    You need only to override this if you believe your  
21.    data will have that sequence in it. I ALWAYS add the  
22.    OS "end of line" marker to this sequence, you should not  
23.    */  
24.   FUNCTION run (p_query        IN VARCHAR2,  
25.                 p_tname        IN VARCHAR2,  
26.                 p_mode         IN VARCHAR2 DEFAULT 'REPLACE',  
27.                 p_dir          IN VARCHAR2,  
28.                 p_filename     IN VARCHAR2,  
29.                 p_separator    IN VARCHAR2 DEFAULT ',',  
30.                 p_enclosure    IN VARCHAR2 DEFAULT '"',  
31.                 p_terminator   IN VARCHAR2 DEFAULT '|')  
32.      RETURN NUMBER;  
33. END;  
34. /  
35.  
36. CREATE OR REPLACE PACKAGE BODY unloader  
37. AS  
38.   g_thecursor   INTEGER DEFAULT DBMS_SQL.open_cursor;  
39.   g_desctbl     DBMS_SQL.desc_tab;  
40.   g_nl          VARCHAR2 (2) DEFAULT CHR (10);  
41.  
42.   FUNCTION to_hex (p_str IN VARCHAR2)  
43.      RETURN VARCHAR2  
44.   IS  
45.   BEGIN  
46.      RETURN TO_CHAR (ASCII (p_str), 'fm0x');  
47.   END;  
48.  
49.   FUNCTION is_windows  
50.      RETURN BOOLEAN  
51.   IS  
52.      l_cfiles   VARCHAR2 (4000);  
53.      l_dummy    NUMBER;  
54.   BEGIN  
55.      IF (DBMS_UTILITY.get_parameter_value ('control_files', l_dummy, l_cfiles) > 0)  
56.      THEN  
57.         RETURN INSTR (l_cfiles, '\') > 0;  
58.      ELSE  
59.         RETURN FALSE;  
60.      END IF;  
61.   END;  
62.  
63.   PROCEDURE dump_ctl (p_dir          IN VARCHAR2,  
64.                       p_filename     IN VARCHAR2,  
65.                       p_tname        IN VARCHAR2,  
66.                       p_mode         IN VARCHAR2,  
67.                       p_separator    IN VARCHAR2,  
68.                       p_enclosure    IN VARCHAR2,  
69.                       p_terminator   IN VARCHAR2)  
70.   IS  
71.      l_output   UTL_FILE.file_type;  
72.      l_sep      VARCHAR2 (5);  
73.      l_str      VARCHAR2 (5) := CHR (10);  
74.   BEGIN  
75.      IF (is_windows)  
76.      THEN  
77.         l_str := CHR (13) || CHR (10);  
78.      END IF;  
79.  
80.      l_output := UTL_FILE.fopen (p_dir, p_filename || '.ctl', 'w');  
81.  
82.      UTL_FILE.put_line (l_output, 'load data');  
83.      UTL_FILE.put_line (l_output, 'infile ''' || p_filename || '.dat'' "str x''' || UTL_RAW.cast_to_raw (p_terminator || l_str) || '''"');  
84.      UTL_FILE.put_line (l_output, 'into table ' || p_tname);  
85.      UTL_FILE.put_line (l_output, p_mode);  
86.      UTL_FILE.put_line (l_output, 'fields terminated by X''' || to_hex (p_separator) || ''' enclosed by X''' || to_hex (p_enclosure) || ''' ');  
87.      UTL_FILE.put_line (l_output, '(');  
88.  
89.      FOR i IN 1 .. g_desctbl.COUNT  
90.      LOOP  
91.         IF (g_desctbl (i).col_type = 12)  
92.         THEN  
93.            UTL_FILE.put (l_output, l_sep || g_desctbl (i).col_name || ' date ''ddmmyyyyhh24miss'' ');  
94.         ELSE  
95.            UTL_FILE.put (l_output, l_sep || g_desctbl (i).col_name || ' char(' || TO_CHAR (g_desctbl (i).col_max_len * 2) || ' )');  
96.         END IF;  
97.  
98.         l_sep := ',' || g_nl;  
99.      END LOOP;  
100.  
101.      UTL_FILE.put_line (l_output, g_nl || ')');  
102.      UTL_FILE.fclose (l_output);  
103.   END;  
104.  
105.   FUNCTION quote (p_str IN VARCHAR2, p_enclosure IN VARCHAR2)  
106.      RETURN VARCHAR2  
107.   IS  
108.   BEGIN  
109.      RETURN p_enclosure || REPLACE (p_str, p_enclosure, p_enclosure || p_enclosure) || p_enclosure;  
110.   END;  
111.  
112.   FUNCTION run (p_query        IN VARCHAR2,  
113.                 p_tname        IN VARCHAR2,  
114.                 p_mode         IN VARCHAR2 DEFAULT 'REPLACE',  
115.                 p_dir          IN VARCHAR2,  
116.                 p_filename     IN VARCHAR2,  
117.                 p_separator    IN VARCHAR2 DEFAULT ',',  
118.                 p_enclosure    IN VARCHAR2 DEFAULT '"',  
119.                 p_terminator   IN VARCHAR2 DEFAULT '|')  
120.      RETURN NUMBER  
121.   IS  
122.      l_output        UTL_FILE.file_type;  
123.      l_columnvalue   VARCHAR2 (4000);  
124.      l_colcnt        NUMBER DEFAULT 0;  
125.      l_separator     VARCHAR2 (10) DEFAULT '';  
126.      l_cnt           NUMBER DEFAULT 0;  
127.      l_line          LONG;  
128.      l_datefmt       VARCHAR2 (255);  
129.      l_desctbl       DBMS_SQL.desc_tab;  
130.   BEGIN  
131.      SELECT VALUE  
132.        INTO l_datefmt  
133.        FROM nls_session_parameters  
134.       WHERE parameter = 'NLS_DATE_FORMAT';  
135.  
136.      /*  
137.      Set the date format to a big numeric string. Avoids  
138.      all NLS issues and saves both the time and date.  
139.      */  
140.      EXECUTE IMMEDIATE 'alter session set nls_date_format=''ddmmyyyyhh24miss'' ';  
141.  
142.      /*  
143.      Set up an exception block so that in the event of any  
144.      error, we can at least reset the date format.  
145.      */  
146.      BEGIN  
147.         /*  
148.         Parse and describe the query. We reset the  
149.         descTbl to an empty table so .count on it  
150.         will be reliable.  
151.         */  
152.         DBMS_SQL.parse (g_thecursor, p_query, DBMS_SQL.native);  
153.         g_desctbl := l_desctbl;  
154.         DBMS_SQL.describe_columns (g_thecursor, l_colcnt, g_desctbl);  
155.  
156.         /*  
157.         Create a control file to reload this data  
158.         into the desired table.  
159.         */  
160.         dump_ctl (p_dir,  
161.                   p_filename,  
162.                   p_tname,  
163.                   p_mode,  
164.                   p_separator,  
165.                   p_enclosure,  
166.                   p_terminator);  
167.  
168.         /*  
169.         Bind every single column to a varchar2(4000). We don't care  
170.         if we are fetching a number or a date or whatever.  
171.         Everything can be a string.  
172.         */  
173.         FOR i IN 1 .. l_colcnt  
174.         LOOP  
175.            DBMS_SQL.define_column (g_thecursor,  
176.                                    i,  
177.                                    l_columnvalue,  
178.                                    4000);  
179.         END LOOP;  
180.  
181.         /*  
182.         Run the query - ignore the output of execute. It is only  
183.         valid when the DML is an insert/update or delete.  
184.         */  
185.         l_cnt := DBMS_SQL.execute (g_thecursor);  
186.  
187.         /*  
188.         Open the file to write output to and then write the  
189.         delimited data to it.  
190.         */  
191.         l_output :=  
192.            UTL_FILE.fopen (p_dir,  
193.                            p_filename || '.dat',  
194.                            'w',  
195.                            32760);  
196.  
197.         LOOP  
198.            EXIT WHEN (DBMS_SQL.fetch_rows (g_thecursor) <= 0);  
199.            l_separator := '';  
200.            l_line := NULL;  
201.  
202.            FOR i IN 1 .. l_colcnt  
203.            LOOP  
204.               DBMS_SQL.COLUMN_VALUE (g_thecursor, i, l_columnvalue);  
205.               l_line := l_line || l_separator || quote (l_columnvalue, p_enclosure);  
206.               l_separator := p_separator;  
207.            END LOOP;  
208.  
209.            l_line := l_line || p_terminator;  
210.            UTL_FILE.put_line (l_output, l_line);  
211.            l_cnt := l_cnt + 1;  
212.         END LOOP;  
213.  
214.         UTL_FILE.fclose (l_output);  
215.  
216.         /*  
217.         Now reset the date format and return the number of rows  
218.         written to the output file.  
219.         */  
220.         EXECUTE IMMEDIATE 'alter session set nls_date_format=''' || l_datefmt || '''';  
221.  
222.         RETURN l_cnt;  
223.      EXCEPTION  
224.         /*  
225.         In the event of ANY error, reset the data format and  
226.         re-raise the error.  
227.         */  
228.         WHEN OTHERS  
229.         THEN  
230.            EXECUTE IMMEDIATE 'alter session set nls_date_format=''' || l_datefmt || '''';  
231.  
232.            RAISE;  
233.      END;  
234.   END run;  
235. END unloader;  
236. /  


4、小结
a、本文描述了单表以及多表如何高速卸载数据,并且批量生成sqlldr的控制文件及数据文件
b、包调用者应该对unloader其具有execute权限以及表上的select权限
c、包主要是通过utl_file来写出到控制文件和数据文件,有关utl_file用法可参考:PL/SQL-->UTL_FILE包的使用介绍 
d、Tom大师的这个包支持lob数据类型,但其字节不能大于4000,以及不支持long raw


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31448824/viewspace-2139356/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/31448824/viewspace-2139356/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值