いきさつ
SQLDeveloperでも出力できるんですけど、なぜが無性にバッチで出力してみたくなりました。
準備するもの
まず、以下のスクリプトをコピーして、"csvexport.sql"というファイルを作成します。
このとき、以下の部分をメンテしてください。
メンテ箇所 |
user/password@servicename |
ユーザー名/パスワード@Oracle接続子(ネット・サービス名) |
in ('TABLE1','TABLE2'..) |
出力対象テーブル |
REPLACE(..., CHR(13), ''^`r'') |
CSVの項目値としての改行コードの変換コードを指定します(\r\n等)。
CSVレコードの終端コードではありません。改行コードをそのまま出力したい場合、省略してください。ただし、その場合は
SORTコマンドをCOPYコマンドに置き換えて下さい。改行された値が別レコードとして認識されてソートされてしまいます。
|
REPLACE(..., CHR(10), ''^`n'') |
------------------------------------------------------------------
-- Copyright(c) 2015 pakkin. All Rights Reserved.
-- [改訂履歴]
-- 2015.09.04 作成
-- 2015.09.11 処理手順を簡潔化
-- 2015.09.14 ソート、ダブルクォーテーション、ヘッダー対応
-- 2015.09.16 フォルダ構成をCSV_DATA,CSV_TEMP,CSV_READCMDに
-- 2015.09.24 CRLFを^`r^`nに置換して出力
--
-- [実行方法]
-- 1)このテキストを、"csvexport.sql"として作成します。
-- 2)作成したフォルダ上で、コマンドプロンプトを起動し、以下のコマンドを実行します。
-- @echo off
-- sqlplus -s user/password@servicename @csvexport.sql
-- csvexport.bat
--
-- [注意事項]
-- LOB系、LONG型には対応していません。
-- 並列度は4で設定しています。(DOS画面が4つ最小化状態で立ち上がります。)
-- Windows端末、SJIS出力を想定しています。
-- 改行コードは^`r^`nに置き換えています。置換を止めたい(改行コードをそのまま出力したい)場合はソートコマンドを廃止し、コピーコマンドに置き換えて下さい。
------------------------------------------------------------------
set escape ?
set linesize 300
set pagesize 0
set term off
set head off
set feed off
set trim on
set trimspool on
set verify off
------------------------------------------------------------------
-- __csvexport1.sql
------------------------------------------------------------------
spool __csvexport1.sql
prompt spool CSV_READCMD/?&?&1..sql
prompt prompt SET PAGESIZE 0
prompt prompt SET ARRAY 100
prompt prompt SET TERM OFF
prompt prompt SET HEAD OFF
prompt prompt SET FEED OFF
prompt prompt SET TRIM ON
prompt prompt SET TRIMSPOOL ON
prompt prompt SET VERIFY OFF
prompt prompt COLUMN C_REC_SZ NEW_VALUE D_REC_SZ NOPRINT
prompt prompt SELECT NVL(MAX(V_LEN.C_REC_SZ_SUB),0) AS C_REC_SZ
prompt prompt FROM (
prompt prompt SELECT LENGTHB(CONVERT(
prompt SELECT CASE WHEN COL.COLUMN_ID = 1 THEN ' ''"'
prompt WHEN COL.COLUMN_ID <> 1 THEN ' || '',"'
prompt END
prompt || REPLACE(REPLACE(NVL(CMN.COMMENTS,COL.COLUMN_NAME), CHR(13), '^`r'), CHR(10), '^`n') || '"'''
prompt FROM USER_TAB_COLUMNS COL
prompt , USER_COL_COMMENTS CMN
prompt WHERE COL.TABLE_NAME = '?&?&1'
prompt AND COL.TABLE_NAME = CMN.TABLE_NAME(+)
prompt AND COL.COLUMN_NAME = CMN.COLUMN_NAME(+)
prompt ORDER BY COL.COLUMN_ID ASC
prompt /
prompt prompt , 'JA16SJISTILDE')) AS C_REC_SZ_SUB
prompt prompt FROM DUAL
prompt prompt WHERE !?&1 = 1
prompt prompt UNION ALL
prompt prompt SELECT LENGTHB(CONVERT(
prompt SELECT RPAD(
prompt CASE WHEN COL.COLUMN_ID = 1 AND COL.DATA_TYPE = 'VARCHAR2' THEN ' ''"'' || REPLACE(REPLACE(REPLACE('
prompt WHEN COL.COLUMN_ID = 1 AND COL.DATA_TYPE = 'CHAR' THEN ' ''"'' || REPLACE(REPLACE(REPLACE('
prompt WHEN COL.COLUMN_ID = 1 AND COL.DATA_TYPE <> 'NUMBER' THEN ' ''"'' || '
prompt WHEN COL.COLUMN_ID = 1 AND COL.DATA_TYPE = 'NUMBER' THEN ' '
prompt WHEN COL.COLUMN_ID <> 1 AND COL.DATA_TYPE = 'VARCHAR2' THEN ' || '',"'' || REPLACE(REPLACE(REPLACE('
prompt WHEN COL.COLUMN_ID <> 1 AND COL.DATA_TYPE = 'CHAR' THEN ' || '',"'' || REPLACE(REPLACE(REPLACE('
prompt WHEN COL.COLUMN_ID <> 1 AND COL.DATA_TYPE <> 'NUMBER' THEN ' || '',"'' || '
prompt WHEN COL.COLUMN_ID <> 1 AND COL.DATA_TYPE = 'NUMBER' THEN ' || '','' || '
prompt END
prompt || CASE WHEN COL.DATA_TYPE = 'DATE' THEN 'TO_CHAR('
prompt WHEN COL.DATA_TYPE LIKE 'TIMESTAMP(%)' THEN 'TO_CHAR('
prompt ELSE NULL END
prompt || RPAD(COL.COLUMN_NAME,30)
prompt || CASE WHEN COL.DATA_TYPE = 'DATE' THEN ', ''YYYY/MM/DD HH24:MI:SS'')'
prompt WHEN COL.DATA_TYPE LIKE 'TIMESTAMP(%)' THEN ', ''YYYY/MM/DD HH24:MI:SS.FF' || COL.DATA_SCALE || ''')'
prompt ELSE NULL END
prompt || CASE WHEN COL.DATA_TYPE = 'VARCHAR2' THEN ',''"'',''""''), CHR(13), ''^`r''), CHR(10), ''^`n'') || ''"'''
prompt WHEN COL.DATA_TYPE = 'CHAR' THEN ',''"'',''""''), CHR(13), ''^`r''), CHR(10), ''^`n'') || ''"'''
prompt WHEN COL.DATA_TYPE <> 'NUMBER' THEN ' || ''"'''
prompt ELSE NULL END,120)
prompt || NVL2(CMN.COMMENTS,'-- ' || CMN.COMMENTS,' ')
prompt FROM USER_TAB_COLUMNS COL
prompt , USER_COL_COMMENTS CMN
prompt WHERE COL.TABLE_NAME = '?&?&1'
prompt AND COL.TABLE_NAME = CMN.TABLE_NAME(+)
prompt AND COL.COLUMN_NAME = CMN.COLUMN_NAME(+)
prompt ORDER BY COL.COLUMN_ID ASC
prompt /
prompt prompt , 'JA16SJISTILDE')) AS C_REC_SZ_SUB
prompt prompt FROM ?&?&1
prompt prompt WHERE ORA_HASH(ROWIDTOCHAR(ROWID),!?&2,1)=!?&!?&1 - 1
prompt prompt ) V_LEN
prompt prompt /
prompt prompt SET LINESIZE !?&D_REC_SZ
prompt prompt SPOOL CSV_TEMP/?&?&1..csv!?&!?&1.h
prompt SELECT CASE WHEN COL.COLUMN_ID = 1 THEN 'SELECT ''"'
prompt WHEN COL.COLUMN_ID <> 1 THEN ' || '',"'
prompt END
prompt || REPLACE(REPLACE(NVL(CMN.COMMENTS,COL.COLUMN_NAME), CHR(13), '^`r'), CHR(10), '^`n') || '"'''
prompt FROM USER_TAB_COLUMNS COL
prompt , USER_COL_COMMENTS CMN
prompt WHERE COL.TABLE_NAME = '?&?&1'
prompt AND COL.TABLE_NAME = CMN.TABLE_NAME(+)
prompt AND COL.COLUMN_NAME = CMN.COLUMN_NAME(+)
prompt ORDER BY COL.COLUMN_ID ASC
prompt /
prompt prompt FROM DUAL
prompt prompt WHERE !?&!?&1 = 1
prompt prompt /
prompt prompt SPOOL CSV_TEMP/?&?&1..csv!?&!?&1.d
prompt SELECT RPAD(
prompt CASE WHEN COL.COLUMN_ID = 1 AND COL.DATA_TYPE = 'VARCHAR2' THEN 'SELECT ''"'' || REPLACE(REPLACE(REPLACE('
prompt WHEN COL.COLUMN_ID = 1 AND COL.DATA_TYPE = 'CHAR' THEN 'SELECT ''"'' || REPLACE(REPLACE(REPLACE('
prompt WHEN COL.COLUMN_ID = 1 AND COL.DATA_TYPE <> 'NUMBER' THEN 'SELECT ''"'' || '
prompt WHEN COL.COLUMN_ID = 1 AND COL.DATA_TYPE = 'NUMBER' THEN 'SELECT '
prompt WHEN COL.COLUMN_ID <> 1 AND COL.DATA_TYPE = 'VARCHAR2' THEN ' || '',"'' || REPLACE(REPLACE(REPLACE('
prompt WHEN COL.COLUMN_ID <> 1 AND COL.DATA_TYPE = 'CHAR' THEN ' || '',"'' || REPLACE(REPLACE(REPLACE('
prompt WHEN COL.COLUMN_ID <> 1 AND COL.DATA_TYPE <> 'NUMBER' THEN ' || '',"'' || '
prompt WHEN COL.COLUMN_ID <> 1 AND COL.DATA_TYPE = 'NUMBER' THEN ' || '','' || '
prompt END
prompt || CASE WHEN COL.DATA_TYPE = 'DATE' THEN 'TO_CHAR('
prompt WHEN COL.DATA_TYPE LIKE 'TIMESTAMP(%)' THEN 'TO_CHAR('
prompt ELSE NULL END
prompt || RPAD(COL.COLUMN_NAME,30)
prompt || CASE WHEN COL.DATA_TYPE = 'DATE' THEN ', ''YYYY/MM/DD HH24:MI:SS'')'
prompt WHEN COL.DATA_TYPE LIKE 'TIMESTAMP(%)' THEN ', ''YYYY/MM/DD HH24:MI:SS.FF' || COL.DATA_SCALE || ''')'
prompt ELSE NULL END
prompt || CASE WHEN COL.DATA_TYPE = 'VARCHAR2' THEN ',''"'',''""''), CHR(13), ''^`r''), CHR(10), ''^`n'') || ''"'''
prompt WHEN COL.DATA_TYPE = 'CHAR' THEN ',''"'',''""''), CHR(13), ''^`r''), CHR(10), ''^`n'') || ''"'''
prompt WHEN COL.DATA_TYPE <> 'NUMBER' THEN ' || ''"'''
prompt ELSE NULL END,120)
prompt || NVL2(CMN.COMMENTS,'-- ' || CMN.COMMENTS,' ')
prompt FROM USER_TAB_COLUMNS COL
prompt , USER_COL_COMMENTS CMN
prompt WHERE COL.TABLE_NAME = '?&?&1'
prompt AND COL.TABLE_NAME = CMN.TABLE_NAME(+)
prompt AND COL.COLUMN_NAME = CMN.COLUMN_NAME(+)
prompt ORDER BY COL.COLUMN_ID ASC
prompt /
prompt prompt AS CSV_DATA FROM ?&?&1
prompt prompt WHERE ORA_HASH(ROWIDTOCHAR(ROWID),!?&!?&2,1)=!?&!?&1 - 1
prompt prompt /
prompt prompt SPOOL OFF
prompt prompt EXIT
prompt spool off
spool off
------------------------------------------------------------------
-- バッチファイル初期化
------------------------------------------------------------------
spool __csvexport1.add
prompt @ECHO OFF
prompt IF "%1" NEQ "" GOTO THREAD_PROC
prompt DEL /Q CSV_TEMP\*.* >> __csvexport1.log 2>> __csvexport2.log
prompt START /MIN csvexport.bat 1
prompt START /MIN csvexport.bat 2
prompt START /MIN csvexport.bat 3
prompt START /MIN csvexport.bat 4
spool off
spool __csvexport2.add
spool off
------------------------------------------------------------------
-- __csvexport2.sql
------------------------------------------------------------------
spool __csvexport2.sql
select '@__csvexport1.sql ' || tbl.table_name || '
spool __csvexport1.add APPEND
prompt :WAIT_' || tbl.table_name || '
prompt if exist CSV_TEMP\' || tbl.table_name || '.end1 ' ||
'if exist CSV_TEMP\' || tbl.table_name || '.end2 ' ||
'if exist CSV_TEMP\' || tbl.table_name || '.end3 ' ||
'if exist CSV_TEMP\' || tbl.table_name || '.end4 GOTO END_' || tbl.table_name || '
prompt PING localhost -n 1 > nul
prompt GOTO WAIT_' || tbl.table_name || '
prompt :END_' || tbl.table_name || '
prompt COPY /Y /B CSV_TEMP\' || tbl.table_name || '.csv1h CSV_DATA\' || tbl.table_name || '.csv > nul
prompt COPY /Y /B CSV_TEMP\' || tbl.table_name || '.csv*d CSV_TEMP\' || tbl.table_name || '.csv > nul
prompt SORT CSV_TEMP\' || tbl.table_name || '.csv >> CSV_DATA\' || tbl.table_name || '.csv
prompt SET /P X=CSV出力対象テーブル : ' || rpad(tbl.table_name,30) || ' 出力行数 : <nul
prompt TYPE CSV_TEMP\' || tbl.table_name || '.csv | FIND /C /V ""
prompt DEL CSV_TEMP\' || tbl.table_name || '.* >> __csvexport1.log 2>> __csvexport2.log
spool OFF
spool __csvexport2.add APPEND
prompt SQLPLUS -s user/password@servicename @CSV_READCMD/' || tbl.table_name || '.sql %1 3
prompt ECHO 1 > CSV_TEMP/' || tbl.table_name || '.end%1
prompt ECHO ' || tbl.table_name || '.csv
spool OFF
' as cmdline
from user_tables tbl
where tbl.table_name in ('TABLE1','TABLE2'..)
order by table_name asc
/
spool off
------------------------------------------------------------------
-- バッチファイル終了処理組み込み+連結+一時ファイルクリア
------------------------------------------------------------------
$MKDIR CSV_DATA >> __csvexport1.log 2>> __csvexport2.log
$MKDIR CSV_READCMD >> __csvexport1.log 2>> __csvexport2.log
$MKDIR CSV_TEMP >> __csvexport1.log 2>> __csvexport2.log
set escape off
set escape !
@__csvexport2.sql
spool __csvexport1.add APPEND
prompt DEL __csvexport*.*
prompt ECHO CSVファイルを出力しました。"EXIT"コマンドで終了して下さい。
prompt GOTO LAST_PROC
prompt :THREAD_PROC
spool off
spool __csvexport2.add APPEND
prompt EXIT
prompt EXIT /B
prompt :LAST_PROC
spool off
$copy /B __csvexport*.add csvexport.bat >> __csvexport1.log 2>> __csvexport2.log
$del __csvexport*.*
$echo スクリプトを生成しました。
exit
実行
スクリプトの存在するフォルダ上でコマンドプロンプトを開き、以下のコマンドを実行します。
@echo off
sqlplus -s user/password@servicename @csvexport.sql
csvexport.bat
実行時に生成されるサブフォルダ |
CSV_READCMD |
CSV形式でデータ出力するスクリプトを生成 |
CSV_TEMP |
CSV出力用の作業領域 |
CSV_DATA |
CSV形式の実データ |
実行結果
[csvexport.bat]
[EXPコマンド]
[EXPDPコマンド]
[1GB程度のデータの出力にかかった時間]
あくまでも私個人での環境での実測結果です。