sqlite_streamlit_join_example.py
· 4.5 KiB · Python
Surowy
import sqlite3
import pandas as pd
import streamlit as st
from datetime import datetime, date
def initialize_database(conn):
cursor = conn.cursor()
# 建立 Customers 資料表
cursor.execute('''
CREATE TABLE IF NOT EXISTS Customers (
CustomerID INTEGER PRIMARY KEY,
CustomerName TEXT NOT NULL,
ContactName TEXT,
Country TEXT
)
''')
# 建立 Orders 資料表
cursor.execute('''
CREATE TABLE IF NOT EXISTS Orders (
OrderID INTEGER PRIMARY KEY,
CustomerID INTEGER,
OrderDate TEXT,
FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID)
)
''')
# 插入範例資料到 Customers(如果表格為空)
cursor.execute('SELECT COUNT(*) FROM Customers')
if cursor.fetchone()[0] == 0:
customers = [
(1, 'Alfreds Futterkiste', 'Maria Anders', 'Germany'),
(2, 'Ana Trujillo Emparedados y helados', 'Ana Trujillo', 'Mexico'),
(3, 'Antonio Moreno Taquería', 'Antonio Moreno', 'Mexico'),
(4, 'Around the Horn', 'Thomas Hardy', 'UK')
]
cursor.executemany('INSERT INTO Customers VALUES (?, ?, ?, ?)', customers)
# 插入範例資料到 Orders(如果表格為空)
cursor.execute('SELECT COUNT(*) FROM Orders')
if cursor.fetchone()[0] == 0:
orders = [
(101, 1, '2023-11-01'),
(102, 2, '2023-11-03'),
(103, 1, '2023-11-07'),
(104, 3, '2023-11-10'),
(105, 4, '2023-11-12')
]
cursor.executemany('INSERT INTO Orders VALUES (?, ?, ?)', orders)
conn.commit()
def get_joined_data(conn):
query = '''
SELECT Customers.CustomerID, Customers.CustomerName, Orders.OrderID, Orders.OrderDate
FROM Customers
INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID
ORDER BY Customers.CustomerID
'''
df = pd.read_sql_query(query, conn)
# 將 OrderDate 轉換為 datetime 類型
df['OrderDate'] = pd.to_datetime(df['OrderDate']).dt.date
return df
def main():
st.title("SQLite JOIN 範例與 Streamlit st.data_editor")
# 連接到 SQLite 資料庫(這裡使用本地檔案資料庫)
conn = sqlite3.connect('example.db', check_same_thread=False)
initialize_database(conn)
# 獲取 JOIN 查詢的資料
df = get_joined_data(conn)
st.header("JOIN 查詢結果")
edited_df = st.data_editor(
df,
num_rows="dynamic",
key="data_editor",
use_container_width=True,
column_config={
"CustomerID": st.column_config.NumberColumn("Customer ID", disabled=True),
"CustomerName": st.column_config.TextColumn("客戶名稱", disabled=True), # 禁用編輯
"OrderID": st.column_config.NumberColumn("訂單編號", disabled=True),
"OrderDate": st.column_config.DateColumn("訂單日期")
}
)
if st.button("更新資料庫"):
# 將編輯後的資料寫回資料庫
cursor = conn.cursor()
for index, row in edited_df.iterrows():
# 確保 OrderDate 是 datetime.date 類型,轉換為字串格式
if isinstance(row['OrderDate'], datetime):
order_date_str = row['OrderDate'].strftime('%Y-%m-%d')
elif isinstance(row['OrderDate'], pd.Timestamp):
order_date_str = row['OrderDate'].date().strftime('%Y-%m-%d')
elif isinstance(row['OrderDate'], date):
order_date_str = row['OrderDate'].strftime('%Y-%m-%d')
elif isinstance(row['OrderDate'], str):
# 嘗試解析字串為日期
try:
order_date = datetime.strptime(row['OrderDate'], '%Y-%m-%d').date()
order_date_str = order_date.strftime('%Y-%m-%d')
except ValueError:
st.error(f"無效的日期格式: {row['OrderDate']} (訂單編號: {row['OrderID']})")
continue
else:
st.error(f"無法解析的日期格式: {row['OrderDate']} (訂單編號: {row['OrderID']})")
continue
cursor.execute('''
UPDATE Orders
SET OrderDate = ?
WHERE OrderID = ?
''', (order_date_str, row['OrderID']))
conn.commit()
st.success("資料庫已更新!")
# Streamlit 會自動重新執行腳本,顯示更新後的資料
# 關閉資料庫連接
conn.close()
if __name__ == "__main__":
main()
| 1 | import sqlite3 |
| 2 | import pandas as pd |
| 3 | import streamlit as st |
| 4 | from datetime import datetime, date |
| 5 | |
| 6 | def 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 | |
| 54 | def 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 | |
| 66 | def 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 | for index, row in edited_df.iterrows(): |
| 94 | # 確保 OrderDate 是 datetime.date 類型,轉換為字串格式 |
| 95 | if isinstance(row['OrderDate'], datetime): |
| 96 | order_date_str = row['OrderDate'].strftime('%Y-%m-%d') |
| 97 | elif isinstance(row['OrderDate'], pd.Timestamp): |
| 98 | order_date_str = row['OrderDate'].date().strftime('%Y-%m-%d') |
| 99 | elif isinstance(row['OrderDate'], date): |
| 100 | order_date_str = row['OrderDate'].strftime('%Y-%m-%d') |
| 101 | elif isinstance(row['OrderDate'], str): |
| 102 | # 嘗試解析字串為日期 |
| 103 | try: |
| 104 | order_date = datetime.strptime(row['OrderDate'], '%Y-%m-%d').date() |
| 105 | order_date_str = order_date.strftime('%Y-%m-%d') |
| 106 | except ValueError: |
| 107 | st.error(f"無效的日期格式: {row['OrderDate']} (訂單編號: {row['OrderID']})") |
| 108 | continue |
| 109 | else: |
| 110 | st.error(f"無法解析的日期格式: {row['OrderDate']} (訂單編號: {row['OrderID']})") |
| 111 | continue |
| 112 | |
| 113 | cursor.execute(''' |
| 114 | UPDATE Orders |
| 115 | SET OrderDate = ? |
| 116 | WHERE OrderID = ? |
| 117 | ''', (order_date_str, row['OrderID'])) |
| 118 | conn.commit() |
| 119 | st.success("資料庫已更新!") |
| 120 | # Streamlit 會自動重新執行腳本,顯示更新後的資料 |
| 121 | |
| 122 | # 關閉資料庫連接 |
| 123 | conn.close() |
| 124 | |
| 125 | if __name__ == "__main__": |
| 126 | main() |