Oracle11g データCSV出力
前書き
以前、WinMergeを使い、データの新旧比較をしていましたが、その際比較するためのデータを出力する必要があったので、OracleからデータをCSV出力するスクリプトを、Oracleのテーブル定義(USER_TAB_COLUMNS)から動的に作るようにしていました。
Oracle12c以降は、SET MARKUP CSVでCSV出力ができるようなのですが、11g以前にはそのような機能が無く、テストの際に割と便利に使っていたので、自分の備忘を兼ねてソースを書いておこうと思います。
ソース
ソースは以下の通り。大したことはしておらず、USER_TABLEから、テーブルの名称順にテーブルの一覧を取得し、USER_TAB_COLUMNSから列名を取得して、全てデータを文字列に変換して、「,」カンマ区切りでデータを出力するSQLを動的に作成するようになっています。
ファイル名:create_csv.sql
SET SERVEROUTPUT ON;
SET TRIMSPOOL ON;
SET LINESIZE 32767
SET FEEDBACK OFF;
SPOOL result.sql;
DECLARE
vColumns VARCHAR2(32767) := '';
vTempCol VARCHAR2(256) := '';
vSorts VARCHAR2(32767) := '';
--ファイル情報
CURSOR vCur IS
SELECT
T1.TABLE_NAME AS TABLE_ID
FROM
USER_TABLES T1
ORDER BY
T1.TABLE_NAME;
vRec vCur%ROWTYPE;
--
--テーブル情報
CURSOR vCur2(pI_Table VARCHAR2) IS
SELECT
*
FROM
USER_TAB_COLUMNS T1
WHERE
T1.TABLE_NAME = pI_Table
ORDER BY
T1.COLUMN_ID;
vRec2 vCur2%ROWTYPE;
--
BEGIN
-- 共通パラメータ出力
DBMS_OUTPUT.PUT_LINE('SET WRAP OFF');
DBMS_OUTPUT.PUT_LINE('SET COLSEP '' ''');
DBMS_OUTPUT.PUT_LINE('SET TRIMSPOOL ON');
DBMS_OUTPUT.PUT_LINE('SET TRIMOUT ON');
DBMS_OUTPUT.PUT_LINE('SET LINESIZE 32767');
DBMS_OUTPUT.PUT_LINE('SET PAGESIZE 0');
DBMS_OUTPUT.PUT_LINE('SET FEEDBACK OFF');
DBMS_OUTPUT.PUT_LINE('SET SERVEROUTPUT ON');
--
FOR vRec IN vCur
LOOP
FOR vRec2 IN vCur2(vRec.TABLE_ID)
LOOP--
-- 動的SQL組み立て
IF vRec2.DATA_TYPE IN ('CHAR','VARCHAR2') THEN
vTempCol := vRec2.COLUMN_NAME;
ELSE
vTempCol := 'TO_CHAR('||vRec2.COLUMN_NAME||')';
END IF;
IF (vRec2.COLUMN_ID = '1') THEN
vColumns := vTempCol;
vSorts := vRec2.COLUMN_NAME;
ELSE
vColumns := vColumns ||'||'',''||'||vTempCol;
vSorts := vSorts || ',' || vRec2.COLUMN_NAME;
END IF;
END LOOP;
--各テーブルの出力SQL
DBMS_OUTPUT.PUT_LINE('spool '||vRec.TABLE_ID|| '.csv');
DBMS_OUTPUT.PUT_LINE('EXEC DBMS_OUTPUT.PUT_LINE( '''||vSorts ||''');');
DBMS_OUTPUT.PUT_LINE('SELECT '||vColumns ||' FROM ' || vRec.TABLE_ID ||' ORDER BY '|| vSorts ||';');
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('spool off');
END LOOP;
END;
/
SPOOL OFF;
create_csv.sql(2021/3/19 追記)リンク先のソースに誤りがありましたので、修正致しました。
実際にソースを実行すると、下記のようなテーブル毎にCSVファイルをspoolで出力するためのsqlが作成されます。
後は、これを実行することで、OracleのデータをCSV形式で出力することができます。(ただ、sqlplusの行幅や列の上限は考慮していないので、あくまでベースと考えて利用の際は適宜修正した方が良いです。)
ファイル名:result.sql
SET WRAP OFF
SET COLSEP ' '
SET TRIMSPOOL ON
SET TRIMOUT ON
SET LINESIZE 32767
SET PAGESIZE 0
SET FEEDBACK OFF
SET SERVEROUTPUT ON
spool TEST_TABLE.csv
EXEC DBMS_OUTPUT.PUT_LINE( 'AAA,BBB,CCC');
SELECT AAA||','||BBB||','||TO_CHAR(CCC) FROM TEST_TABLE ORDER BY AAA,BBB,CCC;
spool off
--・・・以下 テーブル毎にspoolするためのSQLが出力されます。
結果
こんな感じでCSVを出力するためのsqlを作成し、後は使いたいsqlを使い、先日紹介したWinMergeと合わせて利用することで、テストを大分簡略化することができました。(WinMergeについては、下記、関連記事を参考)
一つ一つ自分でSQLを書くよりも、Oracleの定義さえあればどこでも使えて、自動でスクリプトが作ることができ、割と便利に使っているので、ご参考になれば幸いです。