3

我有一个 MySQL 左连接问题。

我有三个要加入的表。

人表:

创建表人(
    id INT NOT NULL AUTO_INCREMENT,
    键入 ENUM('student', 'staff', 'guardian') NOT NULL,
    first_name CHAR(30) NOT NULL,
    姓氏 CHAR(30) 非空,
    性别 ENUM('m', 'f') NOT NULL,
    dob VARCHAR(30) 非空,
    主键(id)
);

学生表:

创建表学生(
    id INT NOT NULL AUTO_INCREMENT,
    person_id INT NOT NULL,
    primary_guardian INT NOT NULL,
    secondary_guardian INT,
    join_date VARCHAR(30) 非空,  
    status ENUM('current', 'graduated', 'expelled', 'other') NOT NULL,
    导师组 VARCHAR(30) 非空,
    year_group VARCHAR(30) 非空,
    主键(id),
    FOREIGN KEY (person_id) REFERENCES person(id) ON DELETE CASCADE,
    外键(primary_guardian)参考监护人(id),
    FOREIGN KEY (secondary_guardian) REFERENCES Guardian(id),
    外键(导师组)参考导师组(名称),
    FOREIGN KEY (year_group) REFERENCES year_group(name)
);

还有一个事件表:

CREATE TABLE 事件 (
    id INT NOT NULL AUTO_INCREMENT,
    学生 INT NOT NULL,
    员工 INT NOT NULL,
    监护人 INT NOT NULL,
    sent_home BOOLEAN NOT NULL,
    疾病类型 VARCHAR(255) 非空,
    action_taken VARCHAR(255) 非空,
    event_date DATETIME NOT NULL,
    主键(id),
    外键(学生)参考学生(id),
    外键(员工)参考员工(id),
    外键(监护人)参考监护人(id)
);

我要选择的是第 9 年每个学生的名字、姓氏和事件数量。

这是我对查询的最佳尝试:

选择 p.first_name, p.last_name, COUNT(i.student)
FROM person p, student s LEFT JOIN event i ON s.id = i.student
WHERE p.id = s.person_id AND s.year_group LIKE "%Year 9%";

但是,它会忽略任何没有发生事件的学生,这不是我想要的 - 他们应该显示但计数为 0。如果我删除左连接和计数,那么我会得到所有学生,如我所料。

我可能误解了 left join 但我认为它应该做的,基本上是我想要做的?

谢谢你的帮助,

亚当

4

4 回答 4

6

你在做什么很好,你只是错过了 group by 条款

SELECT p.first_name, p.last_name, COUNT(i.student)
FROM person p, student s  LEFT JOIN incident i ON s.id = i.student 
WHERE p.id = s.person_id AND s.year_group LIKE "%Year 9%"
GROUP BY p.first_name, p.last_name;

这是一些测试数据

insert into person values(1, 'student', 'Alice', 'Foo', 'f','1970-01-01');
insert into person values(2, 'student', 'Bob', 'Bar', 'm','1970-01-01');

insert into student values(1,1,0,0,'', 'current','','Year 9');
insert into student values(2,2,0,0,'', 'current','','Year 9');

insert into incident values(1,1,0,0,0,'flu','chicken soup', '2008-01-08');

以下是添加了 group by 的查询的输出:

+------------+-----------+------------------+
| first_name | last_name | COUNT(i.student) |
+------------+-----------+------------------+
| Alice      | Foo       |                1 |
| Bob        | Bar       |                0 |
+------------+-----------+------------------+

您可以通过从 where 子句创建连接子句并根据人员 ID 分组来进一步清理查询:

SELECT p.first_name, p.last_name, COUNT(i.student)
FROM person p
INNER JOIN student s ON(p.id = s.person_id)
LEFT JOIN incident i ON(s.id = i.student)
WHERE s.year_group LIKE "%Year 9%"
GROUP BY p.id;
于 2009-01-08T13:10:15.540 回答
0

那不是您正在寻找的左外连接吗?我可能混淆了我的术语?不会是第一次。但阿伦的回答会奏效。

于 2009-01-08T12:51:44.437 回答
0

LEFT JOIN或者,您可以通过使用相关子查询来避免:

SELECT
  p.first_name
  , p.last_name
  , (SELECT COUNT(*) FROM incident i WHERE i.student = s.id) 
FROM
  person p JOIN student s on s.person_id = p.id
WHERE
  s.year_group LIKE "%Year 9%"
于 2009-01-08T12:56:43.117 回答
0

您开始使用不带 group by 的 count,并且您正在混合使用“where”和“on”语法进行连接。试试这个:

SELECT p.first_name, p.last_name, COUNT(i.student)
FROM person p
JOIN student s on p.id = s.person
LEFT JOIN incident i ON s.id = i.student 
WHERE s.year_group LIKE "%Year 9%"
GROUP BY P.id;
于 2009-01-08T13:14:22.097 回答