MySQL多表联查、分组查询每组最新的一条数据,并对某一字段进行条件统计

起因

本人在写查询的时候遇到了如题所述的要求,多次尝试无果(纯菜),最后发现“sql不会写?那就疯狂联表+堆子查询”。如果有更好的写法,也请在评论区赐教

表信息如下

equipment表:存储设备的名称等信息。其实这个表在接下来的查询中的作用,仅仅只是通过eq_id和其它表进行关联,然后查询到设备名称

DROP TABLE IF EXISTS `equipment`;
CREATE TABLE `equipment`  (
  `eq_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '设备ID',
  `eq_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '设备名称',
  `purchase_time` date NULL DEFAULT NULL COMMENT '采购时间',
  `service_life` int(11) NULL DEFAULT NULL COMMENT '预计使用寿命/年',
  `supplier_id` int(11) NULL DEFAULT NULL COMMENT '供应商ID',
  PRIMARY KEY (`eq_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

overhaul表:要求从这个表中查出最新的一条检修结果,并统计“检修结果”为“正常”(overhaul_reasult = 0)一共多少次

DROP TABLE IF EXISTS `overhaul`;
CREATE TABLE `overhaul` (
  `overhaul_id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NULL DEFAULT NULL COMMENT '员工ID',
  `overhaul_time` date NULL DEFAULT NULL COMMENT '检修时间',
  `overhaul_result` int(11) NULL DEFAULT NULL COMMENT '检修结果',
  `eq_id` int(11) NULL DEFAULT NULL '设备ID',
  PRIMARY KEY (`overhaul_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

risk_warning表

DROP TABLE IF EXISTS `risk_warning`;
CREATE TABLE `risk_warning` (
  `risk_warning_id` int(11) NOT NULL AUTO_INCREMENT,
  `eq_id` int(11) NULL DEFAULT NULL COMMENT '设备ID',
  `is_risk_warning` int(11) NULL DEFAULT NULL COMMENT '设备是否存在风险',
  PRIMARY KEY (`risk_warning_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

具体要求

  • 从“overhaul”表中查出“每一个设备”的最新的一条检修结果,并统计“检修结果”为“正常”(overhaul_reasult = 0)的次数;
  • 查询与"eq_id"对应的“eq_name”(设备名称);
  • 查询“risk_warning”的所有内容。
    然后这个需求对我这种菜🐔来说有些复杂了,所以我就干脆把这三个需求拆成三个子查询,最后拼在一起

查询语句及其结果

  • 第一个子查询:从“overhaul”表中查出“每一个设备”的最新的一条检修结果,并统计“检修结果”为“正常”(overhaul_reasult = 0)的次数;并通过“eq_id”(设备ID)与“equipment”表进行内联,查出“eq_name”(设备名称)
SELECT equipment.eq_id, equipment.eq_name, COUNT(overhaul_result = 0 OR NULL) AS overhaul_count, MAX(overhaul_time) AS last_overhaul_time
FROM overhaul
	JOIN equipment ON equipment.eq_id = overhaul.eq_id
GROUP BY equipment.eq_id

查询结果

查出这个后,准备第二步——因为使用了MAX()方法,现在的结果已经是最新的时间了,所以再利用"last_overhaul_time"字段与“overhaul”表进行内联,查出最新的“overhaul_result”

  • 第二个子查询:这时把第一个子查询写到JOIN后面,与“overhaul”表进行内联
SELECT a.*, overhaul.overhaul_result
FROM overhaul
JOIN
(SELECT equipment.eq_id, equipment.eq_name, COUNT(overhaul_result = 0 OR NULL) AS overhaul_count, MAX(overhaul_time) AS last_overhaul_time
FROM overhaul
	JOIN equipment ON equipment.eq_id = overhaul.eq_id
GROUP BY equipment.eq_id ) AS a ON overhaul.overhaul_time = a.last_overhaul_time

查询结果

  • 第三个子查询:如法炮制,通过“eq_id”,将第二个子查询与“risk_warning”进行内联,最后查出我们想要的结果
SELECT a.*, risk_warning.risk_waring_id, risk_warning.is_risk_warning
FROM risk_warning
JOIN
(SELECT a.*, overhaul.overhaul_result
FROM overhaul
JOIN
(SELECT equipment.eq_id, equipment.eq_name, COUNT(overhaul_result = 0 OR NULL) AS overhaul_count, MAX(overhaul_time) AS last_overhaul_time
FROM overhaul
	JOIN equipment ON equipment.eq_id = overhaul.eq_id
GROUP BY equipment.eq_id ) AS a ON overhaul.overhaul_time = a.last_overhaul_time ) AS a ON risk_warning.eq_id = a.eq_id

查询结果

总结

所以以后如果不会写SQL,那就疯狂子查询+内联罢!

posted @ 2024-03-06 16:04  这有懒狗233  阅读(39)  评论(0编辑  收藏  举报