読者です 読者をやめる 読者になる 読者になる

Oracleのシーケンスを扱う

Python SQLAlchemy

 OracleでSQLAlchemyを使う場合は、シーケンスの扱いに注意が必要です。AUTO_INCREMENTやSERIALといった自動採番機能がある他のデータベースとは異なり、明示的に使用するシーケンス名を指定する必要があります。


 SQLAlchemyのOracleバックエンドの動作を確認するために、次のような単純な表を定義しました。ID列の主キーを取得するために、cat_id_seqというシーケンスも事前に定義してあります。

SQL> desc cat;
 Name          Null?    Type
 ------------- -------- ----------------------------
 ID            NOT NULL NUMBER
 NAME          NOT NULL VARCHAR2(100)


 autoload=Trueを使って、データベースから自動的にTableオブジェクトを生成する場合は、次のように、明示的に主キー列を定義して、自動的に生成されるColumnオブジェクトを上書きします。

# -*- coding: utf-8 -*-
from sqlalchemy import *

# 自動ユニコード変換を有効にして、エンジン(DB接続)を作る
engine = create_engine('oracle://scott:tiger@tns', convert_unicode=True)

metadata = BoundMetaData(engine)

cats = Table('CAT', metadata,
             Column('id', Integer, Sequence('cat_id_seq'), primary_key=True),
             autoload=True)


 上の例では、主キー列IDがシーケンスを使う必要があるので、この列だけ、Columnで明示的に指定しています。autoload=Trueも指定しているので、それ以外の列はデータベースから動的に定義を取得することになります。


 Oracle, SQLAlchemyの組み合わせを使う場合、次の点に注意が必要です。

  1. Oracleバックエンド(cx_Oracle)はユニコード文字列を自動的にエンコードしてくれません。従って、SQLAlchemyのユニコード自動変換機能を使う(create_engineでconvert_unicode=Trueを指定する)か、自分でユニコード文字列をエンコードする必要があります。
  2. autoload=Trueでテーブルを取得する場合、テーブル名は大文字で指定する必要があります。


 上記の点に注意すれば、あとは他のバックエンドと同じようにTableオブジェクトを扱えます。

# 行を挿入
cats.insert().execute(name=u"イッパイアッテナ")

# 選択
cats.select(cats.c.name==u"ルドルフ").execute().fetchone()