[Dd]enzow(ill)? with DB and Python

DBとか資格とかPythonとかの話をつらつらと

PythonからOracleに繋いでみる!その2 (sqlpylus(sqlplusではない)でOracleに繋いで見る)

この記事はJPOUG Advent Calendar 2017の3日目です。 さらに同日にもう1記事あげていますのでよろしければご覧ください。

本記事では、sqlpylusを使用してPythonからOracle DatabaseにSQLを発行する流れをご紹介します。 なお、sqlpylusはsqlplusの誤植ではありません。

sqlpylus?

sqlpylusはPythonからOracle DatabaseにSQLを実行し、その結果を扱いやすいDict形式で取得するPython用のライブラリです。

以下READMEからの抜粋です。

sqlpylus はPython経由でOracleDatabaseにSQLを発行できるモジュールです。内部的にはSQLPLUSを起動し、その結果を標準出力経由で受け取って加工しています。

というか、この記事のために以前書き捨てていたコードを急いで整えたものになります。

こんな感じで比較的直感的に利用することが可能です。

import SqlPylus

conn = SqlPylus().connect('scott', 'tiger', 'localhost:1521/orcl')
for row in conn.execute('select empno, deptno from emp'):
    print(row['EMPNO'], row['DEPTNO'])
conn.close()

何故作ったのか

sqlpylusはOCIを利用するcx_Oracleに比べるとSQLPLUSを裏で起動した上で処理しているためパフォーマンス・機能面すべてで劣っていますしかし、唯一のメリットとして1ファイルで構成されているため導入が簡単という点があります。

1ファイルで構成されているため、単一のPythonファイルを実行環境に配置できればそのまま利用できます。以下のような利用ケースを想定しています。 (果たしてこれらの用途でPythonを採用しているケースがどの程度あるかは不明ですが…)

  • バッチ処理の一部での若干面倒なSQLの処理
  • パフォーマンス監視等でSELECTの結果を整ったデータ形式で取得する簡易スクリプトへの組み込み

もちろん、これらのケースではcx_Oracleを利用できればよいのですが、多くの場合このような環境はネットワークの制限が厳しかったり、pipの導入ができなかったりといった理由でcx_Oracleを採用できないケースが多い気がします。

sqlpylusはRedhat6やOracleLinux6系で標準でバンドルされているPython2.6以上で動作するため、このスクリプトさえ、配置できれば利用できます。できれば、Redhat5系でバンドルされているPython2.4もサポートしたいところなのですが、2.4になるとsubprocess関連が途端に貧弱になるので現状はやっていません。

利用方法

繋いでexecuteでSQLを実行するくらいですので大した内容はありませんが、 READMEにまとめています。

内部的な話

sqlplusの結果の表示形式は残念ながら結構崩れるので、そのままパースするのは少しつらいです。しかし、sqlplusは結果をHTML形式で戻すオプション(-M "HTML ON")があります。これを利用するとselect ename, empno from scott.emp where deptno=10;の結果が以下のような形式で結果が戻されます。

ENAME EMPNO
CLARK 7782
KING 7839
MILLER 7934

HTMLとしては以下の形です。

<p>
<table border='1' width='90%' align='center' summary='Script output'>
<tr>
<th scope="col">
ENAME
</th>
<th scope="col">
EMPNO
</th>
</tr>
<tr>
<td>
CLARK
</td>
<td align="right">
      7782
</td>
</tr>
<tr>
<td>
KING
</td>
<td align="right">
      7839
</td>
</tr>
<tr>
<td>
MILLER
</td>
<td align="right">
      7934
</td>
</tr>
</table>
<p>

あとは、これをTHタグとTDタグについて処理してやればJSONやPythonのDictのように整った形式に変換するのは難しくありません。

なお、number型の結果については

<td align="right">
      7934
</td>

という形でalign="right"が付与されているので受け取る際にfloatにキャストしています。それ以外のデータ型は型情報が判別できないのでstr(unicode)として戻しています。

まとめ

単一スクリプトで利用できるPython用Oracle Databaseアダプタのsqlpylusをご紹介しました。最低限の機能しか実装していませんが、何かのご参考になれば幸いです。