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

时间:2016-08-03 10:46:22

标签: mysql

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

我们有一个名为students的表。

然后我们有行为flagsalerts,以及sanctions

然而,不同类别的旗帜/警报/制裁被认为比其他类别更严重。它们与各自的_categories表中的标签一起存储,例如flag_categoriessanction_categoriesflag表格会有一个名为Category_ID的列(alerts略有不同,因为它只是一个带有'A','C','P'的Type字段和'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

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

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

如果我想查找学生有多少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

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

  • 延迟(flagsCategory_ID = 10),潜逃(flagsCategory_ID = 15)和社区标记(flagsCategory_ID = 13)以及保护提醒(alertsType = 'S')都值1分
  • 行为标志(flagsCategory_ID IN (1, 7, 8))值2分
  • 处理提醒(alertsType = 'P')和拘留制裁(sanctionsCategory_ID = 1)值3分

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

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

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

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

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

4 个答案:

答案 0 :(得分: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);

存储过程:

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 ;

<强>测试

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 |
+-----+-----------+--------+

<强>清理:

drop schema s38741386; -- drop the test database

答案 1 :(得分:1)

认为您所要求的所有内容都可以通过子查询和几个子SELECT来完成:

SELECT `Student`,
       `Late Flags` * 1
     + `Absconded Flags` * 1
     + `Community Flags` * 1
     + `Safeguarding Alerts Flags` * 1
     + `Behavioural flags` * 2
     + `Process Alerts Flags` * 3 AS `Total Points`
FROM
(
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 1 ELSE 0 END) AS `Mobile Flags`,
  SUM(CASE WHEN f.Category_ID = 15 THEN 1 ELSE 0 END) AS `Absconded Flags`,
  SUM(CASE WHEN f.Category_ID = 13 THEN 1 ELSE 0 END) AS `Community Flags`,
  (SELECT COUNT(*) FROM `alert` a JOIN `alert_students` ast ON ast.`Alert_ID` = a.`ID`
   WHERE ast.`Student_ID` = stu.`id` AND a.`Type` = 'S') AS `Safeguarding Alerts Flags`,
  SUM(CASE WHEN f.Category_ID IN (1, 7, 8) THEN 1 ELSE 0 END) AS `Behavioural flags`,
  (SELECT COUNT(*) FROM `alert` a JOIN `alert_students` ast ON ast.`Alert_ID` = a.`ID`
   WHERE ast.`Student_ID` = stu.`id` AND a.`Type` = 'P') AS `Process Alerts Flags`
FROM `students` stu
LEFT JOIN `flags` f ON f.Student_ID = stu.id
WHERE stu.Year_Group = 9
GROUP BY stu.id
LIMIT 0, 20
) subq
ORDER BY `Total Points` DESC;

上述查询包括您提到的除制裁之外的所有内容(因为您的原始SQL Fiddle演示版未包含此表)。

演示

上述查询的更新小提示位于:http://sqlfiddle.com/#!9/449218/39

答案 2 :(得分:0)

您可以使用union all

基本上,您为每个表创建所有单独的查询,并使用union all将它们全部连接在一起。

这是一个例子,我使用了你的学生表两次,但你会将第二个改为你想要的其他表。 SQLFiddle

答案 3 :(得分:0)

您可以使用JSONObject JsonObject = (JSONObject) obj; JSONObject Definition = (JSONObject) JsonObject.get("ScriptDefinition"); JSONObject Map = (JSONObject) Definition.get("ScriptNameMap"); JSONArray TestObjectArray = (JSONArray) Map.get("TestObject"); Iterator<?> i = TestObjectArray.iterator(); while (i.hasNext()) { JSONObject Slide = (JSONObject) i.next(); String Name = (String) Slide.get("Name"); String Instance = (String) Slide.get("TO"); String Atributos = Name + "," + Instance; System.out.println(Atributos);}

执行此操作
aceptar,GuiTestObject
jTextField,TextGuiSubitemTestObjec
login,TopLevelTestObject
login2,GuiTestObject

但是如果您对数据库有完全的访问权限,我会将这些权重放在相应的类别和类型中,这将简化逻辑。