之前項目運維人員碰到一個問題,需要寫一個存儲過程,把數據導出為csv文件,查了一些資料,幫他寫成了一個PLSQL,今天拿出來分享一下,不足之處,歡迎指教。
數據背景: 用到兩張表,一張存放單位組織名稱org_name,它只有一個字段org_name;一張存放要導出的具體數據ryxx,其中ryxx這張表有一個字段是org_name中的org_name字段(需要like '%org_name%')。(表因為一些原因不能貼出來,見諒)
目標需求: 要求根據單位組織名稱即org_name,分批導出ryxx數據為csv文件,並且導出的文件最大不能超過30000行,文件名為單位組織名稱后跟序號
所用知識: PLSQL語法,包括游標、循環、條件等語句,CSV文件導出語法
具體實現:
--1、創建要導出文件的存放地址的變量
CREATE OR REPLACE DIRECTORY mydir AS 'D:\sjdc';
--2、PLSQL開始
DECLARE
-- 定義游標 org 用於獲取組織名稱
CURSOR org IS SELECT org_name FROM org_name;
-- 定義組織名 org_name, 接收組織名
org_name VARCHAR2(40);
-- 定義組織名相似匹配(用於 LIKE 查詢)
org_name_like VARCHAR(40);
-- 定義總量,接收每次根據組織名稱查詢時 ryxx 表中匹配的數據總量
count_number NUMBER;
-- 定義每個組織名稱關聯的數據需要循環次數(因為每次導出只能導出30000條數據,需要多次導出)
loop_times NUMBER;
-- 定義當前循環到第幾次(同上)
loop_i NUMBER;
-- 定義根據 org_name 匹配查詢出的具體數據,為SYS_REFCURSOR類型,即動態游標
data_cur SYS_REFCURSOR;
-- 定義匹配查詢出的具體數據的總量(同上)
count_cur SYS_REFCURSOR;
-- 定義文件輸出
csv_output UTL_FILE.FILE_TYPE;
-- 定義 ryxx 的行類型
data_row ryxx%ROWTYPE;
-- 每個文件導出的最大行數
MAX_LINE NUMBER := 30000;
-- 輸出位置
dir VARCHAR(20) := 'MYDIR';
-- 函數體開始
BEGIN
-- 1、打開 org 游標,獲取組織名稱,挨個取出名稱進行操作
OPEN org;
LOOP
-- 2、循環取出組織名稱,當無數據時推出循環
FETCH org INTO org_name;
EXIT WHEN org%NOTFOUND;
-- 3、拼接相似查詢的 org_name_like,兩邊都有%
org_name_like := '%' || org_name || '%';
-- 4、打開游標 count_cur, 查詢對應的單位名稱下的 ryxx 總量
OPEN count_cur FOR 'SELECT COUNT(*) FROM ryxx WHERE st_code_name like :org_name_like' USING org_name_like;
FETCH count_cur INTO count_number;
CLOSE count_cur;
-- 5、 計算此單位的數據總共需要導出幾次
loop_times := count_number/MAX_LINE;
-- 6、 開始循環導出數據
loop_i := 0;
LOOP
-- 退出循環條件:當前循環次數大於總共要循環的次數
EXIT WHEN loop_i > loop_times;
IF loop_i <= loop_times THEN
-- 7、打開查詢數據的data_cur游標,導出數據(需要分頁查詢,所以外層不能直接用*,否則不能把數據放入data_row)
OPEN data_cur FOR 'SELECT id, name, age FROM
(SELECT t.*, rownum rn FROM ryxx WHERE ST_CODE_NAME LIKE :org_name_like)
WHERE rn <= ' || TO_CHAR((loop_i) * MAX_LINE) || ' AND rn > ' || TO_CHAR(loop_i * MAX_LINE) USING org_name_like;
csv_output := UTL_FILE.FOPEN('MYDIR', org_name || loop_i || '.csv', 'W', MAX_LINE);
LOOP
FETCH data_cur INTO data_row;
EXIT WHEN data_cur%NOTFOUND;
UTL_FILE.PUT_LINE(CSV_OUTPUT, data_row.id || ',' || data_row.name || ',' || data_row.age);
END LOOP;
loop_i := loop_i + i;
UTL_FILE.FCLOSE(csv_output);
CLOSE data_cur;
END IF;
END LOOP;
END LOOP;
CLOSE org;
END;
/
