Oracle 複数行INSERTのSQL は、
INSERT ALL
INTOテーブル名 [ ( column, ,,,) ] VALUES ( ・・・)
INTOテーブル名 [ ( column, ,,,) ] VALUES ( ・・・)
SELECT 1 FROM DUAL
で、INTOテーブル名 各行に付けなければならない不便さから解放されるために、
Excel で格納するデータ値を書いて、Python でSQLを生成する。
Excel の書き方の規則を定めておく。
・シート名にテーブル名
・1行目はカラム名
・2行目以降が値
・Excel ファイル、シートに対して ”シート名.sql” のSQLスクリプトを生成する。
Python 実行環境として、openpyxl をインストールしておく。
makeInsertSQL.py
# -*- coding: utf-8 -*- import datetime import openpyxl import sys import os from pathlib import Path class MakeInsertSQL(object): def __init__(self, file): self.book = openpyxl.load_workbook(file) def exec(self): for name in self.book.sheetnames: self.create(name) def create(self, sheetName): sqlfile = "%s/%s.sql" % (Path(__file__).parent.resolve(), sheetName) with open(sqlfile, 'w', encoding='utf-8') as f: f.write("INSERT ALL\n") sheet = self.book[sheetName] row = list(sheet.values) columns = ", ".join(row[0]) for r in row[1:]: vary = [] for cell in r: if type(cell) is str: vary.append("'%s'" % cell) elif type(cell) is int: vstr = "%d" % cell vary.append(vstr) elif type(cell) is datetime.datetime: vary.append("TO_TIMESTAMP('%s', 'YYYY-MM-DD HH24:MI:SS')" % cell.strftime('%Y-%m-%d %H:%M:%S')) elif cell is None: vary.append("NULL") v = ", ".join(vary) f.write("INTO %s (%s) VALUES(%s)\n" % (sheetName, columns, v)) f.write("SELECT 1 FROM DUAL\n") print("created : %s" % sqlfile) if __name__ == '__main__': args = sys.argv if len(args) == 2: if os.path.isfile(args[1]): maker = MakeInsertSQL(args[1]) maker.exec() else: print("Not Found %s" % args[1]) else: print("Usage: makeInsertSQL.py Excelfile")
openpyxl でシート名を指定して読込む時、
self.book.get_sheet_by_name(sheetName) を使うと
DeprecationWarning: Call to deprecated function get_sheet_by_name (Use wb[sheetname]).
と、警告が出るので、book[ sheetName ] で読み込む。
openpyxl は、ブック .values() が返すものはジェネレータであるので、list() で各行のリストにして
処理する。
日付も、日付時刻も、openpyxl は、datetime.datetime として読み取る。
文字列は、str 数値は、int で type が返ってくるのでそれで VALUES 文を組み立てる。
(実行例)
こういうExcel を用意して実行すると
T_USER.sql は、以下のとおり作成される。
INSERT ALL INTO T_USERS (UID, FIRST_NAME, LAST_NAME, AGE, UPDATE_TIME) VALUES(1, '太郎', '山田', 34, TO_TIMESTAMP('2023-05-01 12:23:47', 'YYYY-MM-DD HH24:MI:SS')) INTO T_USERS (UID, FIRST_NAME, LAST_NAME, AGE, UPDATE_TIME) VALUES(2, '次郎', '山田', 32, TO_TIMESTAMP('2023-05-01 09:28:09', 'YYYY-MM-DD HH24:MI:SS')) SELECT 1 FROM DUAL