CentOS7にてPythonからODBC経由でOracleにアクセス

## 概要

* cx_Oracleによるアクセス手順はちらほらあったのですが、ODBC経由がありそうでなかったので、手順をまとめました

### UNIX-ODBCをインストール

```shell
yum install -y unixODBC
```

### Oracle-Instant-Clientのインストール

* [OTN](http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html)からダウンロードし、インストールします
* モジュールは、```/usr/lib/oracle/12.2/client64``` 配下にインストールされるようです

```shell
yum localinstall -y \
  oracle-instantclient12.2-basic-12.2.0.1.0-1.x86_64.rpm \
  oracle-instantclient12.2-devel-12.2.0.1.0-1.x86_64.rpm \
  oracle-instantclient12.2-odbc-12.2.0.1.0-2.x86_64.rpm
```

### 環境変数の設定(.bash_profile/.bashrc)

```bash:.bash_profile
# 以下を追加します
export ORACLE_HOME=/usr/lib/oracle/12.2/client64
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH
export PATH=$ORACLE_HOME/bin:$PATH
```

### ODBCドライバの追加

* Oracle-Instant-Clientは、ODBCドライバファイルがインストール先フォルダに配置されるだけなので、ドライバ情報(ドライバ名とドライバファイルへのパス)をODBCに登録します
* ドライバ情報を記述したファイルを作成し、*odbcinst*コマンドでドライバー情報を登録します
* ODBCドライバは、$ORACLE_HOME/lib/libsqora.so.*というファイルのようです

```ini:/path/to/oracle_driver.ini
[odbcOracle12c]
Description = Oracle 12c Odbc Driver
Driver = /usr/lib/oracle/12.2/client64/lib/libsqora.so.12.1
```

* odbcinstコマンドでODBCドライバを登録します

```shell-session
$ odbcinst -i -d -f /path/to/oracle_driver.ini 
odbcinst: Driver installed. Usage count increased to 1. 
```

### 接続情報(DSN)の登録(任意)

* データベースへの接続情報を任意のファイルに作成します
 * 下記の例では、データソース名(DSN)を*DSN_ORACLE*としています
 * ドライバには先ほど登録したドライバ名(odbcOracle12c)を指定します
 
```ini:/path/to/mydsn.ini
[DSN_ORACLE]
Driver = odbcOracle12c
ServerName = 127.0.0.1:1521/DB名
UserID = USERNAME
Password = PASSWORD
```

* odbcinstにて、データソースを追加します
 * ~/.odbc.iniに直接記述するという方法もあるみたいですが、あえて*odbcinst*コマンドを利用する手順にしています 

```shell-session
# 登録
$ odbcinst -i -s -f /path/to/mydsn.ini
# 登録の確認
$ cat ~/.odbc.ini
```

* isqlを利用して、接続確認を行います
* *Connected!*が表示されれば、接続成功です

```shell-session
$ isql DSN_ORACLE
+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> 
```


### Pythonコードで確認(DSN指定なし)

* DSNを使わず、接続に必要な情報を記述して、データベースに接続する方法です
* 接続文字列の詳細は[こちら](https://docs.oracle.com/cd/E16338_01/server.112/b56317/app_odbc.htm#i1093897)

```python
import pyodbc
# ドライバ名
drv = "odbcOracle12c"
# 接続先DB
dbq = "127.0.0.1:1521/DB名"
# ユーザー名
usr = "USER_NAME"
# パスワード
pwd = "PASSWORD"
# SQL
sql = "select 1 from dual"
# 接続文字列 
conn_str = "DRIVER=%s;DBQ=%s;UID=%s;PWD=%s" % (drv,dbq,usr,psw)
# DBに接続
conn = pyodbc.connect(conn_str)

# カーソル取得
with conn.cursor() as cur:
    cur.execute(sql)
    for row in cur.fetchall():
        print(row)
# DBクローズ
conn.close()
```

### Pythonコードで確認(DSN指定あり)

* DSNを登録したなら、接続時はDSNを指定するだけです

```python
import pyodbc
conn = pyodbc.connect("DSN=DSN_ORACLE")
```

* ユーザー/パスワードを追加で指定

```python
import pyodbc
conn = pyodbc.connect("DSN=DSN_ORACLE;UID=USERNAME2;PWD=PASSWORD2")
```

### Pandasで読み込み

* Pandasによる表データの読み出し方法です
* pandas.read_sqlを利用すると、データベース内のデータを抽出することができます

```python
# pandasをインポート
import pandas as pd

# データフレームを取得(sqlとコネクションオブジェクトを渡す)
df = pd.read_sql(sql,conn)

# CSVファイルへの書き出し
df.to_csv("/path/to/csv",index=False)
```