Try   HackMD

1⃣️ 資料庫設計

簡單版

CREATE TABLE IF NOT EXISTS attraction_images (
    id INT AUTO_INCREMENT PRIMARY KEY,
    attraction_id INT,
    attraction_name VARCHAR(30), 
    image_url TEXT NULL,
    FOREIGN KEY(attraction_id) REFERENCES attractions(id),
    FOREIGN KEY(attraction_name) REFERENCES attractions(name) 
);

 CREATE TABLE IF NOT EXISTS attractions(
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) UNIQUE,
    CAT VARCHAR(30) NULL,
    MRT VARCHAR(30) NULL,
    idpt VARCHAR(30) NULL,
    address VARCHAR(200) NULL,
    longitude FLOAT NULL,
    latitude FLOAT NULL,
    location POINT,
    direction VARCHAR(2000) NULL,
    rate INT NULL,
    description VARCHAR(2000) NULL,
    MEMO_TIME VARCHAR(1000) NULL,
    date DATE NULL,
    langinfo INT NULL,
    REF_WP INT,
    RowNumber INT,
    POI VARCHAR(10),
    avBegin DATE,
    avEnd DATE,
    SERIAL_NO VARCHAR(16),
    old_id INT
);

複雜版

主表

Id(主) 景點名 語言 之前的 id
INT INT Text INT

圖片關聯表:(同簡單版)

Id(主) 景點id (外) 景點名(外) 圖片網址陣列
INT INT Text

🌍🚄 地理關聯表

Id(主) 景點id (外) 景點名(外) 捷運站 交通方向 地址 經度 緯度
INT INT Text

✏️ 描述關聯表

Id(主) 景點id (外) 景點名(外) 評分 描述 時間備註 種類 來源
INT INT Text

📅 日期關聯表

Id(主) 景點id (外) 景點名(外) 日期 開始日 結束日
INT INT Text

💬 其他關聯表

Id(主) 景點id (外) 景點名(外) POI REF_WP 序號 SERIAL_NO 列號 來源
INT INT Text

CREATE TABLE IF NOT EXISTS attractions(
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100),
    langinfo INT NULL,
    old_id INT
);
CREATE TABLE IF NOT EXISTS attractions_location(
    id INT AUTO_INCREMENT PRIMARY KEY,
    attraction_id INT,
    attraction_name VARCHAR(100),
    MRT VARCHAR(30) NULL,
    direction VARCHAR(2000) NULL,
    address VARCHAR(200) NULL,
    longitude FLOAT NULL,
    latitude FLOAT NULL,
    location POINT,
    FOREIGN KEY(attraction_id) REFERENCES attractions(id)
);
CREATE TABLE IF NOT EXISTS attractions_description(
    id INT AUTO_INCREMENT PRIMARY KEY,
    attraction_id INT,
    attraction_name VARCHAR(100),
    rate INT NULL,
    description VARCHAR(2000) NULL,     
    MEMO_TIME VARCHAR(1000) NULL,
    CAT VARCHAR(30) NULL,
    idpt VARCHAR(30) NULL,
    FOREIGN KEY(attraction_id) REFERENCES attractions(id)
);
CREATE TABLE IF NOT EXISTS attractions_date(
    id INT AUTO_INCREMENT PRIMARY KEY,
    attraction_id INT,
    attraction_name VARCHAR(100),
    date DATE NULL,
    avBegin DATE,
    avEnd DATE,  
    FOREIGN KEY(attraction_id) REFERENCES attractions(id)
);
-- 
CREATE TABLE IF NOT EXISTS attractions_others(
    id INT AUTO_INCREMENT PRIMARY KEY,
    attraction_id INT,
    attraction_name VARCHAR(100),
    POI VARCHAR(10),
    REF_WP INT,
    SERIAL_NO VARCHAR(16),     
    RowNumber INT,
    FOREIGN KEY(attraction_id) REFERENCES attractions(id)
);
-- 照片
CREATE TABLE IF NOT EXISTS attraction_images (
    id INT AUTO_INCREMENT PRIMARY KEY,
    attraction_id INT,
    attraction_name VARCHAR(100),
    image_url TEXT NULL,
    FOREIGN KEY(attraction_id) REFERENCES attractions(id)
);

