[Python] 275 MySQLでIF EXISTSが機能しない

MySQLでテーブルを一旦削除してから新たに作成する操作をする際、テーブルが存在しなくてもエラーにならないようSQL文に”IF EXISTS”を付けたのですが機能しません。

SQL文作成はf文字列でもformatメソッドでもNGでした。

仕方がないので、エラーを無視してtry-except-finallyでテーブルを作成するようにしました。

原因は不明ですが、mysql.connectorモジュールがおかしいのでしょうか。

import csv,mysql.connector,glob
import pandas as pd

<中略>

# sqlのリストを作成
sql_l = list()
for table in table_l:
    sql = f"DROP TABLE IF EXISTS horse_race_name.{table}"
    sql_l.append(sql)

sql_l2 = list()
for table in table_l:
    sql = f"CREATE TABLE horse_race_name.{table} {column_l_str}"
    sql_l2.append(sql)

# mysqlに接続
conn = mysql.connector.connect(**config)
cur = conn.cursor()

# データベースhorse_race_nameにtableを作成する
for file,table,sql,sql2 in zip(file_l,table_l,sql_l,sql_l2):
    try:
        cur.execute(sql)
    except Exception as e:
        print(e)
    finally:
        try:
            cur.execute(sql2)
        except Exception as e:
             print(e)
        else:
            cur.execute('BEGIN')

            # CSVファイルを読み込み、各行をtableに挿入する
            with open(file, 'rt', encoding='Shift-JIS') as f:
                reader = csv.reader(f)
                for i,row in enumerate(reader):
                    if i != 0:
                        row_str = str(row).replace('[','(').replace(']',')')
                        sql3 = f'INSERT INTO horse_race_name.{table} VALUES {row_str}'
                        cur.execute(sql3)

            cur.execute('COMMIT')

conn.close()

[Python] 274 CSVファイル完全一致検索の高速化検討

誕生年単位の馬名ファイルとCSVファイル内の馬名との完全一致検索を実行するコードです。[Python] 229にも似たようなコードを書いています。

実行時間が結構かかり、改善の余地ありです。C言語でモジュールを書いたらどれだけ早くなるか、試してみたいです。

import csv
import pandas as pd

<中略>

with open (file_new_pre, mode="r", encoding="shift_jis") as f3:
    with open (file_new, mode="a", encoding="shift_jis") as f4:
        writer = csv.writer(f4)

        for i,row in enumerate(csv.reader(f3)):
            if i != 0:
                if int(year) >=2001: # 満年齢
                    birthyear = int(year) - int(re.sub("\\D", "", row[4]))
                else: # 2000年以前は数え年
                    birthyear = int(year) - int(re.sub("\\D", "", row[4])) + 1

                # 誕生年馬名ファイル
                namefile = f'horse{birthyear}.csv'
                
                try:
                    df = pd.read_csv(namefile,encoding="shift_jis")
                except:
                    horseID = '198500000'
                else:
                    # 馬名ファイル各行の馬名とレースファイルの馬名が完全一致する場合にTrueとする配列を作成
                    b_array = df[df.columns[1]]==row[3]

                    # ブール値の配列として取り出しリスト化
                    b_array_v = b_array.values.tolist()

                    # Trueのインデックス値を取得
                    try:
                        i = b_array_v.index(True)
                    except: # 該当なし
                        horseID = '100000000'
                    else: # horseID取得
                        horseID = df.iloc[i,0]

                rows = row[0:22] + [horseID]
                writer.writerow(rows)

            else: # タイトル行(0行目)
                rows = row[0:22] + ['horseID']
                writer.writerow(rows)

[Python] 273 macOSのデスクトップ通知

処理に時間がかかる場合は、待っている間に他のことができるよう通知設定しています。

目立たせるため、関数にしました。

import os

# Macのデスクトップ通知
def notification():
    os.system("osascript -e 'display notification \"〇〇チェック\nコード実行終了\"'")

notification()

[Python] 272 辞書型データをCSVファイルに変換他

辞書型データからのvalue取得、キーの任意並べ替え(valueがない場合にも対応)、データフレームとの相互変換、CSVファイルへの変換が含まれたコードです。

import pandas as pd

<中略>

df = pd.read_csv(path,header=None,encoding='shift_jis')
df2 = df.drop_duplicates(subset=[0])

# データフレームを辞書型データに変換
dict = {str(x) : str(y) for x,y in zip(df2[0],df2[1])}

