PythonでOracleデータベースを扱う:cx_Oracle入門

Oracle Databaseは企業システムで広く使われるリレーショナルデータベース管理システム(RDBMS)です。

PythonからOracleデータベースを操作する際に便利なのが、Oracle公式のDB APIラッパーであるcx_Oracleライブラリです。

本記事では、cx_Oracleの基本的な使い方を初心者向けに解説し、最後に演習問題と解答例を紹介します。


cx_Oracleとは

cx_Oracleは、PythonからOracleデータベースを操作するための公式DB API準拠ドライバです。

特徴は以下のとおりです。

  • OCI(Oracle Call Interface)を利用した高速かつ安定した通信
  • プレースホルダーを使ったSQLパラメータバインド
  • LOB(CLOB/BLOB)や配列バインドなどの高度な機能をサポート
  • トランザクション制御や接続プールにも対応

開発環境の準備

  1. Oracle Instant Clientのダウンロード
    Oracleの公式サイトから、自分のOS/バージョンに合ったInstant Clientを取得し、展開またはインストールします。
  2. Oracle Database(またはOracle XE)の用意
    ローカルマシンにOracle Databaseを入れるか、すでに稼働中のホストへ接続できるアカウント情報を用意してください。
  3. Python環境
    Python 3.6以上を推奨。仮想環境(venvやvirtualenv)を使うと依存管理が楽になります。

cx_Oracleのインストール

仮想環境を有効化した上で、pipコマンドでインストールします。

python -m pip install cx_Oracle

※ Instant Clientが正しくインストールされている場合、自動的にOCIライブラリを参照します。環境変数LD_LIBRARY_PATH(Linux)やPATH(Windows)にInstant Clientのパスを追加してください。


データベース接続の基本

import cx_Oracle

# 接続文字列:user/password@host:port/service_name
dsn = cx_Oracle.makedsn("db_host", 1521, service_name="ORCLPDB1")
conn = cx_Oracle.connect(user="scott", password="tiger", dsn=dsn)

# カーソルを取得
cur = conn.cursor()

# …ここでSQL実行…

# 後片付け
cur.close()
conn.close()
  • makedsn: ホスト名・ポート・サービス名を組み合わせてDSNを生成
  • connect: DSNから接続オブジェクトを返す
  • cursor: SQL実行用のカーソルオブジェクト

SQLの実行

SELECT文

cur.execute("SELECT empno, ename, sal FROM emp WHERE deptno = :dept", dept=10)
for empno, ename, sal in cur:
    print(f"{empno}: {ename} — {sal}")
  • プレースホルダー:deptにキーワード引数dept=10で値をバインド
  • cur.fetchall()やcur.fetchone()でも結果取得可能

INSERT文

sql = "INSERT INTO emp (empno, ename, job, sal, deptno) VALUES (:1, :2, :3, :4, :5)"
data = (9999, "JANE", "ANALYST", 3000, 20)
cur.execute(sql, data)
conn.commit()
  • 数値位置プレースホルダー:1, :2…にタプルをバインド
  • conn.commit()でトランザクションをコミット

UPDATE/DELETE文

# UPDATE
cur.execute("UPDATE emp SET sal = sal * 1.1 WHERE deptno = :d", d=20)
conn.commit()

# DELETE
cur.execute("DELETE FROM emp WHERE empno = :e", e=9999)
conn.commit()

トランザクション制御

  • 自動コミットはデフォルトでOFF。複数の操作をまとめてコミットすることで整合性を保てます。
  • conn.rollback()でロールバックも可能。

接続のクローズと例外処理

try:
    conn = cx_Oracle.connect(...)
    cur = conn.cursor()
    # SQL実行
except cx_Oracle.DatabaseError as e:
    print("データベースエラー:", e)
    conn.rollback()
finally:
    if cur:
        cur.close()
    if conn:
        conn.close()
  • try-except-finallyで必ずリソースを解放
  • エラー発生時はロールバックして状態を戻す

演習問題

  1. 問題1
    empテーブルからdeptnoが30の社員情報を取得し、社員番号(empno)と名前(ename)を一覧表示するPythonスクリプトを作成せよ。
  2. 問題2
    新規社員レコードを1件追加するスクリプトを作成せよ。社員番号は8888、名前は“TEST”、職種“DEV”、給与2000、部署番号10とする。
  3. 問題3
    部署番号20の社員の給与を5%アップし、その後ロールバックするコードを作成せよ。実際にデータベースには変更を反映させないこと。

解答例

解答例1
import cx_Oracle

dsn = cx_Oracle.makedsn("db_host", 1521, service_name="ORCLPDB1")
conn = cx_Oracle.connect("scott", "tiger", dsn)
cur = conn.cursor()

cur.execute("SELECT empno, ename FROM emp WHERE deptno = :d", d=30)
for empno, ename in cur:
    print(f"{empno} — {ename}")

cur.close()
conn.close()
解答例2
import cx_Oracle

dsn = cx_Oracle.makedsn("db_host", 1521, service_name="ORCLPDB1")
conn = cx_Oracle.connect("scott", "tiger", dsn)
cur = conn.cursor()

sql = """
INSERT INTO emp (empno, ename, job, sal, deptno)
VALUES (:1, :2, :3, :4, :5)
"""
data = (8888, "TEST", "DEV", 2000, 10)
cur.execute(sql, data)
conn.commit()

print("レコードを追加しました。")

cur.close()
conn.close()
解答例3
import cx_Oracle

dsn = cx_Oracle.makedsn("db_host", 1521, service_name="ORCLPDB1")
conn = cx_Oracle.connect("scott", "tiger", dsn)
cur = conn.cursor()

try:
    cur.execute("UPDATE emp SET sal = sal * 1.05 WHERE deptno = :d", d=20)
    # 変更を確認してロールバック
    cur.execute("SELECT empno, sal FROM emp WHERE deptno = 20")
    for empno, sal in cur:
        print(f"{empno}: 新給与 {sal}")
    print("ロールバックします。")
    conn.rollback()
finally:
    cur.close()
    conn.close()

実際に手を動かしながら、接続やSQL実行の流れを体感し、エラー時のトラブルシューティングにも挑戦してみてください。

これを機にPythonでのデータベース操作をマスターしましょう!