Последняя активность 10 months ago

這段程式碼是一個使用 Streamlit 和 SQLite 的範例應用程式,透過 JOIN 查詢顯示客戶與訂單的關聯資料,並在介面中使用 st.data_editor 允許編輯訂單日期,按下更新按鈕後會將修改內容同步至資料庫。

Версия 537ecb1b6d869271a033a15ba7cdb676f194bfee

sqlite_streamlit_join_example.py Исходник
1import sqlite3
2import pandas as pd
3import streamlit as st
4from datetime import datetime, date
5
6def initialize_database(conn):
7 cursor = conn.cursor()
8
9 # 建立 Customers 資料表
10 cursor.execute('''
11 CREATE TABLE IF NOT EXISTS Customers (
12 CustomerID INTEGER PRIMARY KEY,
13 CustomerName TEXT NOT NULL,
14 ContactName TEXT,
15 Country TEXT
16 )
17 ''')
18
19 # 建立 Orders 資料表
20 cursor.execute('''
21 CREATE TABLE IF NOT EXISTS Orders (
22 OrderID INTEGER PRIMARY KEY,
23 CustomerID INTEGER,
24 OrderDate TEXT,
25 FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID)
26 )
27 ''')
28
29 # 插入範例資料到 Customers(如果表格為空)
30 cursor.execute('SELECT COUNT(*) FROM Customers')
31 if cursor.fetchone()[0] == 0:
32 customers = [
33 (1, 'Alfreds Futterkiste', 'Maria Anders', 'Germany'),
34 (2, 'Ana Trujillo Emparedados y helados', 'Ana Trujillo', 'Mexico'),
35 (3, 'Antonio Moreno Taquería', 'Antonio Moreno', 'Mexico'),
36 (4, 'Around the Horn', 'Thomas Hardy', 'UK')
37 ]
38 cursor.executemany('INSERT INTO Customers VALUES (?, ?, ?, ?)', customers)
39
40 # 插入範例資料到 Orders(如果表格為空)
41 cursor.execute('SELECT COUNT(*) FROM Orders')
42 if cursor.fetchone()[0] == 0:
43 orders = [
44 (101, 1, '2023-11-01'),
45 (102, 2, '2023-11-03'),
46 (103, 1, '2023-11-07'),
47 (104, 3, '2023-11-10'),
48 (105, 4, '2023-11-12')
49 ]
50 cursor.executemany('INSERT INTO Orders VALUES (?, ?, ?)', orders)
51
52 conn.commit()
53
54def get_joined_data(conn):
55 query = '''
56 SELECT Customers.CustomerID, Customers.CustomerName, Orders.OrderID, Orders.OrderDate
57 FROM Customers
58 INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID
59 ORDER BY Customers.CustomerID
60 '''
61 df = pd.read_sql_query(query, conn)
62 # 將 OrderDate 轉換為 datetime 類型
63 df['OrderDate'] = pd.to_datetime(df['OrderDate']).dt.date
64 return df
65
66def main():
67 st.title("SQLite JOIN 範例與 Streamlit st.data_editor")
68
69 # 連接到 SQLite 資料庫(這裡使用本地檔案資料庫)
70 conn = sqlite3.connect('example.db', check_same_thread=False)
71 initialize_database(conn)
72
73 # 獲取 JOIN 查詢的資料
74 df = get_joined_data(conn)
75
76 st.header("JOIN 查詢結果")
77 edited_df = st.data_editor(
78 df,
79 num_rows="dynamic",
80 key="data_editor",
81 use_container_width=True,
82 column_config={
83 "CustomerID": st.column_config.NumberColumn("Customer ID", disabled=True),
84 "CustomerName": st.column_config.TextColumn("客戶名稱", disabled=True), # 禁用編輯
85 "OrderID": st.column_config.NumberColumn("訂單編號", disabled=True),
86 "OrderDate": st.column_config.DateColumn("訂單日期")
87 }
88 )
89
90 if st.button("更新資料庫"):
91 # 將編輯後的資料寫回資料庫
92 cursor = conn.cursor()
93 updates = []
94 errors = []
95 for index, row in edited_df.iterrows():
96 # 確保 OrderDate 是 datetime.date 類型,轉換為字串格式
97 if isinstance(row['OrderDate'], datetime):
98 order_date_str = row['OrderDate'].strftime('%Y-%m-%d')
99 elif isinstance(row['OrderDate'], pd.Timestamp):
100 order_date_str = row['OrderDate'].date().strftime('%Y-%m-%d')
101 elif isinstance(row['OrderDate'], date):
102 order_date_str = row['OrderDate'].strftime('%Y-%m-%d')
103 elif isinstance(row['OrderDate'], str):
104 # 嘗試解析字串為日期
105 try:
106 order_date = datetime.strptime(row['OrderDate'], '%Y-%m-%d').date()
107 order_date_str = order_date.strftime('%Y-%m-%d')
108 except ValueError:
109 errors.append(f"無效的日期格式: {row['OrderDate']} (訂單編號: {row['OrderID']})")
110 continue
111 else:
112 errors.append(f"無法解析的日期格式: {row['OrderDate']} (訂單編號: {row['OrderID']})")
113 continue
114
115 updates.append((order_date_str, row['OrderID']))
116
117 if updates:
118 try:
119 cursor.executemany('''
120 UPDATE Orders
121 SET OrderDate = ?
122 WHERE OrderID = ?
123 ''', updates)
124 conn.commit()
125 st.success("資料庫已更新!")
126 except Exception as e:
127 st.error(f"資料庫更新失敗: {e}")
128
129 if errors:
130 for error in errors:
131 st.error(error)
132
133 # 不需要手動重新執行腳本,Streamlit 會自動重新渲染並顯示更新後的資料
134
135 # 關閉資料庫連接
136 conn.close()
137
138if __name__ == "__main__":
139 main()