用Oracle的DBMS_OUTPUT包产生CSV文件

本文介绍了一种使用Oracle数据库的DBMS_OUTPUT包生成CSV文件的方法。通过创建特定的PL/SQL包,可以方便地从数据库表中导出数据到CSV格式,并提供了插入和删除记录的过程。示例展示了如何设置并使用该包来生成包含大量记录的CSV文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

试过很多产生CSV文件的方法后,发现用Oracle的DBMS_OUTPUT就可以实现,例子代码如下:
1 创建一个数据库表
Drop TABLE VEHICLE;
Create TABLE VEHICLE (
MAKE VARCHAR2(256) NOT NULL,
MODEL VARCHAR2(256),
REGISTRATION_NO NUMBER(15) NOT NULL primary key,
AGE NUMBER(2,1) NOT NULL,
CATEGORY VARCHAR(1) NOT NULL,
MILAGE NUMBER(15,2) NOT NULL,
LAST_SERVICE_DATE DATE NOT NULL
);
2.创建PL/SQL包
-- Package Header Definition
CREATE OR REPLACE PACKAGE ISS_CSV IS
PROCEDURE WCSV(
inRegStart IN NUMBER,
inRegStop IN NUMBER,
inFSep IN VARCHAR2 :=',',
inRSep IN VARCHAR2 :='/n'
);
PROCEDURE AddRec
(startNum IN NUMBER,
 endNum IN NUMBER
);
PROCEDURE DelRec
(startNum IN NUMBER,
 endNum IN NUMBER
);
--PROCEDURE CreateSampTab(tabName IN VARCHAR2);
END;
/
-- Package Body Definition
CREATE OR REPLACE PACKAGE BODY ISS_CSV
IS PROCEDURE WCSV(
inRegStart IN NUMBER,
inRegStop IN NUMBER,
inFSep IN VARCHAR2,
inRSep IN VARCHAR2
) IS
cursor p_cursor is SELECT MAKE||inFSep||MODEL||inFSep||REGISTRATION_NO||inFSep||AGE||inFSep||CATEGORY||
inFSep||MILAGE||inFSep||LAST_SERVICE_DATE||inRSep strRet FROM vehicle WHERE registration_no>=inRegStart
and registration_no<=inRegStop;
c1rec p_cursor%rowtype;
p_errorcode NUMBER :=0;
start_time TIMESTAMP;
right_now TIMESTAMP;
F1 UTL_FILE.FILE_TYPE;
BEGIN
F1 := UTL_FILE.FOPEN('c:/temp','THOMAS.CSV','W',32767);
start_time := SYSTIMESTAMP;
-- OPEN p_cursor;
for c1rec in p_cursor loop
   UTL_FILE.PUT_LINE(F1,c1rec.strRet);  
end loop;
UTL_FILE.FCLOSE(F1);
-- CLOSE p_cursor;
right_now := SYSTIMESTAMP;
dbms_output.put_line(to_char(right_now - start_time));
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN;
WHEN UTL_FILE.INVALID_PATH THEN
DBMS_OUTPUT.PUT_LINE('INVALID PATH');
WHEN UTL_FILE.INVALID_MODE THEN
DBMS_OUTPUT.PUT_LINE('INVALID MODE');
WHEN UTL_FILE.INVALID_FILEHANDLE THEN
DBMS_OUTPUT.PUT_LINE('INVALID FILEHANDLE');
WHEN UTL_FILE.INVALID_OPERATION THEN
DBMS_OUTPUT.PUT_LINE('INVALID OPERATION');
WHEN UTL_FILE.READ_ERROR THEN
DBMS_OUTPUT.PUT_LINE('READ ERROR');
WHEN UTL_FILE.WRITE_ERROR THEN
DBMS_OUTPUT.PUT_LINE('WRITE ERROR');
WHEN UTL_FILE.INTERNAL_ERROR THEN
DBMS_OUTPUT.PUT_LINE('INTERNAL ERROR');
WHEN OTHERS THEN
   DBMS_OUTPUT.PUT_LINE(SQLERRM);
   p_errorcode:= SQLCODE;
   dbms_output.put_line('Error, Rollback'||to_char(p_errorcode));
END;
-- Insert Procedure --
PROCEDURE AddRec
(startNum IN NUMBER
,endNum IN NUMBER
) IS
i number:=startNum;
j number:=endNum;
BEGIN
dbms_output.put_line(to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') );
While i<=j Loop
  INSERT INTO VEHICLE (REGISTRATION_NO,MAKE,MODEL,AGE,CATEGORY,MILAGE,LAST_SERVICE_DATE)
  VALUES(i,'Oracle 10g R2 -Key'||i,'Thomas Kyte Oracle',3,'A',1000,SYSDATE);
  i:=i+1;
End Loop;
commit;
dbms_output.put_line(to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') );
END;
-- Delete Procedure --
PROCEDURE DelRec
( startNum IN NUMBER
 , endNum IN NUMBER
) IS
i number:=startNum;
j number:=endNum;
BEGIN
dbms_output.put_line(to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') );
Delete From VEHICLE Where REGISTRATION_NO>=i and REGISTRATION_NO<=j;
dbms_output.put_line(to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') );
Commit;
END;
--Create Sample Table --
--PROCEDURE CreateSampTab(tabName IN VARCHAR2
--) IS
--BEGIN
--Drop TABLE VEHICLE;
--Create TABLE VEHICLE (
--MAKE VARCHAR2(256) NOT NULL,
--MODEL VARCHAR2(256),
--REGISTRATION_NO NUMBER(15) NOT NULL primary key,
--AGE NUMBER(2,1) NOT NULL,
--CATEGORY VARCHAR(1) NOT NULL,
--MILAGE NUMBER(15,2) NOT NULL,
--LAST_SERVICE_DATE DATE NOT NULL
--);
--EXCEPTION
--WHEN OTHERS THEN
--    dbms_output.put_line('Error When creating Sample Table');
--END;
END;
/
 
 
3. 添加测试数据
  SQL> EXEC ISS_CSV.AddRec(1,1000000);
 
4. 生产CSV文件
  设置参数UTL_FILE_DIR,否则,不能生产CSV文件。
    SQL> ALTER SYSTEM SET UTL_FILE_DIR = 'c:/temp' scope =spfile;
  SQL> SHUTDOWN IMMEDIATE;
  SQL> STARTUP;
  SQL> EXEC ISS_CSV.WCSV(1,1000000);
 
读者可以根据需要做一定修改。
CREATE OR REPLACE PROCEDURE dump_table_to_csv (p_tname IN VARCHAR2, p_dir IN VARCHAR2, p_filename IN VARCHAR2) IS l_output UTL_FILE.file_type; l_theCursor INTEGER DEFAULT DBMS_SQL.open_cursor; l_columnValue VARCHAR2 (4000); l_status INTEGER; l_query VARCHAR2 (1000) DEFAULT 'select * from ' || p_tname; l_colCnt NUMBER := 0; l_separator VARCHAR2 (1); l_descTbl DBMS_SQL.desc_tab; BEGIN l_output := UTL_FILE.fopen (p_dir, p_filename, 'w'); EXECUTE IMMEDIATE 'alter session set nls_date_format=''yyyy-mm-dd hh24:mi:ss'' '; DBMS_SQL.parse (l_theCursor, l_query, DBMS_SQL.native); DBMS_SQL.describe_columns (l_theCursor, l_colCnt, l_descTbl); FOR i IN 1 .. l_colCnt LOOP DBMS_SQL.define_column (l_theCursor, i, l_columnValue, 4000); END LOOP; l_status := DBMS_SQL.execute (l_theCursor); WHILE (DBMS_SQL.fetch_rows (l_theCursor) > 0) LOOP l_separator := ''; FOR i IN 1 .. l_colCnt LOOP DBMS_SQL.COLUMN_VALUE (l_theCursor, i, l_columnValue); UTL_FILE.put (l_output, l_separator || l_columnValue); l_separator := ','; END LOOP; UTL_FILE.new_line (l_output); END LOOP; DBMS_SQL.close_cursor (l_theCursor); UTL_FILE.fclose (l_output); EXECUTE IMMEDIATE 'alter session set nls_date_format=''dd-MON-yy'' '; EXCEPTION WHEN OTHERS THEN EXECUTE IMMEDIATE 'alter session set nls_date_format=''dd-MON-yy'' '; RAISE; END; 这个是oracle的存储过程,我想要把它给转成postgreSql的。其中我postgreSql的数据库里所有的表名和字段都是小写的,但是我转成postgreSql的这个存储过程的名字我还是希望保留着大写的。还有就是你还要给出我这两种数据库的存储过程的运行方法以及查询结果方法,像 “ postgreSQL: CALL "SP_CREATE_RP_GRPSVRWORK_CNT"('2024-03-04'::timestamp, '2024-03-05'::timestamp); -- 或者指定具体日期范围 SELECT * FROM rp_grpsvrworkcnt WHERE offhktm BETWEEN '2024-03-04' AND '2024-03-05' ORDER BY offhktm DESC; oracle: BEGIN SP_CREATE_RP_GRPSVRWORK_CNT(TO_DATE('2024-03-04', 'YYYY-MM-DD'), TO_DATE('2024-03-05', 'YYYY-MM-DD')); END; SELECT * FROM RP_GRPSVRWORKCNT WHERE OFFHKTM BETWEEN TO_DATE('2024-03-04', 'YYYY-MM-DD') AND TO_DATE('2024-03-05', 'YYYY-MM-DD') ORDER BY OFFHKTM DESC; ”这样
03-12
CREATE OR REPLACE DIRECTORY STOCK_DIR AS 'C:\Users\谢东杰\Desktop\数据库'; GRANT READ, WRITE ON DIRECTORY STOCK_DIR TO scott; CREATE TABLE stock_data ( 2 trade_date DATE, -- 交易日期 3 open_price NUMBER(10,2), -- 开盘价 4 close_price NUMBER(10,2), -- 收盘价 5 high_price NUMBER(10,2), -- 最高价 6 low_price NUMBER(10,2), -- 最低价 7 volume NUMBER(12) -- 成交量 8 ); DECLARE file_handle UTL_FILE.FILE_TYPE; v_line VARCHAR2(4000); row_count NUMBER := 0; v_date_raw VARCHAR2(20); v_open_raw VARCHAR2(20); v_high_raw VARCHAR2(20); v_low_raw VARCHAR2(20); v_close_raw VARCHAR2(20); v_volume_raw VARCHAR2(20); -- 解析后字段变量 v_date DATE; v_open NUMBER(10,2); v_high NUMBER(10,2); v_low NUMBER(10,2); v_close NUMBER(10,2); v_volume NUMBER(12); BEGIN -- 正确调用 FOPEN(参数顺序:目录对象名, 文件名, 打开模式, 最大行大小) file_handle := UTL_FILE.FOPEN('STOCK_DIR', '000001.SS.csv', 'R', 32767); -- 跳过标题行(如果存在) BEGIN UTL_FILE.GET_LINE(file_handle, v_line); EXCEPTION WHEN NO_DATA_FOUND THEN NULL; END; -- 主循环:逐行读取并解析 LOOP BEGIN UTL_FILE.GET_LINE(file_handle, v_line); -- 使用正则表达式提取前6列(兼容末尾多余逗号) v_date_raw := REGEXP_SUBSTR(v_line, '([^,]*)(,|$)', 1, 1, NULL, 1); v_open_raw := REGEXP_SUBSTR(v_line, '([^,]*)(,|$)', 1, 2, NULL, 1); v_high_raw := REGEXP_SUBSTR(v_line, '([^,]*)(,|$)', 1, 3, NULL, 1); v_low_raw := REGEXP_SUBSTR(v_line, '([^,]*)(,|$)', 1, 4, NULL, 1); v_close_raw := REGEXP_SUBSTR(v_line, '([^,]*)(,|$)', 1, 5, NULL, 1); v_volume_raw := REGEXP_SUBSTR(v_line, '([^,]*)(,|$)', 1, 6, NULL, 1); -- 解析日期(格式:YYYY-MM-DD) BEGIN v_date := TO_DATE(v_date_raw, 'YYYY-MM-DD'); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('[错误] 日期解析失败: ' || v_date_raw); RAISE; END; -- 解析数值字段(处理NULL和空字符串) v_open := CASE WHEN v_open_raw IN ('null', 'NULL', '') THEN NULL ELSE TO_NUMBER(v_open_raw) END; v_high := CASE WHEN v_high_raw IN ('null', 'NULL', '') THEN NULL ELSE TO_NUMBER(v_high_raw) END; v_low := CASE WHEN v_low_raw IN ('null', 'NULL', '') THEN NULL ELSE TO_NUMBER(v_low_raw) END; v_close := CASE WHEN v_close_raw IN ('null', 'NULL', '') THEN NULL ELSE TO_NUMBER(v_close_raw) END; v_volume := CASE WHEN v_volume_raw IN ('null', 'NULL', '') THEN NULL ELSE TO_NUMBER(v_volume_raw) END; -- 插入数据并累加计数器 INSERT INTO stock_data VALUES (v_date, v_open, v_close, v_high, v_low, v_volume); row_count := row_count + 1; DBMS_OUTPUT.PUT_LINE('[成功] 插入: ' || v_date || ' | 成交量: ' || v_volume); EXCEPTION WHEN NO_DATA_FOUND THEN EXIT; -- 文件读取完毕 WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('[错误] 行内容: ' || v_line); DBMS_OUTPUT.PUT_LINE('[错误] 详细: ' || SQLERRM); -- 仅跳过错误行,继续执行 END; END LOOP; -- 关闭文件并提交事务 UTL_FILE.FCLOSE(file_handle); COMMIT; DBMS_OUTPUT.PUT_LINE('[完成] 共插入 ' || row_count || ' 行数据'); EXCEPTION WHEN UTL_FILE.INVALID_PATH THEN DBMS_OUTPUT.PUT_LINE('[错误] 路径无效,请检查目录对象'); WHEN UTL_FILE.INVALID_OPERATION THEN DBMS_OUTPUT.PUT_LINE('[错误] 文件操作失败,检查权限或文件是否存在'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('[严重错误] 代码: ' || SQLCODE || ' | 信息: ' || SQLERRM); -- 尝试提交已插入的有效数据 IF row_count > 0 THEN COMMIT; DBMS_OUTPUT.PUT_LINE('[警告] 已提交 ' || row_count || ' 行有效数据'); END IF; RAISE; END; /以上代码虽然得到了正确结果,但是太长,请问能否简化
最新发布
05-23
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值