Расчет взвешенных оценок внутри взвешенных оценок - PullRequest
0 голосов
/ 14 июля 2020

У меня есть математическая / SQL проблема, с которой я боролся.

У меня есть две таблицы со следующей структурой:

    CREATE TABLE Exams
(
ExamID INT PRIMARY KEY,
ExamName VARCHAR(100),
CourseID INT,
RelatedExamID INT NULL,
Weighting DECIMAL (5,3)
)

CREATE TABLE ExamMarks
(
ExamMarkID INT IDENTITY PRIMARY KEY,
StudentID VARCHAR(8),
ExamID INT FOREIGN KEY REFERENCES Exams(ExamID),
ExamMark DECIMAL (5,4)
)

Таблица экзаменов содержит следующее данные:

INSERT INTO Exams (ExamID, ExamName, CourseID, RelatedExamID, Weighting)
VALUES (1, 'English',1,NULL,1),
(2, 'French',2,NULL,1),
(3, 'Maths',3,NULL,0.6),
(4, 'Statistics',3,NULL,0.4),
(5, 'Physics Part 1',4,NULL,0.5),
(6, 'Physics Part 2',4,NULL,0.5),
(7, 'Heat and Mass',4,6,0.25)

Таблица экзаменационных оценок содержит следующие данные:

INSERT INTO ExamMarks (StudentID, ExamID, ExamMark)
VALUES ('00112233', 1, 0.75),
('00112233', 2, 0.52),
('00112233', 3, 0.68),
('00112233', 4, 0.8),
('00112233', 5, 0.50),
('00112233', 6, 0.66),
('00112233', 7, 0.45)

Идея состоит в том, что данный курс может иметь

  • экзамен (например, с английским sh и французским)
  • Несколько экзаменов (например, с курсом 3, который состоит из 2 экзаменов под названием «Математика» и «Физика»), которые имеют независимые веса - в данном случае Курс структурирован таким образом, что экзамен по математике составляет 60% от общего количества, а экзамен по физике дает 40%.
  • Экзамены с дополнительными экзаменами, например, курс 4, подробнее о котором чуть позже. *

    Если я хочу получить взвешенные общие баллы для каждого кандидата на каждом экзамене - забывая пока о курсе 4 - я делаю следующее:

    SELECT em.StudentID,e.CourseID, SUM(em.ExamMark * e.Weighting)/SUM(e.Weighting)
    FROM Exams e
    INNER JOIN ExamMarks em ON e.ExamID = em.ExamID
    GROUP BY em.StudentID,e.CourseID
    

    Однако курс 4 состоит из 3 части:

    • Физика 1 часть - 50% т otal и
    • Physics Part 2 - также 50% от общего количества
    • Heat and Mass, что составляет 25% Physics Part 2 (таким образом, его идентификатор в столбце «RelatedExamID»)

    Для ясности: тепло и масса составляют 25% части 2 по физике, что само по себе составляет 50% курса.

    Я поместил эти цифры в таблицу Excel , и после долгой ломки головы выяснил, что наш ученик должен получить оценку за Курс 4 на уровне 55,375%.

    Однако, к сожалению, мои SQL (и maths / logi c) недостаточно хороши, чтобы получить такой результат в запросе SQL.

    Приведенные выше данные представляют собой что-то вроде упрощения. Фактически, необходимо учитывать около 10000 баллов (задействовано около 500 студентов) примерно за 200 различных экзаменов, из которых, возможно, 30 являются «дополнительными экзаменами». Ежегодно их необходимо суммировать, чтобы дать студенту оценку за курс с учетом этих весов.

1 Ответ

0 голосов
/ 15 июля 2020

Хорошо, мне удалось найти решение. Я все равно буду благодарен тем, кто знает больше меня, за других, которые могут быть более эффективными или надежными.

--Get SubComponent marks
WITH SubComponents
AS
(SELECT
        em.StudentID
       ,em.ExamID
       ,e.RelatedExamID
       ,e.Weighting
       ,e.Weighting * em.ExamMark AS WeightedMark
    FROM Exams e
    INNER JOIN ExamMarks em
        ON e.ExamID = em.ExamID
    WHERE e.RelatedExamID IS NOT NULL),
--Get marks for those components which have subcomponents
ParentComponents
AS
(SELECT
        em.StudentID
       ,e.CourseID
       ,em.ExamID
       ,e.RelatedExamID
       ,e.Weighting
       ,((1 - SubComponents.Weighting) * em.ExamMark) 
            + SubComponents.WeightedMark AS OverallComponentMark
    FROM Exams e
    INNER JOIN ExamMarks em
        ON e.ExamID = em.ExamID
    INNER JOIN SubComponents
        ON SubComponents.RelatedExamID = e.ExamID
        AND SubComponents.StudentID=em.StudentID),

--Get marks for those components which are neither parent nor child components
StandaloneComponents
AS
(SELECT
        em.StudentID
       ,e2.CourseID
       ,em.ExamID
       ,e2.RelatedExamID
       ,e2.Weighting
       ,em.ExamMark
    FROM Exams e2
    INNER JOIN ExamMarks em
        ON e2.ExamID = em.ExamID
    WHERE NOT EXISTS (SELECT
            *
        FROM Exams
        WHERE RelatedExamID = e2.ExamID)
    AND e2.RelatedExamID IS NULL),

-- Bring all the above together
ComponentMarks
AS
(SELECT
        StudentID
       ,CourseID
       ,ExamID
       ,Weighting
       ,ExamMark
    FROM StandaloneComponents
    UNION
    SELECT
        StudentID
       ,CourseID
       ,ExamID
       ,Weighting
       ,OverallComponentMark
    FROM ParentComponents)

-- Finally group and combine marks at course level
SELECT
    StudentID
   ,CourseID
   ,SUM(ExamMark * Weighting) / SUM(Weighting)
FROM ComponentMarks
GROUP BY StudentID
        ,CourseID
...