今までPythonからOracleデータベースにアクセスするライブラリとして、「cx_Oracle」を利用していました。
しかし、cx_Oracleは「python-oracledb」という名称になったようです。
cx_Oracle has a major new release under a new name and homepage python-oracledb.
引用: https://oracle.github.io/python-cx_Oracle/
本記事ではpython-oracledbをインストールしてOracleデータベースからデータを取得するところまでやってみようと思います。
勉強用のOracleデータベースの準備やcx_Oracleの情報をお探しの方は下記記事をご覧ください。
python-oracledbとは何か
PythonとオラクルDBを繋ぐためのモジュールでcx_Oracleが名称変更して生まれ変わったドライバーです。
The python-oracledb driver is a Python programming language extension module allowing Python programs to connect to Oracle Database. Python-oracledb is the new name for Oracle's popular cx_Oracle driver. 引用: https://python-oracledb.readthedocs.io/en/latest/user_guide/installation.html
cx_Oracleでは必要であったOracle Instant Clientをインストールしなくても、ThinモードでOracle 12c以降であればデータベースにアクセスすることが出来るようです。
Thin mode: By default, python-oracledb is a 'Thin' driver which connects directly to Oracle Database. This mode does not need Oracle Client libraries.引用: https://python-oracledb.readthedocs.io/en/latest/user_guide/installation.html
もしOracle11.2を使いたい場合やThinモードでサポートされていない機能を使いたい場合は、Oracle Instant ClientをインストールしてThickモードで利用した方が良さそうです。
例えばコネクション文字列で(ENABLE=BROKEN)はThinモードでは使えないといった制約があるようです。
The ENABLE=BROKEN connect descriptor option is not supported in python-oracledb Thin mode. Use expire_time instead.
引用: https://python-oracledb.readthedocs.io/en/latest/user_guide/appendix_b.html#connection-strings
私だったら本番環境で運用する場合はOracle Instant ClientをインストールしてThickモード、それ以外の勉強や開発時の確認などのみで使いたい場合はThinモードという風に使い分けると思います。(今はまだcx_Oracle使って本番運用してる)
その他にもcx_Oracleから変わった点として下記があるようです。
・パラメータのカプセル化が出来るようになった。
params = oracledb.ConnectParams(host="localhost", port=1521, service_name="XE")
conn = oracledb.connect(user="SYSTEM", password="hinomaruc", params=params)
・encoding、nencoding、threadedのパラメータが不要になった(deprecated and ignoredされました)
cx_Oracleとpython-oracledbの違いに関しては「Appendix C: The python-oracledb and cx_Oracle Drivers」に詳しく記載されています。
ちなみにcx_Oracleからpython-oracledbにアップデートする手順は「steps-to-upgrade-to-python-oracledb」に手順があります。
cx_Oracleからアップデートする場合だとOracle Instant Clientがインストールされていると思うので、python-oracledbはThickモードで利用するのが良さそうですね。
python-oracledbの利用準備
まずはOracle環境のセットアップからやります。
dockerでoracleデータベースXEを簡単に起動できますので、データベースの立ち上げからデータ挿入まで事前にやっておきます。
その次にpython-oracledbのインストールとThinモードでアクセスし挿入したデータを取得しpandasへ格納するところまで確認が出来たらと考えています。
dockerでoracleデータベースXEの準備
こちらの記事でOracleデータベースXEをインストールする3つの方法をまとめていますが、今回は簡単に構築できるOracle Cloud Infrastructure Container Registryを使います。
docker pull container-registry.oracle.com/database/express:21.3.0-xe
21.3.0-xe: Pulling from database/express 63183c9b4598: Pull complete fe297bb4960b: Pull complete 31dd4858f370: Pull complete 4f4fb700ef54: Pull complete b4584ceb9e7a: Pull complete Digest: sha256:016d1a2becd9c9b9bfb683eebf3aa092527fe1354ace5b23691e75759f301bed Status: Downloaded newer image for container-registry.oracle.com/database/express:21.3.0-xe container-registry.oracle.com/database/express:21.3.0-xe
docker run -it -d --name oracledb \
-p 1521:1521 -p 5500:5500 \
-e ORACLE_PWD=hinomaruc \
container-registry.oracle.com/database/express:21.3.0-xe
ORACLE_PWDでデータベースのパスワードを指定します。
docker logs -f --tail=100 oracledb
Starting Oracle Net Listener. Oracle Net Listener started. Starting Oracle Database instance XE. Oracle Database instance XE started. The Oracle base remains unchanged with value /opt/oracle SQL*Plus: Release 21.0.0.0.0 - Production on Thu Dec 1 12:05:07 2022 Version 21.3.0.0.0 Copyright (c) 1982, 2021, Oracle. All rights reserved. Connected to: Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production Version 21.3.0.0.0 SQL> User altered. SQL> User altered. SQL> Session altered. SQL> User altered. SQL> Disconnected from Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production Version 21.3.0.0.0 The Oracle base remains unchanged with value /opt/oracle ######################### DATABASE IS READY TO USE! ######################### The following output is now a tail of the alert.log: XEPDB1(3):Opening pdb with Resource Manager plan: DEFAULT_PLAN Pluggable database XEPDB1 opened read write ・・・省略・・・ Resize operation completed for file# 3, fname /opt/oracle/oradata/XE/sysaux01.dbf, old size 573440K, new size 593920K
少し時間はかかりますが、Oracleデータベースが使える状態になったようです。
# ユーザ名/パスワード@XE
docker exec -it oracledb sqlplus system/hinomaruc@XE
SQL*Plus: Release 21.0.0.0.0 - Production on Thu Dec 8 13:16:47 2022 Version 21.3.0.0.0 Copyright (c) 1982, 2021, Oracle. All rights reserved. Last Successful login time: Thu Dec 08 2022 13:15:53 +00:00 Connected to: Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production Version 21.3.0.0.0 SQL> select 1 from dual; 1 ---------- 1
無事sqlplusでデータベースに繋ぐことができました。
Oracleデータベースにテスト用のテーブルを作成しデータを挿入する
# 参考: https://stackoverflow.com/questions/34779894/executing-sql-scripts-on-docker-container
docker exec -it oracledb /bin/bash -c 'echo "select 1 from dual;" | sqlplus -S system/hinomaruc@XE'
1 ---------- 1
コンテナの中に入らなくてもホスト側である程度作業は出来るかも知れません。
しかし私はインタラクティブにクエリ発行したいので、コンテナ内に入ってからテーブル作成とデータ挿入をしてみます。
docker exec -it oracledb sqlplus system/hinomaruc@XE
SQL> CREATE TABLE SAMPLE_TABLE (FRUIT_NAME VARCHAR(255),PROD_ID INT);
SQL> INSERT INTO SAMPLE_TABLE (FRUIT_NAME, PROD_ID) VALUES ('apple', 0);
SQL> INSERT INTO SAMPLE_TABLE (FRUIT_NAME, PROD_ID) VALUES ('apple', 1);
SQL> INSERT INTO SAMPLE_TABLE (FRUIT_NAME, PROD_ID) VALUES ('orange', 2);
SQL> INSERT INTO SAMPLE_TABLE (FRUIT_NAME, PROD_ID) VALUES ('orange', 3);
SQL> INSERT INTO SAMPLE_TABLE (FRUIT_NAME, PROD_ID) VALUES ('banana', 4);
SQL> INSERT INTO SAMPLE_TABLE (FRUIT_NAME, PROD_ID) VALUES ('banana', 5);
SQL> INSERT INTO SAMPLE_TABLE (FRUIT_NAME, PROD_ID) VALUES ('peach', 6);
SQL> commit;
Table created. 1 row created. 1 row created. 1 row created. 1 row created. 1 row created. 1 row created. 1 row created. Commit complete.
docker exec -it oracledb /bin/bash -c 'echo -e "SET pagesize 0; \n select FRUIT_NAME,PROD_ID from SAMPLE_TABLE;" | sqlplus -S system/hinomaruc@XE'
apple 0 apple 1 orange 2 orange 3 banana 4 banana 5 peach 6
きちんとデータが登録されているようです。
python-oracledbのインストール
インストールする前の確認事項ですが、Pythonのバージョンに指定があります。
22年12月時点ですとLinuxのみPython3.6にも対応していましたが今はどのプラットフォームもPython 3.7以上に統一されたようです。
23年10月17日現在、下記Pythonのバージョンに対応しているようです。※ 利用前に引用元のリンクから最新の情報をご確認ください。
To use python-oracledb, you need:
Python 3.7, 3.8, 3.9, 3.10, 3.11 or 3.12
引用: https://python-oracledb.readthedocs.io/en/latest/user_guide/installation.html#installation-requirements
python3 -m pip install oracledb --upgrade
・・・省略・・・ clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -iwithsysroot/System/Library/Frameworks/System.framework/PrivateHeaders -iwithsysroot/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/Headers -arch arm64 -arch x86_64 -I/Users/hinomaruc/Desktop/blog/venv-oracle/include -I/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/Headers -c src/oracledb/base_impl.c -o build/temp.macosx-10.14.6-x86_64-cpython-38/src/oracledb/base_impl.o -mmacosx-version-min=10.9 src/oracledb/base_impl.c:6:10: fatal error: 'Python.h' file not found #include "Python.h" ^~~~~~~~~~ 1 error generated. /private/var/folders/n0/ft3172td6v70d6klgt216_3r0000gn/T/pip-build-env-b_f28qgr/overlay/lib/python3.8/site-packages/setuptools/config/expand.py:144: UserWarning: File '/private/var/folders/n0/ft3172td6v70d6klgt216_3r0000gn/T/pip-install-e387z73n/oracledb_7b6209e3673340219d47bc303da3c31c/README.md' cannot be found warnings.warn(f"File {path!r} cannot be found") error: command '/usr/bin/clang' failed with exit code 1 [end of output] note: This error originates from a subprocess, and is likely not a problem with pip. ERROR: Failed building wheel for oracledb Failed to build oracledb ERROR: Could not build wheels for oracledb, which is required to install pyproject.toml-based projects
エラーになってしまいました。Python.hが見つからないようです。
どうやらpython-develかそれに準ずるものが必要なようです。Linuxであればapt-get install python-develなどで解決しそうですが、Macの場合はbrewでインストールしたPythonを使うとPython.hが含まれているようです。
システムで最初からインストールされているPython3を使わず、brew install python@3.8などでインストールしたPythonを使おうと思います。
Compiling python-oracledb requires the Python.h header file. If you are using the default python package, this file is in the python-devel package or equivalent.
引用: https://python-oracledb.readthedocs.io/en/latest/user_guide/installation.html#install-python-oracledbIf you install Python using brew, the relevant headers are already installed for you.
引用: https://stackoverflow.com/questions/32578106/how-to-install-python-devel-in-mac-os
brew install python@3.8
# リンクを貼る
ln -s /usr/local/opt/python@3.8/bin/python3.8 /usr/local/bin/python3.8
# brewでインストールしたpython3.8で仮想環境を作成
python3.8 -m venv venv-oracle
source venv-oracle/bin/activate
python3 -m pip install --upgrade pip
# メインのjupyter環境からvenv-oracleのカーネルを参照できるようにする
python3 -m pip install ipykernel
python3 -m ipykernel install --user --name venv-oracle --display-name "venv-oracle"
python3 -m pip install oracledb --upgrade
Collecting oracledb ・・・省略・・・ Successfully built oracledb Installing collected packages: pycparser, cffi, cryptography, oracledb Successfully installed cffi-1.15.1 cryptography-38.0.4 oracledb-1.2.1 pycparser-2.21
今度は無事インストールが完了しました。
python-oracledbを使ってみる
「[Mac] Pythonからcx_OracleでOracleデータベースを操作してみる」の記事と同じようなコードでアクセス出来ました。
読み込むライブラリ名がcx_Oracleからoracledbに変更になるだけで、基本的に同じような仕組みでデータの取得とアウトプットが出来るようです。
データのフェッチと出力
# 参考:https://python-oracledb.readthedocs.io/en/latest/user_guide/connection_handling.html
import oracledb
#Thickモードで使いたい時はインスタントクライアントを読み込む
#oracledb.init_oracle_client(lib_dir=r"/Users/hinomaruc/Desktop/blog/instantclient_19_8")
connection = oracledb.connect(user="system", password="hinomaruc", dsn="localhost/XE")
cur = connection.cursor()
cur.execute("""SELECT TABLE_NAME FROM USER_TABLES""")
# 1行だけフェッチする
cur.fetchone()
('LOGMNR_SESSION_EVOLVE$',)
# 残り全行フェッチする
rows = cur.fetchall()
for r in rows:
print(r)
('LOGMNR_GLOBAL$',) ・・・省略・・・ ('SAMPLE_TABLE',)
きちんと取得出来ているようです。
# カーソルとコネクションをクローズする
cur.close()
connection.close()
python-oracledbを使ってpandasにデータを読み込む
こちらも「Oracleのデータをpandasに読み込んでみる」でcx_Oracleを使っている処理とあまり変わりないです。
python-oracledbのコネクションを作成しpandasに読み込む
import oracledb
import pandas as pd
connection = oracledb.connect(user="system", password="hinomaruc", dsn="localhost/XE")
query = """SELECT * FROM SAMPLE_TABLE"""
df = pd.read_sql(query, con=connection)
connection.close()
df
/var/folders/n0/ft3172td6v70d6klgt216_3r0000gn/T/ipykernel_1886/2190498718.py:6: UserWarning: pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite3 DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.df = pd.read_sql(query, con=connection)
FRUIT_NAME PROD_ID 0 apple 0 1 apple 1 2 orange 2 3 orange 3 4 banana 4 5 banana 5 6 peach 6
OracleDBのデータは取得出来ているようですが、warningがでてしまいました。pandas only supports SQLAlchemy connectable (engine/connection) ... connectionとありますので、SQLAlchemyのエンジンを作成して繋げてみようと思います。
22年12月現在、最新版であるsqlAlchemy1.4はcx_Oracleにしか対応していないようです。
python-oracledbをネィティブサポートしていない場合はpython-oracledbをcx_Oracleとして使う暫定処理があるようなので試してみます。
python-oracledb can be used in SQLAlchemy, Django, Pandas, and other frameworks and Object-relational Mappers (ORMs). Until they add native support, you can override the use of cx_Oracle with a few lines of code.
引用: https://python-oracledb.readthedocs.io/en/latest/user_guide/appendix_c.html#things-to-know-before-the-upgrade
SQLAlchemyのエンジンを作成しpandasに読み込む
import sys
import oracledb
import pandas as pd
# python-oracledbをcx_Oracleとして利用する暫定処理
oracledb.version = "8.3.0"
sys.modules["cx_Oracle"] = oracledb
import cx_Oracle
# importしているcx_Oracleが本当のcx_Oracleなのか、cx_Oracleとして使ってるoracledbなのか判別
if cx_Oracle.__name__ == 'cx_Oracle':
print('cx_Oracle')
else:
print('oracledb')
# https://docs.sqlalchemy.org/en/14/dialects/oracle.html
from sqlalchemy import create_engine
engine = create_engine("oracle+cx_oracle://SYSTEM:hinomaruc@localhost/XE",max_identifier_length=30)
query = """SELECT * FROM SAMPLE_TABLE"""
df = pd.read_sql(query, con=engine)
engine.close()
df
fruit_name prod_id 0 apple 0 1 apple 1 2 orange 2 3 orange 3 4 banana 4 5 banana 5 6 peach 6
今度はwarningが出ませんでした。
まとめ
oracleデータベースの構築からpython-oracledbを使ってpythonからオラクルのテーブルのデータを取得するところまで実施することが出来ました。python-oracledbのThinモードを利用することによって、Oracle Instant Clientなしで利用すること出来るので手順が簡単になったのかなと思います。
これからPythonとOracleデータベース間のやり取りをしたい方はpython-oracledbをインストールすることをおすすめします。
ライブラリのバージョン
import pandas as pd
import oracledb
import sqlalchemy
print("pandas",pd.__version__)
print("python-oracledb",oracledb.__version__)
print("SQLAlchemy",sqlalchemy.__version__)
pandas 1.5.2 python-oracledb 1.2.1 SQLAlchemy 1.4.45