MySQL: CSVエクスポートをリモートでも対応にする方法 (windows)
毎回毎回、それをやろうとすると、ん?あれ?って思う、MySQLの謎仕様、それがエクスポートコマンドです(汗
通常MySQLでのデータエクスポートといえばこれですね。
・通常でのMySQLのEXPORT例 [SQL] SELECT * INTO OUTFILE '/tmp/table_a.csv' FIELDS TERMINATED BY ',' LINES TERMINATED BY '\r\n' FROM table_a; [/SQL]
区切り文字の設定や、改行の設定とかオプションで選択できる感じかと思います。私の場合、基本的にDBサーバ直接の操作を行うほうが多いので、このコマンドはよく使うのですが。たとえば、上記のSQLをリモートで発行した場合どうなっちゃうか知ってます? 答えは、DBサーバ側にCSVが生成されてしまうでした!なんだそりゃ? 結局のところ、MySQLの INTO OUFILE句は、リモートからのリクエストで生成したCSVは呼び出し元のディレクトリには保存してくれないのです。LOADはリモートからローカルファイルを実行できるくせに、エクスポートだけ、なんでこんなに中途半端な仕様なのか?正直理解に苦しみます。一部の方がセキュリティの一環といっているところを昔どこかで見た気がしますが、だったら、MySQL DUMPも制限しろよ!とか思うのです。 ちなみに、INTO OUTFILEを指定しない代替案として、TAB区切りで通常のSQL結果をリダイレクトしてファイル出力する方法なんていうものありますが、CSVファイルで出力する方法はありません。また、TABを含むデータがあった場合、きっとなんか出力結果おかしくなりそうな気がする・・。
というわけで、EXPORTをリモートで実行して呼び出し元に、その出力結果を返す、スクリプトを作成しました。VBScriptでwww何故、VBS(VBScript)を言語としてチョイスしたか?ですが、単純な理由で、その他の言語でこれを実現する場合、その環境に即した設定とかを作るのが嫌だったからであって、つまり、VBScriptが好きだからという理由ではありません。また、VBSであれば、面倒な設定など行わずにさくっと実行できますしね。それ以外の理由はないです。
以下のポイントを中心につくってみました。 ・なんとなく、MySQLコマンド風に引数設定できて・・ ・カラム属性が文字型の場合は、ダブルクォーテーションでくくる ・ヘッダの出力は引数でON,OFFできるようにする
以下が作成したスクリプトです。VBScriptとADO(ActiveX Data Object)でやってみました。
【MySQL_EXPORT_REMOTE.vbs】 [TEXT] Option Explicit ' ' MySQL CSVエクスポートをリモートから実行するスクリプト '*
public pHOSTNAME public pUSERID public pPASSWD public pSCHEMA public pSQL public pHEAD
call main
' ' メイン処理 '* sub main()
dim cn dim rs
Set cn = wscript.CreateObject("ADODB.Connection") Set rs = wscript.CreateObject("ADODB.recordset")
Dim connectionString Dim strSQL
Dim colNo Dim item Dim header Dim detail
call setArg
'接続文字列 connectionString = "Driver={MySQL ODBC 5.1 DRIVER};" _ & " SERVER=" & pHOSTNAME & ";" _ & " DATABASE=" & pSCHEMA & ";" _ & " USER=" & pUSERID & ";" _ & " PASSWORD=" & pPASSWD & ";" ' MySQLのオープン cn.Open connectionString
strSQL = pSQL
rs.Open strSQL, cn, 0, 1
' ヘッダ情報を含める if pHEAD <> 1 then header = "" colNo = 1 For Each item In rs.fields header = header & item.name if rs.fields.count <> colNo then header = header & "," end if colNo = colNo + 1
next
wscript.echo header
end if
do while not rs.EOF
detail = "" colNo = 1 For Each item In rs.fields detail = detail & TYPE2quote(item.type,item.value)
if rs.fields.count <> colNo then detail = detail & "," end if colNo = colNo + 1
next
wscript.echo detail
rs.movenext loop
rs.close set rs = nothing
cn.close set cn = nothing
end sub
' ' 文字列の型を識別し、ダブルクォートを付けるかつけないか判断する ' function TYPE2quote(byval strType, byval strVal)
const quote = """" dim result
select case strType case 8,12,128,129,133,134,135,200,202,204 result = quote & strVal & quote case else result = strVal end select
TYPE2quote = result
end function
' ' 引数を取得し設定する ' sub setArg()
Dim lngLoop ' ループカウンタ
For lngLoop = 0 To WScript.Arguments.Count - 1 select case WScript.Arguments.Item(lngLoop) case "-h" pHOSTNAME = WScript.Arguments.Item(lngLoop + 1) case "-u" pUSERID = WScript.Arguments.Item(lngLoop + 1) case "-p" pPASSWD = WScript.Arguments.Item(lngLoop + 1) case "-s" pSCHEMA = WScript.Arguments.Item(lngLoop + 1) case "-sql" pSQL = WScript.Arguments.Item(lngLoop + 1) case "-nohead" pHEAD = 1 end select Next
end sub [/TEXT]
・ちなみにこのshellはコマンドベースで行うことを前提に作っております。WSH(Windows Scripting Host)って、コマンドベースで実行するものと、GUIベースで実行するものとの2通りが存在します。 上記のSHELLをコマンドで実行する場合の例を以下に記載します。
[TEXT] C:\ cscript //nologo MySQL_EXPORT_REMOTE.vbs -h mysqlhostname -u userid -p password -s schema_name -sql "select * from table_a" -nohead > c:\table_a.csv [/TEXT]
はじめは、CSVファイルも、FileSystemObjectを利用しようと思いましたが、echoの結果を、ファイルにリダイレクトかけたほうがなんか、MySQLっぽいので上記に構成に至ったわけです。
・スクリプトの引数としては以下のものがあります。 [TEXT] -h hostname・・・ホスト名を指定 -u userid・・・ユーザー名を指定 -p password・・・パスワードを指定 -s schema・・・ターゲットスキーマ(データベース名)を指定 -sql・・・SQLを設定、この引数のみ、SQLの部分は、ダブルクォーテーションで括ります -nohead・・ヘッダを出力しない [/TEXT] ※引数の順番は順不同での指定も対応しており、例えばこんな感じで引数の順番を変えても正常に動きます。 [TEXT] C:\ cscript //nologo MySQL_EXPORT_REMOTE.vbs -sql "select * from table_a" -u userid -h mysqlhostname -p password -s schema_name -nohead > c:\table_a.csv [/TEXT] 但し、-nohead以外の引数の設定は必須です、引数の設定が1つでも抜けてしまうと、きっとエラーになって落ちると思います。そもそもこのスクリプトでエラートラップをかけておりませんので、皆様のセンスで追記していただけたらと思いますw
尚、このshellを実行するための環境は ・Windowsである ・MySQL connector for ODBCがインストールされている ことが必須です。
色々の中途半端なことをやっていると思いますが、みなさまもどんどん改造してもらって改造してもらったものを私にくれればと思います。
でわでわ!!