Pregunta

Tengo un problema de MySQL Left Join.

Tengo tres tablas a las que estoy tratando de unir.

Una tabla de personas:

CREATE TABLE person (
    id INT NOT NULL AUTO_INCREMENT,
    type ENUM('student', 'staff', 'guardian') NOT NULL,
    first_name CHAR(30) NOT NULL,
    last_name CHAR(30) NOT NULL,
    gender ENUM('m', 'f') NOT NULL,
    dob VARCHAR(30) NOT NULL,
    PRIMARY KEY (id)
);

Una mesa de estudiantes:

CREATE TABLE student (
    id INT NOT NULL AUTO_INCREMENT,
    person_id INT NOT NULL,
    primary_guardian INT NOT NULL,
    secondary_guardian INT,
    join_date VARCHAR(30) NOT NULL,  
    status ENUM('current', 'graduated', 'expelled', 'other') NOT NULL,
    tutor_group VARCHAR(30) NOT NULL,
    year_group VARCHAR(30) NOT NULL,
    PRIMARY KEY (id),
    FOREIGN KEY (person_id) REFERENCES person(id) ON DELETE CASCADE,
    FOREIGN KEY (primary_guardian) REFERENCES guardian(id),
    FOREIGN KEY (secondary_guardian) REFERENCES guardian(id),
    FOREIGN KEY (tutor_group) REFERENCES tutor_group(name),
    FOREIGN KEY (year_group) REFERENCES year_group(name)
);

Y una tabla de incidentes:

CREATE TABLE incident (
    id INT NOT NULL AUTO_INCREMENT,
    student INT NOT NULL,
    staff INT NOT NULL,
    guardian INT NOT NULL,
    sent_home BOOLEAN NOT NULL,
    illness_type VARCHAR(255) NOT NULL,
    action_taken VARCHAR(255) NOT NULL,
    incident_date DATETIME NOT NULL,
    PRIMARY KEY (id),
    FOREIGN KEY (student) REFERENCES student(id),
    FOREIGN KEY (staff) REFERENCES staff(id),
    FOREIGN KEY (guardian) REFERENCES guardian(id)
);

Lo que estoy tratando de seleccionar es el nombre, el apellido y el número de incidentes para cada estudiante en el año 9.

Aquí está mi mejor intento para la consulta:

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%";

Sin embargo, ignora a los estudiantes sin un incidente que no es lo que quiero, deberían mostrarse pero con un conteo de 0. Si elimino la combinación izquierda y el conteo, obtengo todos los estudiantes como esperaría.

Probablemente he entendido mal a la izquierda, pero pensé que se suponía que debía hacer, ¿esencialmente lo que estoy tratando de hacer?

Gracias por tu ayuda,

Adán

¿Fue útil?

Solución

Lo que estás haciendo está bien, simplemente te saltaste del grupo por cláusula

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;

Aquí hay algunos datos de prueba

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');

Y aquí se agrega el resultado de la consulta con el grupo:

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

Puede limpiar la consulta aún más haciendo cláusulas de unión de su cláusula where y agrupándolas en el ID de la persona:

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;

Otros consejos

Alternativamente, puedes evitar el LEFT JOIN usando subconsulta correlacionada :

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%"

para empezar, estás usando contar sin grupo y estás mezclando " donde " y " en " sintaxis para uniones. Prueba esto:

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;

¿No sería esa una combinación externa izquierda que está buscando? ¿Puedo tener mi terminología mezclada? No sería la primera vez. Pero la respuesta de Aron funcionaría.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top