Groovyでテーブルのデータを取得したい(5)
先日の日記で、SafeArrayを使用してスクリプトの時間短縮にチャレンジしたのですが、
まだまだ時間がかかるため、もっと改良できないかと思案中。。。
ただ、SafeArrayのコンストラクタには2次元以上の配列を受け取るものが存在しないので
無理なのかと思っていたのですが、putAtというメソッドを発見しました。
http://groovy.codehaus.org/modules/scriptom/1.6.0/scriptom/apidocs/org/codehaus/groovy/scriptom/SafeArray.html
第一引数、第二引数ともにObject型をとりますが、第一引数には行列を表すリストを指定できます。(←いろいろ試してみた結果)
第二引数には、設定したい値を指定します。
putAtで行列データを挿入していくためには、コンストラクタで行列数をRange(1..N)指定してやる必要があるようです。(←いろいろ試してみた結果)
SafeArray safeArray = new SafeArray(型の種類,1..行数,1..列数)
これで行数分(約4万回)worksheet.rangeをコールしていた部分が、一気にテーブル分(19回)に減ります。
改良したコードは以下の通りです。
import java.text.SimpleDateFormat import org.codehaus.groovy.scriptom.ActiveXObject import org.codehaus.groovy.scriptom.SafeArray def sql = groovy.sql.Sql.newInstance('jdbc:oracle:thin:@localhost:1521:ORCL','userid','password','oracle.jdbc.driver.OracleDriver') def xlApp = new ActiveXObject('Excel.Application') def username = "INIT" def workbook = xlApp.workbooks.Add SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss") sql.eachRow("SELECT table_name FROM user_tables WHERE table_name LIKE 'BIZ_AB_%'"){ rs-> def rows = sql.rows("SELECT * FROM " + rs.table_name +" WHERE create_user_cd ='" + username + "'") if( rows.size() > 0 ){ def worksheet = workbook.worksheets.Add worksheet.name = rs.table_name def (long rowNumber, long colNumber) = [1,1] SafeArray safeArray = new SafeArray(org.codehaus.groovy.scriptom.SafeArray.VARIANT,1..rows.size()+1,1..rows[0].size()) for(r in rows){ if(1==rowNumber){ r.each{ safeArray.putAt([rowNumber,colNumber++],it.key) } rowNumber++ } colNumber = 1 r.each{ if( it.value instanceof oracle.sql.TIMESTAMP ) it.value = sdf.format(it.value.dateValue()) safeArray.putAt([rowNumber,colNumber++],it.value) } rowNumber++ } worksheet.Range(worksheet.cells(1,1),worksheet.cells(rows.size()+1,rows[0].size())).Value = safeArray } } xlApp.visible = true
これで約19秒で実行できるようになりました。(140秒→19秒)
もっと劇的に早くできる方法はないか、模索中です。