pagetakaBlog

最近リフォームと鳥取県日南町の記事多め。写真、PC、ネット等の話題も

MySQL:fetchall()は一回消費、保持するなら変数代入。

この記事は、MySQLからデータ取得後の使いまわしのコトです。おもにfetchallが一回使うと消えるコト関係です。

MySQL:fetchall()でひとつの項目データは取得できる…。

PythonでMySQLからデータ取得する際、二つの項目を得る必要がありました。

項目ひとつはデータ取得問題なし。

ひとつの項目を取得するのは問題ありません。例えば、次のような例です。

# 部分なので、動きません。
        with con.cursor() as cur:
            sql = """ SELECT mh-mo FROM `market` WHERE cd = '1332' """
            cur.execute(sql)
            difs_ho = [d.get("mh-mo") for d in cur.fetchall()]
            print(difs_ho)
爺の失敗例:項目ふたつの場合

要素が二つになると、どう書けばよいのか…。爺の横着は、次の通りで成功せず。

# 部分なので、動きません。
# エラーになります
        with con.cursor() as cur:
            sql = """ SELECT mh-mo, mc-mo FROM `market` WHERE cd = '1332' """
            cur.execute(sql)
            difs_ho, difs_co = [d.get("mh-mo"), d.get("mc-mo")  for d in cur.fetchall()]
            print(difs_ho)
            print(difs_co)

次は期待通りの結果になりませんでした。

# 部分なので、動きません。
# 最終行の結果が空
        with con.cursor() as cur:
            sql = """ SELECT mh-mo, mc-mo FROM `market` WHERE cd = '1332' """
            cur.execute(sql)
            difs_ho = [d.get("mh-mo") for d in cur.fetchall()]
            difs_co = [d.get("mc-mo") for d in cur.fetchall()]
            print(difs_ho)
            print(difs_co)

最後行「print(difs_co)」が期待通りにならず、空でした。

Microsoft:Copilotによるとfetchall()は一回使うと消える…。

こういう時頼りになるのが Microsoft:Copilot です。最後行のprint結果が空になるのは、fetchall()一回使用で消費される(≒消える)、との旨の回答でした。
流れに合わせて考えると、

  1. difs_ho ← fetchall()結果
  2. fetchall = 一回使ったので中身消える
  3. difs_co ← すでに空になったfetchall()結果
  4. print(difs_ho):中身があるので期待した結果表示
  5. print(difs_co):中身が無いのを表示する=爺的には期待外

なので、fetchall()の結果を変数に収めるのがヨロシイ、との旨を教えてくれました。

fetchall()を変数代入し、複数回使用。

言われてみればその通りのことです。次のようにスクリプトを直せば、期待通りの結果になります。

# 部分なので、動きません。
# fetchallを変数代入
        with con.cursor() as cur:
            sql = """ SELECT mh-mo, mc-mo FROM `market` WHERE cd = '1332' """
            cur.execute(sql)
            results = cur.fetchall()
            difs_ho = [d.get("mh-mo") for d in results]
            difs_co = [d.get("mc-mo")  for d in results]
            print(difs_ho)
            print(difs_co)

zipとアンパック「*」だと、一回のforで複数項目取得+爺の横着。

項目の回数だけfor文回せば、目的のデータを取得できるのは、わかりました。「しかしなあ~」と爺がもの思いにふけっている(≒ただボンヤリしてるだけ)と、Copilotが「zip」とアンパック「*」を使えば、一回のfor文で複数項目データそれぞれに取得できるよ~との旨、教えてくれました。
教えてもらったスクリプトに、爺の横着を加えたのが次のようなものです。

# 部分なので動きません
# for文一回なので、fetchall() をそのまま使用
with con.cursor() as cur:
    sql = """ SELECT mh-mo, mc-mo FROM `market` WHERE cd = '1332' """
    cur.execute(sql)
    difs_ho, difs_co = zip(*[(d["mh-mo"], d["mc-mo"]) for d in cur.fetchall()])
    print(f'\n{cd}:{difs_ho}\n{difs_co}')

※ cd = '1332' を %s など変数を使い使い回しできます。

これで、一回のfor文で複数要素のデータを変数に代入できました。今回、変数はタプル(tuple)になっています。
ひとつの項目の時には d.get("mh-mo") という書き方でしたが、zipを使った際には d["mh-mo"] と変化していました。何故だか爺にはわかりませぬ…。どなたか教えてください。

爺の美貌録、いや、備忘録です。齟齬などありましたら教えてくださいませ。優し目に…よろしくおねがいします。