Pythonで cx_oracle
ライブラリを使ってOracleデータベースにデータをinsertする際に
cx_Oracle.DatabaseError: ORA-01861 : literal does not match format string
のエラーが発生することがある。
特にOracle Cloudを初めて利用する際に発生するので、今回はこの ORA-01861
エラーの原因と対策について紹介する。
エラー原因
エラー内容を見ると、 ORA-
で始まっているので、PythonではなくOracleで発生していることがわかる。
また literal does not match format string
を訳すと「リテラルが書式文字列と一致しません」となるので何らかの書式が間違っていることが推測できる。
では何の書式がエラーになっているかというと、日付だ。
insertしようとしている日付の書式がOracle側と合っていないために ORA-01861
エラーが発生している。
書式も色々存在する。
書式 | 例 |
---|---|
YYYYMMDD |
20200113 |
YYYY年MM月DD日 |
2020年01月13日 |
DD-MM-YYYY |
13-01-2020 |
DD-MON-RR |
13-Jan-20 |
環境を確認するにはOracle上で以下のSQLを実行する。
するとNLS_DATE_FORMATの値がDD‐MON-RRと表示される。
select * from v$nls_parameters;
実はOracleの標準の日付書式が DD‐MON-RR
となっており、YYYYMMDD
や YYYY-MM-DD
形式で日付を入れようとするとエラーになってしまうのだ。
Oracle Databaseのデフォルトの標準日付書式はDD‐MON-RRです。
「JanとかFebとか普段使わないのでどうしたらいいのか」
と思うかも知れないが、対策は存在する。
対策
実は日付書式を気にしなくてもデータをinsertできる方法がある。
それはDateTime型を使うことだ。
実はPythonからOracleに接続するためのライブラリ cx_oracle
には、Pythonのdatetime型とOracleのdatetime型を暗黙的に変換する機能があり、datetime型をそのままinsertできる。
PyMySQL
の場合はdatetime型のままだとMySQLと型の不整合が起こるので、以下のように文字列に変換してから挿入していた。
now = datetime.datetime.now() now_str = now.strftime('%Y-%m-%d %H:%M:%S')
しかしcx_oracle
ではinsertするレコードの1カラムがdatetime型でも文字列に変換する必要がない。
now = datetime.datetime.now()
日付を文字列ではなくdatetime型のままinsertすることで ORA-01861
のエラーを回避できる。
cx_Oracleはクラス datetime.datetime のオブジェクトの受け渡しをサポートしています。
まとめ
ora-01861
の原因は日付書式が間違っているから- cx_oracleを使うならdatetime型を文字列変換せずにそのままinsertすればエラーを回避できる