SQLite 資料庫 -3
將 student 與 department 透過 系碼 欄位建立關聯(外鍵),形成一個完整的 關聯式資料庫 (Relational Database),並在 Tkinter 介面中一次「顯示學生 + 系所資料」。
設計目標
資料庫:MySchoolDB.db
關聯: student.系碼 → 對應 department.系碼
顯示欄位如下:
| 學號 | 姓名 | 系碼 | 系名 | 系主任 |
Python + Tkinter 程式
import tkinter as tk
from tkinter import ttk, messagebox
import sqlite3
import os
DB_NAME = "MySchoolDB.db"
# === 建立資料庫與資料表 ===
def create_db():
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
# 建立 department 資料表
cursor.execute('''
CREATE TABLE IF NOT EXISTS department (
系碼 CHAR(10) PRIMARY KEY,
系名 VARCHAR(50),
系主任 VARCHAR(50)
)
''')
# 建立 student 資料表,外鍵對應 department
cursor.execute('''
CREATE TABLE IF NOT EXISTS student (
學號 CHAR(10) PRIMARY KEY,
姓名 VARCHAR(50) NOT NULL,
系碼 CHAR(10) NOT NULL,
FOREIGN KEY(系碼) REFERENCES department(系碼)
)
''')
conn.commit()
conn.close()
messagebox.showinfo("訊息", f"{DB_NAME} 中的 student 與 department 資料表已建立!")
# === 新增 department 資料 ===
def add_department():
if not os.path.exists(DB_NAME):
messagebox.showwarning("警告", "請先建立資料庫!")
return
dept_id = entry_dept_id.get().strip()
dept_name = entry_dept_name.get().strip()
dept_head = entry_dept_head.get().strip()
if dept_id == "":
messagebox.showwarning("警告", "系碼不可為空!")
return
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
try:
cursor.execute("INSERT INTO department VALUES (?, ?, ?)", (dept_id, dept_name, dept_head))
conn.commit()
messagebox.showinfo("成功", "科系資料已新增!")
show_all()
except sqlite3.IntegrityError:
messagebox.showerror("錯誤", "該系碼已存在!")
conn.close()
# === 新增 student 資料 ===
def add_student():
if not os.path.exists(DB_NAME):
messagebox.showwarning("警告", "請先建立資料庫!")
return
sid = entry_sid.get().strip()
sname = entry_sname.get().strip()
dept_id = entry_sdept.get().strip()
if sid == "" or sname == "" or dept_id == "":
messagebox.showwarning("警告", "請完整輸入學生資料!")
return
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
# 檢查系碼是否存在於 department
cursor.execute("SELECT 系碼 FROM department WHERE 系碼=?", (dept_id,))
result = cursor.fetchone()
if not result:
messagebox.showerror("錯誤", f"系碼 {dept_id} 不存在於 department!")
conn.close()
return
try:
cursor.execute("INSERT INTO student VALUES (?, ?, ?)", (sid, sname, dept_id))
conn.commit()
messagebox.showinfo("成功", "學生資料已新增!")
show_all()
except sqlite3.IntegrityError:
messagebox.showerror("錯誤", "該學號已存在!")
conn.close()
# === 顯示 JOIN 結果 ===
def show_all():
if not os.path.exists(DB_NAME):
messagebox.showwarning("警告", "請先建立資料庫!")
return
for row in tree.get_children():
tree.delete(row)
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
# 使用 JOIN 顯示學生 + 系所資料
cursor.execute('''
SELECT s.學號, s.姓名, s.系碼, d.系名, d.系主任
FROM student s
LEFT JOIN department d ON s.系碼 = d.系碼
''')
rows = cursor.fetchall()
for row in rows:
tree.insert("", "end", values=row)
conn.close()
# === 刪除資料庫 ===
def delete_db():
if os.path.exists(DB_NAME):
os.remove(DB_NAME)
for row in tree.get_children():
tree.delete(row)
messagebox.showinfo("成功", f"{DB_NAME} 已刪除!")
else:
messagebox.showwarning("警告", "資料庫不存在!")
# === Tkinter 介面 ===
root = tk.Tk()
root.title("MySchoolDB 關聯式資料庫系統")
root.geometry("900x600")
# === Department 區 ===
frame_dept = tk.LabelFrame(root, text="科系資料 (department)")
frame_dept.pack(pady=5, fill="x", padx=10)
tk.Label(frame_dept, text="系碼:").grid(row=0, column=0, padx=5, pady=3)
entry_dept_id = tk.Entry(frame_dept, width=10)
entry_dept_id.grid(row=0, column=1)
tk.Label(frame_dept, text="系名:").grid(row=0, column=2, padx=5, pady=3)
entry_dept_name = tk.Entry(frame_dept, width=20)
entry_dept_name.grid(row=0, column=3)
tk.Label(frame_dept, text="系主任:").grid(row=0, column=4, padx=5, pady=3)
entry_dept_head = tk.Entry(frame_dept, width=20)
entry_dept_head.grid(row=0, column=5)
ttk.Button(frame_dept, text="新增科系", command=add_department).grid(row=0, column=6, padx=10)
# === Student 區 ===
frame_stu = tk.LabelFrame(root, text="學生資料 (student)")
frame_stu.pack(pady=5, fill="x", padx=10)
tk.Label(frame_stu, text="學號:").grid(row=0, column=0, padx=5, pady=3)
entry_sid = tk.Entry(frame_stu, width=10)
entry_sid.grid(row=0, column=1)
tk.Label(frame_stu, text="姓名:").grid(row=0, column=2, padx=5, pady=3)
entry_sname = tk.Entry(frame_stu, width=20)
entry_sname.grid(row=0, column=3)
tk.Label(frame_stu, text="系碼:").grid(row=0, column=4, padx=5, pady=3)
entry_sdept = tk.Entry(frame_stu, width=10)
entry_sdept.grid(row=0, column=5)
ttk.Button(frame_stu, text="新增學生", command=add_student).grid(row=0, column=6, padx=10)
# === 功能按鈕 ===
frame_btn = tk.Frame(root)
frame_btn.pack(pady=5)
ttk.Button(frame_btn, text="建立資料庫", command=create_db).grid(row=0, column=0, padx=5)
ttk.Button(frame_btn, text="顯示所有資料 (JOIN)", command=show_all).grid(row=0, column=1, padx=5)
ttk.Button(frame_btn, text="刪除資料庫", command=delete_db).grid(row=0, column=2, padx=5)
# === Treeview 顯示區 ===
columns = ("學號", "姓名", "系碼", "系名", "系主任")
tree = ttk.Treeview(root, columns=columns, show="headings", height=15)
for col in columns:
tree.heading(col, text=col)
tree.column(col, width=130)
tree.pack(pady=10, fill="x")
root.mainloop()


沒有留言:
張貼留言