WindowsのPythonからOracleにcx_Oracleで繋ぐ

## PythonでDB接続

皆様Python使っていますか？
私も今年から業務で少し触り始めましたが、行列計算や、データ加工がとてもやりやすくて、簡単にかけるのが便利ですよね。
その中で、DB接続を使って、DBへのマスタ更新を自動化したく、OracleのDBに接続した際のやったことのメモ書きになります。

#### 前提
以下、当人環境です

・Windows10 Pro 64bit
・Python3.6
・Oracle Database 12.2c

#### cx_Oracleって？

[cx_Oralcle](https://cx-oracle.readthedocs.io/en/latest/index.html#)はPythonのDB接続APに基づいて実装され、OracleDBに簡単にアクセスするためのモジュールです。

導入要件は *Pythonが2.5 or 3.5以上、Oracle Client*が必要になります。
>
Python 2.7 or 3.5 and higher. Older versions of cx_Oracle may work with older versions of Python.
Oracle client libraries. These can be from the free Oracle Instant Client, or those included in Oracle Database if Python is on the same machine as the database. Oracle client libraries versions 18, 12, and 11.2 are supported on Linux, Windows and macOS. Users have also reported success with other platforms.
>

#### Oracle Instant Clientの導入

1. [Oracle Instant Client](https://www.oracle.com/technetwork/topics/winx64soft-089540.html)をダウンロード
※要Oracleアカウント

2. `C:\Oracle\`に解凍（解凍場所は自由ですが）


3. Oracle Instant Clientを環境変数PATHを通す（手順2で別の場所にした場合はそれに合わせる）
以下をPATHに追加すればいいです
`c:\Oracle\instantclient_18_3`

4. 以下フォルダを作成(tnsname.oraの保存場所になる)
`c:\Oracle\instantclient_18_3\network`
`c:\Oracle\instantclient_18_3\network\admin`

5. [Microsoft Visual C++ Redistributable for Visual Studio 2017.](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads#bookmark-vs2013)をダウンロードしてインストール
※VC2013以上でいいみたいですが

#### cx_Oracleの導入

- オンライン

コマンドプロンプトを起動して、以下を入力

```
python -m pip install cx_Oracle --upgrade
```

- オフライン（私はこっちでせざるを得なかった）

1. [cx_Oracle](https://pypi.org/project/cx-Oracle/)を入手して、Pythonインストールフォルダ配下のLibにコピーする。
例：`C:\Python\Lib`
2. Python配下のScriptフォルダでプロンプトを起動し、以下を入力

```
pip install --no-deps　.\\Lib\cx_Oracle-7.1.0-cp36-cp36m-win_amd64.whl
```

---

#### 使ってみる

テスト用のプログラムで接続テスト

```test.connect.py

#!/bin/python

import cx_Oracle

TARGET_HOST = "接続先のホスト名"
PORT = 'ポート番号'
SERVICE_NAME = "接続先のサービス名"
SCHEME_NAME = "スキーマ名"
USERNAME = "ユーザー"
PASSWORD = "パスワード"

def connect_test():
   print(cx_Oracle.clientversion()) # Oracleへ接続テストするならこれだけでも

def connect():
   tns = cx_Oracle.makedsn(TARGET_HOST, PORT, service_name = SERVICE_NAME) # tnsを設定
   connect = cx_Oracle.connect(USERNAME, PASSWORD, tns) # DBに接続
   cursor = connect.cursor() # カーソルを取得

   cursor.execute('''
   SELECT NAME, EMAIL  FROM EMPLOYER
   WHERE EMP_ID >= :arg1,
   AND NAME LIKE :arg2''',
   arg1=1,
   arg2="%Tanaka%") # クエリの実行(バインド変数を使っています）

   rows = cursor.fetchall() # カーソルからデータの取得

   for row in rows:
       print("%s : %s" %(row[0],row[1]))

if __name__ == '__main__':
    connect()

```

実行結果

```
Tanaka Kenta : k-tanaka@ab.sd.com
Tanaka Jiro : j-tanna@hoge.hoge.jp
```

#### バインド変数で困ったこと

テーブル名をバインドしたかったのですが、エラーを返されました

``` table_bind.py
cursor.execute (SELECT NAME, EMAIL  FROM :arg1
   arg1="EMPROYER")
```
・実行結果

```
ORA-00903：表名が無効です
```

OracleのSQL実行履歴を見ても、上記では、正しく実行されていなさそうでした。

そんな中、[この記事](https://stackoverflow.com/questions/13124572/binding-variable-to-table-name-with-cx-oracle)を拝見して、解決できました。

``` table_bind.py
cursor.execute('select * from {arg1}'.format(arg1="EMPROYER"))
```

## 終わりに
今回は、Pythonのcx_Oracleモジュールについて紹介しました。

#### 余談（バインドについて）

Railsのチュートリアルも5章まで進めました。
とてもわかり易いフレームワークだという感想です。