Pourquoi ce LEFT JOIN élimine-t-il les enregistrements sans rien dans l'autre table?

StackOverflow https://stackoverflow.com/questions/424092

  •  05-07-2019
  •  | 
  •  

Question

J'ai un problème avec MySQL Left Join.

J'ai trois tables auxquelles j'essaie de participer.

Une table de personnes:

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

Une table d'étudiants:

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

Et un tableau des incidents:

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

Ce que j'essaie de sélectionner, c'est le prénom, le nom et le nombre d'incidents pour chaque élève au cours de la neuvième année.

Voici ma meilleure tentative de requête:

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

Cependant, il ignore les étudiants sans incident qui n’est pas ce que je veux. Ils doivent être affichés, mais avec un décompte égal à 0. Si je supprime la jointure gauche et le décompte, tous les élèves sont comme je l’attendais.

J'ai probablement mal compris la gauche rejoindre, mais je pensais que c'était censé faire, essentiellement ce que j'essaie de faire?

Merci de votre aide,

Adam

Était-ce utile?

La solution

Ce que vous faites est bien, vous venez de rater la clause groupe par

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;

Voici quelques données de test

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

Et voici la sortie de la requête avec le groupe ajouté:

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

Vous pouvez nettoyer davantage la requête en créant des clauses de jointure à partir de votre clause where et en les regroupant dans l'ID de la personne:

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;

Autres conseils

Vous pouvez également éviter LEFT JOIN en utilisant un sous-requête corrélée :

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

Vous utilisez un nombre sans groupe par pour commencer et vous mélangez "où" et " on " syntaxe pour les jointures. Essayez ceci:

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;

Ne s'agit-il pas d'une jointure externe gauche que vous recherchez? J'ai peut-être confondu ma terminologie? Ce ne serait pas la première fois. Mais la réponse d'Aron fonctionnerait.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top