2⃣️ 最後ㄧ頁

next_page = page + 1 if len(attractions) == 12 else None

隱含了一個錯誤假設,除以 12 除不盡才是最後ㄧ頁,但如果最後ㄧ頁剛好是 12 * N 怎麼辦?

# 個數不能超過總數
is_last_page = (page * 12 + len(attractions)) >= total_count
next_page = page + 1 if not is_last_page else None

總數

query_count = "SELECT COUNT(*) FROM attractions "
if keyword:
    query_count += "WHERE name LIKE %s OR mrt = %s "
    # 萬用字元的 %{keyword}% 讓名稱能模糊匹配到關鍵字
    cursor.execute(query_count, (f"%{keyword}%", keyword))
else:
    cursor.execute(query_count)
    
    # 從查詢結果中獲取總數。
    # `etchone() 返回一個 tuple,而 [0] 取 tuple 的第一個元素,也就是計數結果
    total_count = cursor.fetchone()['COUNT(*)']

3⃣️ 分析景點

    SELECT mrt, COUNT(*) as count
        FROM attractions
        -- 排除那些沒有關聯到捷運站的景點
        WHERE mrt IS NOT NULL
        GROUP BY mrt
        --  根據景點數量進行降序排序(多 ->少)
        ORDER BY count DESC
        LIMIT 40
mrts = [
           row['mrt'] for row 
           in result_raw
       ]
# 或
mrts = [
            row['mrt'] 
            if row['mrt'] is not None 
            else '未知' 
            for row in result_raw
       ]

4⃣️ 價格

  • 實例類型(例如:t2.micro, t3.small 等)
  • 運行時間(一個月有大約 720 小時)
  • 地理區域(不同區域有不同價格)
  • 附加資源(例如:儲存、資料傳輸等)
subquery = 
db.session.query(
    Attraction.MRT,
    func.count(Attraction._id).label('num_around_attractions')
)
.group_by(Attraction.MRT)
.subquery()

mrt_attraction_counts = 
db.session.query(
    subquery.c.MRT,
    subquery.c.num_around_attractions
)
.order_by(subquery.c.num_around_attractions.desc()).all()

❓ 其他資料庫設計參考

SELECT 
    attractions.attraction_id, 
    attractions.attraction,
    attractions.category, 
    attractions.description,
    attractions.address, 
    attractions.direction,
    mrt.mrt_station, 
    attractions.lat, 
    attractions.lng,
    attractions.id
FROM 
    mrt 
INNER JOIN 
    attractions 
ON
mrt.id = attractions.mrt_id 
WHERE 
    mrt.mrt_station=%s 
OR 
    attractions.attraction LIKE %s 
ORDER BY 
    attractions.id 
LIMIT %s,12
SELECT attraction.*, GROUP_CONCAT(images.images_link) AS images_links 
    FROM attraction 
    LEFT JOIN images ON attraction.id = images.attraction_id 
    WHERE mrt = %s OR name LIKE %s 
    GROUP BY attraction.id 
    LIMIT %s, %s
on, cursor = connect_to_database()
	cursor.execute("SELECT MRT FROM attraction")
	data = cursor.fetchall()
	con.close()
	data_list=[]
	for name in data:
		if name[0]!=None:
			data_list.append(name[0])
	element_count = Counter(data_list)
	sorted_elements = sorted(element_count.items(), key=lambda x: x[1], reverse=True)
	sort_list=[]
	for i in sorted_elements:
		sort_list.append(i[0])
	response={
  		"data": sort_list
	}