从不同的表创建值的加权和

dun*_*unc 9 mysql

我正在尝试创建一个学生名单,这些学生的行为在我们每个学校的年度组中都是统计上最差的.

我们有一个名为的表students.

然后,我们有行为flagsalertssanctions.

但是,不同类别的旗帜/警报/制裁被认为比其他类别更严重.这些与标签一起存储在各自的_categories表中,例如flag_categoriessanction_categories.flag然后该表将有一个名为的列Category_ID(alerts有点不同,因为它只是一个Type带有'A','C','P'和'S'值的字段).

如果我想查看显示特定年份组中标记最高的学生的数据,我会运行此查询:

SELECT
  CONCAT(stu.Firstname, " ", stu.Surname) AS `Student`,
  COUNT(f.ID) AS `Flags`
FROM `students` stu
LEFT JOIN `flags` f ON f.Student_ID = stu.id
WHERE stu.Year_Group = 9
GROUP BY stu.id
ORDER BY `Flags` DESC
LIMIT 0, 20
Run Code Online (Sandbox Code Playgroud)

如果我想向学生展示特定年份组中最危机警报,我会运行此查询:

SELECT
  CONCAT(stu.Firstname, " ", stu.Surname) AS `Student`,
  COUNT(f.ID) AS `Flags`
FROM `students` stu
LEFT JOIN `flags` f ON f.Student_ID = stu.id
WHERE stu.Year_Group = 9
AND f.Category_ID = 10
GROUP BY stu.id
ORDER BY `Flags` DESC
LIMIT 0, 20
Run Code Online (Sandbox Code Playgroud)

如果我想找到学生有多少Late或Mobile标志,并且可能将这些标志加在一起(带有权重),我可以运行以下查询:

SELECT
  CONCAT(stu.Firstname, " ", stu.Surname) AS `Student`,
  SUM(CASE WHEN f.Category_ID = 10 THEN 1 ELSE 0 END) AS `Late Flags`,
  SUM(CASE WHEN f.Category_ID = 12 THEN 2 ELSE 0 END) AS `Mobile Flags`,
  ## not sure about this line below... is there a nicer way of doing it? `Late Flags` isn't recognised as a field apparently
  ## so I can't just do ( `Late Flags` + `Mobile Flags` )
  (SUM(CASE WHEN f.Category_ID = 10 THEN 1 ELSE 0 END) + SUM(CASE WHEN f.Category_ID = 12 THEN 2 ELSE 0 END)) AS `Points`
FROM `flags` f
LEFT JOIN `students` stu ON f.Student_ID = stu.id
WHERE stu.Year_Group = 9
GROUP BY stu.id
ORDER BY `Points` DESC
LIMIT 0, 20
Run Code Online (Sandbox Code Playgroud)

我不明白的是我将如何在无数的表格中做到这一点.我需要能够减肥:

  • 延迟(flags,Category_ID = 10),潜逃(flags,Category_ID = 15)和社区标志(flags,Category_ID = 13)以及保护警报(alerts,Type = 'S')都值1分
  • 行为标志(flags,Category_ID IN (1, 7, 8))值得2分
  • 过程警报(alerts,Type = 'P')和拘留制裁(sanctions,Category_ID = 1)值得3分

等等等等.这远远不是一个详尽的列表,但我已经包含了足够的变量来帮助我了解多表加权总和.

我正在寻找的结果只有2列 - 学生的名字和加权点.

因此,根据上面的要点,如果学生收到2个Late标志(每个1分)和1个Process警报(3分),输出应该只说Joe Bloggs5.

任何人都可以帮助我理解如何从不同的表中将这些加权值转换为每个学生的一个SUM'd输出吗?

[编辑] SQLFiddle:http://sqlfiddle.com/#!9/449218/1/0

Dre*_*rew 1

请注意,我这样做不是为了赏金。请给别人。

LEFT JOIN这可以通过几个派生表来完成。请注意,您没有提供制裁表。但下面的内容似乎很能说明问题。所以我创建了一个临时表。它似乎允许最大的灵活性,而不会使可能难以调试的更大的左连接概念过于复杂。毕竟,你说过你真正的查询会比这复杂得多。因此,更多地构建临时表结构。

这会将“通过参数学生年份传递”中的学生的 tmp 表的默认值为 0 加载到存储过程。执行两次更新。然后选择结果集。

架构/负载:

create schema s38741386; -- create a test database
use s38741386;

CREATE TABLE `students` (
  `id` int(11) PRIMARY KEY,
  `Firstname` varchar(50) NOT NULL,
  `Surname` varchar(50) NOT NULL,
  `Year_Group` int(2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

# STUDENT INSERTS
INSERT INTO `students`
  (`id`, `Firstname`, `Surname`, `Year_Group`)
VALUES
  (201, 'Student', 'A', 9),
  (202, 'Student', 'B', 9),
  (203, 'Student', 'C', 9),
  (204, 'Student', 'D', 9),
  (205, 'Student', 'E', 9);

CREATE TABLE `alert` (
  `ID` int(11) PRIMARY KEY,
  `Staff_ID` int(6) NOT NULL,
  `Datetime_Raised` datetime NOT NULL,
  `Room_Label` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `Type` enum('A','C','P','Q','S') COLLATE utf8_unicode_ci NOT NULL COMMENT 'A=Absconded, C=Crisis, P=Process, Q=Quiet, S=Safeguarding',
  `Details` text COLLATE utf8_unicode_ci,
  `Responder` int(8) DEFAULT NULL,
  `Datetime_Responded` datetime DEFAULT NULL,
  `Room_ID` int(11) NOT NULL COMMENT 'will be linked to internal room id.',
  `Status` varchar(1) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'O:ngoing, R:esolved'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

# ALERT INSERTS
INSERT INTO `alert`
  (`ID`, `Staff_ID`, `Datetime_Raised`, `Room_Label`, `Type`, `Details`, `Responder`, `Datetime_Responded`, `Room_ID`, `Status`)
VALUES
  (1, '101', '2016-08-04 00:00:00', NULL, 'P', NULL, '103', '2016-08-04 00:00:01', '15', 'R'),
  (2, '102', '2016-08-04 00:00:00', NULL, 'P', NULL, '103', '2016-08-04 00:00:01', '15', 'R'),
  (3, '102', '2016-08-04 00:00:00', NULL, 'P', NULL, '103', '2016-08-04 00:00:01', '15', 'R'),
  (4, '101', '2016-08-04 00:00:00', NULL, 'P', NULL, '103', '2016-08-04 00:00:01', '15', 'R');

CREATE TABLE `alert_students` (
  `ID` int(11) PRIMARY KEY,
  `Alert_ID` int(6) NOT NULL,
  `Student_ID` int(6) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

# ALERT_STUDENT INSERTS
INSERT INTO `alert_students`
  (`ID`, `Alert_ID`, `Student_ID`)
VALUES
  (1, '1', '201'),
  (2, '1', '202'),
  (3, '2', '201'),
  (4, '3', '202'),
  (5, '4', '203'),
  (6, '5', '204');

CREATE TABLE `flags` (
  `ID` int(11) PRIMARY KEY,
  `Staff_ID` int(11) NOT NULL,
  `Student_ID` int(11) NOT NULL,
  `Datetime` datetime NOT NULL,
  `Category_ID` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


# ALERT INSERTS
-- TRUNCATE TABLE flags;
INSERT INTO `flags`
  (`ID`, `Staff_ID`, `Student_ID`, `Datetime`, `Category_ID`)
VALUES
  (1, '101', '201', '2016-08-04 00:00:01', 10),
  (2, '102', '202', '2016-08-04 00:00:02', 12),
  (3, '102', '203', '2016-08-04 00:00:03', 10),
  (4, '101', '204', '2016-08-04 00:00:04', 13),
  (5, '102', '202', '2016-08-04 00:00:02', 12),
  (6, '102', '203', '2016-08-04 00:00:03', 10),
  (7, '101', '204', '2016-08-04 00:00:04', 13),
  (8, '102', '202', '2016-08-04 00:00:02', 10),
  (9, '102', '203', '2016-08-04 00:00:03', 10),
  (10, '101', '204', '2016-08-04 00:00:04', 7),
  (11, '101', '204', '2016-08-04 00:00:07', 8),
  (12, '101', '204', '2016-08-04 00:00:08', 1),
  (13, '101', '204', '2016-08-04 00:00:09', 8);
Run Code Online (Sandbox Code Playgroud)

存储过程:

DROP PROCEDURE IF EXISTS rptSM_by_year;
DELIMITER $$
CREATE PROCEDURE rptSM_by_year
(   pSY INT -- parameter student year
)
BEGIN


    DROP TEMPORARY TABLE IF EXISTS tmpStudentMetrics;
    CREATE TEMPORARY TABLE tmpStudentMetrics
    (   `StudentId` int(11) PRIMARY KEY,
        LateFP INT NOT NULL,
        MobiFP INT NOT NULL,
        AbscFP INT NOT NULL,
        CommFP INT NOT NULL,
        SafeAP INT NOT NULL,
        BehaFP INT NOT NULL,
        ProcAP INT NOT NULL
    )ENGINE=InnoDB;

    INSERT tmpStudentMetrics (StudentId,LateFP,MobiFP,AbscFP,CommFP,SafeAP,BehaFP,ProcAP)
    SELECT id,0,0,0,0,0,0,0
    FROM students
    WHERE Year_Group = pSY;

    UPDATE tmpStudentMetrics tmp
    JOIN
    (   SELECT
          stu.id,
          SUM(CASE WHEN f.Category_ID = 10 THEN 1 ELSE 0 END) AS `LateFP`,
          SUM(CASE WHEN f.Category_ID = 15 THEN 1 ELSE 0 END) AS `AbscFP`,
          SUM(CASE WHEN f.Category_ID = 13 THEN 1 ELSE 0 END) AS `CommFP`,
          SUM(CASE WHEN f.Category_ID = 12 THEN 2 ELSE 0 END) AS `MobiFP`,
          SUM(CASE WHEN f.Category_ID IN (1,7,8) THEN 2 ELSE 0 END) AS `BehaFP`
        FROM `flags` f
        LEFT JOIN `students` stu ON f.Student_ID = stu.id
        WHERE stu.Year_Group = pSY
        GROUP BY stu.id
    ) xDerived
    ON xDerived.id=tmp.StudentId
    SET tmp.LateFP=xDerived.LateFP,
    tmp.AbscFP=xDerived.AbscFP,
    tmp.CommFP=xDerived.CommFP,
    tmp.MobiFP=xDerived.MobiFP,
    tmp.BehaFP=xDerived.BehaFP;

    UPDATE tmpStudentMetrics tmp
    JOIN
    (   SELECT
          stu.id,
          SUM(CASE WHEN a.Type = 'S' THEN 1 ELSE 0 END) AS `SafeAP`,
          SUM(CASE WHEN a.Type = 'P' THEN 3 ELSE 0 END) AS `ProcAP`
        FROM `alert_students` als
        JOIN `alert` a
        ON a.ID=als.Alert_ID
        JOIN `students` stu 
        ON stu.id=als.Student_ID and stu.Year_Group = pSY
        GROUP BY stu.id
    ) xDerived
    ON xDerived.id=tmp.StudentId
    SET tmp.SafeAP=xDerived.SafeAP,
    tmp.ProcAP=xDerived.ProcAP;

    -- SELECT * FROM tmpStudentMetrics; -- check detail

    SELECT stu.id, 
    CONCAT(stu.Firstname, " ", stu.Surname) AS `Student`, 
    tmp.LateFP+tmp.MobiFP+tmp.AbscFP+tmp.CommFP+tmp.SafeAP+tmp.BehaFP+tmp.ProcAP AS `Points` 
    FROM `students` stu 
    JOIN tmpStudentMetrics tmp 
    ON tmp.StudentId=stu.id 
    WHERE stu.`Year_Group` = pSY 
    ORDER BY stu.id; 

    -- SELECT * FROM tmpStudentMetrics; -- check detail
    DROP TEMPORARY TABLE IF EXISTS tmpStudentMetrics;
    -- TEMP TABLES are connection based. Explicityly dropped above for safety when done.
    -- Depends on your connection type and life-span otherwise.
END$$
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

测试:

call rptSM_by_year(9);
+-----+-----------+--------+
| id  | Student   | Points |
+-----+-----------+--------+
| 201 | Student A |      7 |
| 202 | Student B |     11 |
| 203 | Student C |      6 |
| 204 | Student D |     10 |
| 205 | Student E |      0 |
+-----+-----------+--------+
Run Code Online (Sandbox Code Playgroud)

清理:

drop schema s38741386; -- drop the test database
Run Code Online (Sandbox Code Playgroud)