# 15項目の辞書型データを作成(valueがない場合はnanを入力)
dict2 = {'馬名':dict.get('馬名','nan'),'稼働':dict.get('稼働','nan'), '性別':dict.get('性別','nan'), '毛色':dict.get('毛色','nan'), '生年月日':dict.get('生年月日','nan'), '調教師':dict.get('調教師','nan'), '馬主':dict.get('馬主','nan'),'募集情報':dict.get('募集情報','nan'),'生産者':dict.get('生産者','nan'), '産地':dict.get('産地','nan'), 'セリ取引価格':dict.get('セリ取引価格','nan'), '獲得賞金':dict.get('獲得賞金','nan'), '通算成績':dict.get('通算成績','nan'), '主な勝鞍': dict.get('主な勝鞍','nan'), '近親馬':dict.get('近親馬','nan')}

# 辞書型データをデータフレームに変換
df3 = pd.json_normalize(dict2)

# df3の行と列を転置してCSVファイルを作成(T属性を使う)
with open(path,mode="w",encoding="cp932", errors="ignore") as f:
    df3.T.to_csv(f,header=False)

[Python] 270 CSVファイルの重複行削除

メモ書きしておきます。

for path in paths:
    df = pd.read_csv(path,header=None,encoding='shift_jis')

    # 列0の値が重複する場合に最初の行だけ残す
    df2 = df.drop_duplicates(subset=[0])

    with open(path,mode="w",encoding="cp932", errors="ignore") as f:
        df2.to_csv(f,index=False,header=False)

[Python] 269 欠番リスト作成(差集合)

リスト同士を比較して差分を演算するコードの一例です。

千番単位で連番リストを作り、比較したいリストとの差集合を演算します。

# 連番リスト作成
list_num = [[str(x).zfill(5) for x in range(1000*thou +1,1000*thou +1001)] for thou in range(0,11) ]

# 比較リスト作成
list_compare_pre = glob.glob('/*.csv')
list_compare = [path.split('.')[0][-5:] for path in list_compare_pre]

# 欠番リスト作成    
list_lack = list(set(list_num[0]) - set(list_compare))
list_lack.sort()

[Python] 268 ゼロ埋め数字のリストを作成する その2

前回の続きです。

for文ではなくリスト内包表記で書くと以下の通りになります。

リストを関数の戻り値にすることもできますが、普通に変数にする方が使い勝手は良さそうです。

# 00001から11000までの千番台ごとのリストを入れ子にしたリストを作成する関数
def list_num():
    return [[str(x).zfill(5) for x in range(1000*thou +1,1000*thou +1001)]\
for thou in range(0,11) ]

list_num_flat = [y for x in list_num() for y in x]

print(len(list_num_flat))
--------------------------------------------------

出力
--------------------------------------------------
11000

[Python] 267 ゼロ埋め数字のリストを作成する

00001から11000のゼロ埋め数字を1000個ずつまとめたリストの作成コードです。欠番検索の元データに使えます。

リスト内の1つ目のリストは00001から01000のゼロ埋め数字で構成されています。

list_all = list()
for thousand in range(0,11,1):
    list_thou = list()
    for num in range(1,1001,1):
        number = 1000*thousand + num
        # 数字を5桁のゼロ埋め数字に変換する
        number_5digits = str(number).zfill(5)
        list_thou.append(number_5digits)
    list_all.append(list_thou)

# リストを平滑化して入れ子をなくす
list_all_flat = [y for x in list_all for y in x]

print(len(list_all_flat))
--------------------------------------------------

出力
--------------------------------------------------
11000

[Python] 266 globによるパス一覧からの選別

久しぶりにPythonをいじりました。最近は融通の効かないJavaを使いこなすことにやりがいを感じていましたが、Pythonの自由さもいいものです。

globメソッドで得られたCSVファイルのパス一覧から、ファイル内容が条件に合致するパスのリストを作成しようとしたところ、エラーになってしまう問題にぶつかりました。さすがにそこまで柔軟ではないようです。

仕方ないのでパスをprint関数でtxtファイルに追記出力しました。

# 競走馬個別ファイル内の競走馬名が幼名("XXXの2018"など)になっているファイルのパスリストを作成
import glob,os,re,sys
import pandas as pd

print("検索する年度を入力してください")
year = input()

path = f'/horse/{year}'
print(os.listdir(path))

# 数字が含まれているディレクトリ名をリスト化する
pattern = r'\d'
list_dir = [p for p in os.listdir(path) if re.compile(pattern).search(p)]
print(list_dir)

for dir in list_dir:
    for path in glob.glob(f'/horse/{year}/{dir}/*.csv'):
        df = pd.read_csv(path,header = None,encoding='shift_jis')
        
        # B1セル相当の文字列に数字が含まれている場合、ファイルパスを追記出力する
        if re.compile(pattern).search(df.iat[0,1]):
            print(df.iat[0,1])
            with open('未登録馬path.txt', 'a') as f:
                print(path, file = f)
                # list.append(path)は不可なのでこのような処理になった