Online Judge(OJ)搭建——2、數據庫,SQL語句


數據庫EER圖

 

 

數據庫表、字段、約束解釋

users 用戶:

id 標識符,email 郵箱,password 密碼,name 姓名,sex 性別,enabled 啟用 ,role 角色

id primary key

 

advisors 指導:

id 標識符,uid_user 被指導者,uid_admin 指導者

id primary key

uid_user -> user(id),uid_admin(id)

 

categories 類別:

id 標識符,name 名稱,description 描述

id primary key

 

questions 問題:

id 標識符,qid 題號,description 描述,cid 類別標識符,name 名稱

id primary key

cid -> categories(id)

 

test_data 測試數據:

id 標識符,qid 題號,input 一組輸入,output 一組輸出

id primary key

qid -> questions(id)

 

tests 測試信息:

id 標識符,uid 用戶標識符,qid 題號,submit_time 提交時間,code 代碼,correct_rate 正確率

id primary key

uid -> users(id),qid -> questions(id)

 

scores 成績:

id 標識符,uid 用戶標識符,cid 類別標識符,usual_score 平時成績

 

復雜SQL語句

selectSumScoreAndRank:

功能:根據用戶 ID,查詢用戶 ID、用戶所有題目總成績、總成績的排名。

實現:主要是利用了聚集函數,MySQL 自帶 @rowNum 屬性。 

代碼:

       SELECT *
        FROM
            (SELECT
                 uid,
                 sum_correct_rate,
                 (@rowNum := @rowNum + 1) AS rank
             FROM (SELECT
                       uid,
                       sum(max_corrcet_rate) AS sum_correct_rate
                   FROM
                       (SELECT
                            uid,
                            qid,
                            max(correct_rate) AS max_corrcet_rate
                        FROM tests
                        GROUP BY uid, qid) AS max_tests
                   GROUP BY uid
                   ORDER BY sum_correct_rate DESC) AS rank_tests, (SELECT (@rowNum := 0)) AS rank) AS all_tests
        WHERE uid = #{uid}

 

selectPracticeAndUsualScoreFromAdmin:

功能:根據管理員 ID 和類別 ID,查詢特定管理員的指導關系下用戶的實踐成績和平時成績。

實現:首先根據指導關系下的用戶 ID 和特定題庫 ID 選出特定題目,再根據特定題目選出特定測試,最后利用聚集函數進行成績整合(例如,聚集函數 sum 計算特定用戶特定題庫下的總分)。

代碼:

        SELECT
            scores.id,
            scores.uid,
            users.email,
            users.name                       AS userName,
            sum_tests.avg_correct_rate * 100 AS practice_score,
            scores.usual_score
        FROM
            (SELECT
                 uid,
                 avg(max_corrcet_rate) AS avg_correct_rate
             FROM
                 (SELECT
                      uid,
                      qid,
                      max(correct_rate) AS max_corrcet_rate
                  FROM (SELECT
                            uid,
                            qid,
                            correct_rate
                        FROM tests
                        WHERE
                            uid IN (SELECT uid_user
                                    FROM advisors
                                    WHERE uid_admin = #{uidAdmin}) AND qid IN (SELECT questions.id
                                                                               FROM categories
                                                                                   LEFT JOIN questions
                                                                                       ON categories.id = questions.cid
                                                                               WHERE cid = #{cid})
                       ) AS filter_tests
                  GROUP BY uid, qid) AS max_tests
             GROUP BY uid) AS sum_tests LEFT JOIN scores ON sum_tests.uid = scores.uid AND scores.cid = #{cid} LEFT JOIN users ON sum_tests.uid = users.id

 

 

設計思想

1、為什么要每張表都有 ID,並且把 ID 作為主鍵?

表的主鍵不應該可以變動的,而現實中的需求會變動。起初,表 questions 是沒有列 cid 的,后來為了模擬現實中題目(questions)的類別(categories), 增加了 cid 列。

假設有一種情況:

類別名(categories name)為 Java,題號(qid)為 1,2,3;類別為 C#,題號為1,2,3。 

如果表 questions 以 qid 作為主鍵,上述的情況是無法實現的,因為primary key 違反了唯一性約束,需要重新設計架構;如果表 questions 以無意義的 id 作為主鍵,上述情況實現很簡單,不需要變動架構。

所以,表的主鍵最好是無意義的id。

 

2、表 questions 和表 test_data 的設計

表 questions 起初和 test_data 是放在一起的,即 input 和 output 起初是在表 questions 中的,並且每條記錄表示的多組輸入和多組輸出。后來我剝離了,並且將每條記錄由多組輸入和多組輸出變為一組輸入和一組輸出,原因如下:

① 多組的輸入或者多組的輸出不方便保存。如果合並為一組保存,必須以一個符號作為分隔符,然而在 OJ 系統,任何符號的輸入都是有可能的,分隔符無法選擇

② 如果采用多組保存,冗余性較高,qid、name等多保存了很多次。

所以,我采取弱關聯(將多值屬性剝離,新建一個表存入,新表高度依賴於原來的表)來保存。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM