DB Python

cx_oracle - Oracle で ora-01861 でハマる

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 となっており、YYYYMMDDYYYY-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すればエラーを回避できる



ITipsと同じようなブログを作る方法

ブログに興味がありますか?

もしブログに興味がある場合は↓このページ↓を参考にすれば、ITipsと同じ構成でブログを作ることができます

サーバー、ドメイン、ASPと【ブログに必要なものは全て】このページに書きました。
同じ構成でブログ作るのはいいけど、記事はマネしないでネ (TДT;)

ランキング参加中

にほんブログ村 IT技術ブログへ

他にもブログやSNSで紹介してくれると励みになります。

はてブのコメントで酷評されると泣きます(´;ω;`)

-DB, Python
-,

© 2022 ITips