必要な機能を考える
Pythonのsqlite3を使えば手軽にDBを作成できますが、PythonからDBの内容を確認するためは、接続、カーソル取得、SELECT文投入、結果確認という手順を踏まねばならず、やや手間に感じます。
SQLiteのコマンドラインを使用して直接ファイルを開けば、ドットコマンドというSQLite特有の便利な機能が使えますが、Pythonとは別にSQLiteをインストールしなければなりません。
なんとかPythonだけで簡単にDBファイルを確認できるようにするため、tkinterを使ってGUIのDB確認ソフトを作成することにしました。必要な機能は以下の通りです。
- DBファイル(*.db)を指定するとテーブル一覧が表示される
- テーブルを選択すると、テーブル情報を表示する
- 最新5件を表示する簡易ボタンをつける
- SELECT文を書いて実行するボタンをつける
目次
完成品のスクリーンショット
テストDBに投入したデータはテストデータ・ジェネレータを利用させていただきました。
起動して「開く」ボタンでファイルを選択するとテーブル一覧を表示。
リストからテーブルを選択して「選択」ボタンを押すとテーブル定義が表示される。
「最新5件」でデータを表示。
SELECT文を投入(テストデータは合計500件投入)。
スクリプトソース
およそ100行です。SELECT文のたびにDBに接続、切断していたり、改善すべきところはかなりあると思いますが、個人で使う分にはこのくらいで十分なので、多少の不具合は目をつぶっています。
入力されたSQL文はノーチェックで通しているので、あくまでDBファイル確認用の個人ツールという扱いです。
# -*- coding: utf-8 -*-
import tkinter as tk
import tkinter.filedialog as filedialog
import sqlite3
class App(tk.Frame):
def __init__(self, master = None):
tk.Frame.__init__(self, master)
self.pack()
# ラベル
self.lbl1 = tk.Label(self, text='対象DB')
self.lbl1.grid(row=0, column=0)
self.lbl2 = tk.Label(self, text='テーブルリスト')
self.lbl2.grid(row=1, column=0)
self.lbl3 = tk.Label(self, text='対象テーブル')
self.lbl3.grid(row=2, column=0)
self.lbl4 = tk.Label(self, text='SELECT文')
self.lbl4.grid(row=3, column=0)
# ファイル選択用ボタンと選択されたファイル名表示エントリー
self.btn1 = tk.Button(self, text='開く', command = self.btn_open_file)
self.btn1.grid(row=0, column=2)
self.ent1 = tk.Entry(self, width=50)
self.ent1.grid(row=0, column=1)
# テーブル名表示用リストボックスとテーブル選択ボタン
self.lstb = tk.Listbox(self, height=7, width=50)
self.lstb.grid(row=1, column=1)
self.btn2 = tk.Button(self, text='選択', command = self.btn_select_tbl)
self.btn2.grid(row=1, column=2)
# 選択テーブル表示エントリーとselect文投入用エントリー
self.ent2 = tk.Entry(self, width=50)
self.ent2.grid(row=2, column=1)
self.ent3 = tk.Entry(self, width=50)
self.ent3.grid(row=3, column=1)
# select文実行、最新10件ボタンと結果表示用テキストエリア
self.btn3 = tk.Button(self, text='実行', command = self.btn_select_exe)
self.btn3.grid(row=3, column=2)
self.btn3 = tk.Button(self, text='最新5件', command = self.btn_latest5)
self.btn3.grid(row=3, column=3)
self.text = tk.Text(self)
self.text.grid(row=4, column=0, columnspan=4)
def btn_open_file(self):
# .dbファイル選択
f_name = filedialog.askopenfilename()
if f_name[-3:] != '.db':
print('.dbファイルを選んでください。')
else:
# 既存エントリーを削除して選択したファイル名を表示
self.ent1.delete(0, 50)
self.ent1.insert(0, f_name)
# dbファイル内のテーブルを取得してリストボックスに表示
con = sqlite3.connect(f_name)
cur = con.cursor()
cur.execute("SELECT tbl_name FROM sqlite_master \
WHERE type = 'table'")
result = cur.fetchall()
con.close()
self.lstb.delete(0, self.lstb.size()) # リストボックスをカラにする
for tbl_name in result:
self.lstb.insert(0, list(tbl_name))
# テーブル選択
def btn_select_tbl(self):
# 既存エントリー削除
self.ent2.delete(0, 50) # 50文字を超えるテーブル名は削除されない
self.text.delete('1.0', '100.100') # 同上
# テーブル名選択、表示
tbl_selected = self.lstb.get(self.lstb.curselection())
self.ent2.insert(0, tbl_selected)
# テーブル定義表示
con = sqlite3.connect(self.ent1.get())
cur = con.cursor()
cur.execute("SELECT sql FROM sqlite_master \
WHERE type = 'table' AND tbl_name = (?)", tbl_selected)
result = str(cur.fetchall()[0]) # cur.fetchallの返り値はタプルのリスト
self.text.insert('1.0', result.replace(',', ',\n'))
con.close()
# 既存エントリーを削除して、select文の候補表示
self.ent3.delete(0, 50)
select = 'SELECT * FROM ' + tbl_selected[0]
self.ent3.insert(0, select)
# select文実行
def btn_select_exe(self):
con = sqlite3.connect(self.ent1.get())
cur = con.cursor()
cur.execute(self.ent3.get())
result = cur.fetchall()
result_text = str(len(result)) + '個selectされました.\n'
self.text.delete('1.0', '100.100')
self.text.insert('1.0', result_text)
i=1
for line in result:
num = str(i+1) + '.0'
line = str(i)+' : '+str(line).replace("('", "").replace("',)", "\n")
self.text.insert(num, line)
i += 1
con.close()
# 最新5件表示
def btn_latest5(self):
tbl_selected = self.lstb.get(self.lstb.curselection())
con = sqlite3.connect(self.ent1.get())
cur = con.cursor()
select = 'select * from ' + tbl_selected[0] + ' order by ROWID desc limit 5'
cur.execute(select)
result = cur.fetchall()
# 既存を削除して結果表示
self.text.delete('1.0', '100.100')
for line in result:
line = str(line) + '\n\n'
self.text.insert('1.0', line)
con.close()
app = App()
app.mainloop()