Pythonでデータ処理した後にMySQLなどのデータベースに保存する操作の話題です。
Pythonにまだ慣れていないという人でも、Pandasなどで処理したデータをデータベースとやり取りする経験はあるのではないでしょうか。
今回の記事では、Pandasのデータ(DataFrameやSeries)にNaN
やNone
が含まれているときにMySQLからエラーが返ってきたときの対処法をまとめています。
検証環境
Python 3.9
Pandas 1.2.3
SQLAlchemy 1.4.5
PyMySQL 1.0.2
nan can not be used with MySQLエラーに対処する
このようなエラーが出ましたか?
sqlalchemy.exc.ProgrammingError: (pymysql.err.ProgrammingError) nan can not be used with MySQL
これは、NaNを含むデータをMySQLにUPDATEまたはINSERTしようとしたときに発生します。
エラーを再現してみます。
まずは適当なデータ(カンマ区切りのテキストファイル形式)を用意し、読み込ませます。
csv = ("tag,name\n"
+ "A,Alpha\n"
+ "B,Bravo\n"
+ "C,\n"
+ "D,Delta\n")
stream = io.StringIO(csv)
df = pd.read_csv(stream)
1行目はヘッダーとして扱います。
今回、4行目(tag='C')のname列を空欄としました。
pandas.read_csv で読み込むと、空欄(空文字)のところは自動でNaN
(np.nan)になります。
print
して見てみます。
print(df)
# tag name
# 0 A Alpha
# 1 B Bravo
# 2 C NaN # 空欄の部分はNaNに
# 3 D Delta
次に、このdf をそのままSQLAlchemyのORMでadd
しようとすると…
for _, d in df.iterrows():
tag = TagName(tag=d['tag'], name=d['name'])
session.add(tag)
session.commit()
こんな感じのエラーとなります。
sqlalchemy.exc.ProgrammingError: (pymysql.err.ProgrammingError) nan can not be used with MySQL
[SQL: INSERT INTO tag_names (tag, name) VALUES (%(tag)s, %(name)s)]
[parameters: {'tag': 'C', 'name': nan}]
(Background on this error at: http://sqlalche.me/e/14/f405)
nan
は MySQLでは扱えないよ!と怒られてしまいました。
そのままだと保存できないので、None
などに変換してあげましょう。
import numpy as np
df = df.replace({np.nan: None})
これで、もう一度 add
/ commit
を実行してみると正常に挿入が完了します。
MySQL側をみれば、空欄だったところがnull
で保存されているはずです。
Pythonのスキルを使って毎月の収入源を増やすのが最適なんじゃないかという件
実際、今のスキルに合わせて仕事を獲得し、スキマ時間で毎月+5、+20、+70万円くらいの人が多いです。
必要なスキル、仕事の獲得までの流れは以下の記事で徹底解説しています。
(もちろん全部無料です)
空いた時間にぜひ参考にしてみてください。
pandasa.to_sql()でNaNをnullとしてINSERT
ちなみに別の方法もあります。
SQLAlchemy ORMではなくCoreでinsertすればnanのままでも更新操作ができます。
engine = get_engine()
df.to_sql(
'tag_names', # テーブル名
con=engine,
schema='playground',
if_exists='append',
index=False
)
DataFrameの中身をデータベースに書き込む pandas.to_sql()
メソッドを使っています。
この場合も、nan
だった部分がMySQLにはnullとして保存されます。
雑記
ちなみにPythonの世界ではNone
、NaN
はそれぞれ違うものです。
これらの違いはこちらのまとめを参考にしてみてください。