首页
>
挨踢(IT),
数据库 > 多表关联下的测试数据制造方法(二):将数据导出为CSV文件
多表关联下的测试数据制造方法(二):将数据导出为CSV文件
多表关联下的测试数据制造方法系列
- 多表关联下的测试数据制造方法(一):思路详解
上一节中,我们详细介绍了单表、多表关联等情况下,制造测试数据的思路,并用SQL、存储过程等测试了这些思路。这一节,D瓜哥讲继续上一节的思路,使用SQL Loader来提升导入数据的效率。
使用SQL Loader来导入数据时,必须提供有规范格式的数据文件。假设,我们的基础表已经有数据了。目前需要做的事,1、根据基础表生成数据文件;2、使用SQL Loader讲数据文件中的数据导入到数据汇总表。那么,问题就来了:我们如何生存数据文件呢?这一篇文章,我们就重点关注一下,如何根据查询结果生存数据文件的问题。
了解SQL的朋友应该都知道,使用SQL增删改查还行。如果让SQL读写文件,那真是鞭长莫及啊!好在Oracle的存储过程提供了读写文件的功能。所以,只能通过Oracle的存储过程来完成数据文件的生成。下面,给大家讲解一下如果通过存储过程来生成数据文件。
准备工作
提供文件读写功能的utl_file包。使用这包之前,必须先创建DIRECTORY类型的变量,用于指点生成数据文件的路径。所以,需要DBA或者或者是其他具有CREATE DIRECTORY权限的用户创建DIRECTORY,SQL如下:
2 | CREATE OR REPLACE DIRECTORY output_data_dir AS 'd:\oracle' ; |
创建完成后,将其授权给需要使用的用户,这里假如是scott。SQL如下:
2 | GRANT read ,write ON DIRECTORY output_data_dir TO scott; |
然后,就可以使用存储过程生成文件了。根据使用游标类型的不同,还分使用显式游标和使用隐式游标两种方式。下面我们分别给出相关例子。
使用显式游标生成数据文件
先来了解一下游标的概念。在PL/SQL块中执行SELECT、INSERT、DELETE和UPDATE语句时,ORACLE会在内存中为其分配上下文区(Context Area),即缓冲区。游标是指向该区的一个指针,或是命名一个工作区(Work Area),或是一种结构化数据类型。它为应用等量齐观提供了一种对具有多行数据查询结果集中的每一行数据分别进行单独处理的方法,是设计嵌入式SQL语句的应用程序的常用编程方式。
游标有两种类型:显式游标和隐式游标。显式游标即用户显式声明的游标,即指定结果集。我们直接来看看如何使用显式游标读取数据,导出成数据文件的程序。代码如下:
02 | CREATE OR REPLACE PROCEDURE export_to_csv(data_dir IN VARCHAR2) is |
05 | SELECT total_fee_sequence.nextval AS tfee_id, |
07 | d.user_name AS user_name, |
08 | d.mobile_phone AS mobile_phone, |
09 | d.month_total_fee AS month_total_fee, |
10 | d.fee_month AS fee_month, |
11 | d.data_state AS data_state |
12 | FROM ( SELECT u.user_id, |
15 | sum (f.fee) AS month_total_fee, |
16 | trunc(f.fee_date, 'MM' ) AS fee_month, |
17 | trunc(dbms_random.value(0, 5)) AS data_state |
18 | FROM users u, phone_fee f |
19 | WHERE u.user_id = f.user_id |
23 | trunc(f.fee_date, 'MM' )) d; |
27 | csv_output utl_file.file_type; |
29 | out_file_name VARCHAR2(20); |
31 | fee_month_str VARCHAR2(20); |
38 | begin_time := dbms_utility.get_time; |
42 | out_file_name := 'total_fee_data.csv' ; |
44 | csv_output := UTL_FILE.FOPEN(data_dir, out_file_name, 'W' ); |
46 | while count_num < 100000000 loop |
48 | fetch mycur into myrecord; |
51 | fee_month_str := to_char(myrecord.fee_month, 'yyyy-MM-dd HH24:mi' ); |
54 | utl_file.put_line(csv_output, |
55 | myrecord.tfee_id || ',' || myrecord.user_id || ',' |
56 | || myrecord.user_name || ',' |
57 | || myrecord.mobile_phone || ',' |
58 | || myrecord.month_total_fee || ',' |
59 | || fee_month_str || ',' || myrecord.data_state); |
65 | UTL_FILE.FCLOSE(csv_output); |
68 | end_time := dbms_utility.get_time; |
69 | dbms_output.put_line( 'Total time=' || |
70 | (end_time - begin_time) * 10 || 'ms.' ); |
75 | export_to_csv( 'output_data_dir' ); |
使用隐式游标生成数据文件
显式游标主要是用于对查询语句的处理,尤其是在查询结果为多条记录的情况下;而对于非查询语句,如修改、删除操作,则由ORACLE 系统自动地为这些操作设置游标并创建其工作区,这些由系统隐含创建的游标称为隐式游标,隐式游标的名字为SQL,这是由ORACLE 系统定义的。对于隐式游标的操作,如定义、打开、取值及关闭操作,都由ORACLE 系统自动地完成,无需用户进行处理。用户只能通过隐式游标的相关属性,来完成相应的操作。在隐式游标的工作区中,所存放的数据是与用户自定义的显示游标无关的、最新处理的一条SQL 语句所包含的数据。
刚刚演示了显式游标的例子。现在再看看隐式游标的例子。在D瓜哥看来,显式游标和隐式游标只是使用方法上的不同。基本原理是一样的。例子代码如下:
02 | CREATE OR REPLACE PROCEDURE export_to_csv(data_dir IN VARCHAR2) IS |
03 | csv_output utl_file.file_type; |
04 | out_file_name VARCHAR2(20); |
05 | fee_month_str VARCHAR2(20); |
10 | begin_time := dbms_utility.get_time; |
12 | out_file_name := 'total_fee_data.csv' ; |
15 | csv_output := utl_file.fopen(data_dir, out_file_name, 'W' ); |
18 | FOR cur IN ( select total_fee_sequence.nextval AS tfee_id, |
20 | d.user_name AS user_name, |
21 | d.mobile_phone AS mobile_phone, |
22 | d.month_total_fee AS month_total_fee, |
23 | d.fee_month AS fee_month, |
24 | d.data_state AS data_state |
25 | from ( SELECT u.user_id, |
28 | sum (f.fee) AS month_total_fee, |
29 | trunc(f.fee_date, 'MM' ) AS fee_month, |
30 | trunc(dbms_random.value(0, 5)) AS data_state |
31 | FROM users u, phone_fee f |
32 | WHERE u.user_id = f.user_id |
36 | trunc(f.fee_date, 'MM' )) d |
41 | fee_month_str := to_char(cur.fee_month, 'yyyy-MM-dd HH24:mi' ); |
44 | utl_file.put_line(csv_output, |
45 | cur.tfee_id || ',' || cur.user_id || ',' |
46 | || cur.user_name || ',' || cur.mobile_phone || ',' |
47 | || cur.month_total_fee || ',' || fee_month_str |
48 | || ',' || cur.data_state); |
51 | utl_file.fclose(csv_output); |
53 | end_time := dbms_utility.get_time; |
55 | dbms_output.put_line( 'Total time=' || |
56 | (end_time - begin_time) * 10 || 'ms.' ); |
61 | export_to_csv( 'output_data_dir' ); |
注意:由于D瓜哥没有CREATE DIRECTORY的权限。所以,这里的例子,没有进行测试。如果有朋友测试后发现问题,请及时通知D瓜哥,D瓜哥马上改正。谢谢!
一般数据量比较大的情况下,还要考虑分批导出到不同文件中。这个留给大家慢慢摸索吧!下一节,讲给大家介绍使用SQL Loader将数据文件导入到数据库中。敬请关注!
参考资料
- 使用存储过程将Oracle数据批量导出为多个csv文件
- Oracle的UTL_FILE.FOPEN的用法
- 利用存储过程将表中数据导出到.txt文件
- Oracle存储过程读写文件
- Oracle存储过程读写文件
- oracle 隐式游标,显示游标
- ORACLE PL/SQL编程之四:把游标说透
- ORACLE游标概念讲解