[RESOLU] SUM, une jointure qui pose problème ^^

Eléphant du PHP | 363 Messages

24 août 2015, 14:24

Bonjour,

Pouvez-vous m'aider sur ce problème svp merci ?

J'ai une table écoliers et une table absences. Je voudrais calculer pour chaque enfant son temps d'absence (c'est un exercice je ne fait pas de délation :D)

Y compris pour les enfants qui n'ont pas eu d'absences et c'est d'ailleurs eux qui me posent problème avec leur assiduité !!! :lol:

J'arrive pas à afficher Mattéo a été absent : 0 jours
SELECT *, SUM(nb_jours) AS total_jours
FROM
(
	SELECT *,
		CASE
			WHEN absences.fin = '0000-00-00' OR absences.fin IS NULL THEN DATEDIFF(CURRENT_DATE, absences.debut)
			ELSE DATEDIFF(absences.fin, absences.debut)
		END AS nb_jours
	FROM absences, ecoliers
) tmp
GROUP BY ecoliers.prenom

Féfé
Dis-donc fossoyeur, t'as une dent contre moi ou quoi ?

Mammouth du PHP | 571 Messages

24 août 2015, 17:35

bonjour,
Est-ce que t'as vraiment besoin de stocker la fin d'une absence dans la table des absences au point de se retrouver avec des dates vides(0000-00-00, NULL)? logiquement la table des absences ne devraient contenir que les données (id, date absence) des écoliers absents, ainsi les écoliers qui n'y figurent pas dans cette table sont considérés de facto comme ceux n'ayant aucune absence.
Avec le MCD suivant

Code : Tout sélectionner

ecoliers(id,nom, prenom) absences(ecolier_fk, date_absence) ;//où ecolier_fk est la clé étrangère
Pour compter le nombre d'absences de chaque écolier, on fait une jointure à gauche(cf Jointures externes)

Code : Tout sélectionner

SELECT id, nom, prenom, COUNT(a.ecolier_fk) nb_absences FROM ecoliers LEFT JOIN absence a ON e.id=a.ecolier_fk GROUP BY id, nom, prenom

Eléphanteau du PHP | 42 Messages

24 août 2015, 17:49

Code : Tout sélectionner

SELECT id, nom, prenom, COUNT(a.ecolier_fk) nb_absences FROM ecoliers LEFT JOIN absence a ON e.id=a.ecolier_fk GROUP BY id, nom, prenom
je pense que cette solution est la bonne. Il faut éviter de faire des requête compliquées avec MYSQL. Cela coûute moins cher en resource de faire plusieurs requêtes simples que une seule requête compliquée. :wink:

Eléphant du PHP | 363 Messages

24 août 2015, 21:09

Bonsoir,

Merci de votre aide.

Euh non ça va pas aller. Je cherche à savoir le nombre de jours où les élèves ont été absents d'où le calcul et les dates de début et fin.

Car si quelqu'un est absent 10 x 1 journée ça ne fait que 10 jours alors qu'une fois 1 mais tout le mois d'août ça fera 31.

Fée
Dis-donc fossoyeur, t'as une dent contre moi ou quoi ?

Mammouth du PHP | 571 Messages

25 août 2015, 10:56

Car si quelqu'un est absent 10 x 1 journée ça ne fait que 10 jours alors qu'une fois 1 mais tout le mois d'août ça fera 31.
ton groupement n'est probablement pas correct c-a-d les dates début et fin n'apparaissent pas dans la clause GROUP BY ce qui expliquerait qu'une absence du mois d'août soit compté 31 fois.

peux-tu poster la structure des tables ainsi qu'un jeu d'enregistrement?

Eléphant du PHP | 363 Messages

25 août 2015, 11:43

Hola senor :)

Les tables ecoliers et absences :

Code : Tout sélectionner

CREATE TABLE IF NOT EXISTS `absences` ( `id` int(5) NOT NULL AUTO_INCREMENT, `qui` int(5) NOT NULL, `debut` date NOT NULL, `fin` date NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ; INSERT INTO `absences` (`id`, `qui`, `debut`, `fin`) VALUES (1, 1, '2015-08-02', '2015-08-04'), (2, 2, '2015-05-10', '2015-05-16'), (3, 1, '2015-01-01', '2015-01-02');

Code : Tout sélectionner

CREATE TABLE IF NOT EXISTS `ecoliers` ( `idd` int(5) NOT NULL AUTO_INCREMENT, `prenom` varchar(5) NOT NULL, PRIMARY KEY (`idd`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ; INSERT INTO `ecoliers` (`idd`, `prenom`) VALUES (1, 'eva'), (2, 'aline'), (3, 'mateo');
Le résultat que je cherche à afficher :
eva a été absent(e) 3 jours (2+1 somme des lignes 1 et 3 dans absences)
aline a été absent(e) 6 jours (ligne 2 dans absences)
mateo a été absent(e) 0 jours (car pas présent dans la table des absences)

En espérant être plus claire ^^
Dis-donc fossoyeur, t'as une dent contre moi ou quoi ?

Mammouth du PHP | 571 Messages

25 août 2015, 13:24

Code : Tout sélectionner

SELECT idd, prenom,SUM(IFNULL(DATEDIFF(fin,debut),0)) nb_absences,debut,fin FROM ecoliers e LEFT JOIN absences a ON e.idd = a.qui GROUP BY idd, prenom,debut,fin;

Eléphant du PHP | 363 Messages

25 août 2015, 14:29

Kikoo Yann,

C'était super jusqu'à ce que j'ajoute une absence pour eva, ça me recrée une ligne avec le prénom plutôt que de faire la somme des lignes pour le même écolier ^^
J'ai essayé de rajouter "qui" dans le select et le group by mais ça ne change rien :(

Féfé
Dis-donc fossoyeur, t'as une dent contre moi ou quoi ?

Mammouth du PHP | 571 Messages

25 août 2015, 15:45

il suffit d'enlever la date début et la date fin dans le regroupement ainsi que dans le SELECT pour ressortir qu'une seule ligne par écolier:

Code : Tout sélectionner

SELECT idd, prenom,SUM(IFNULL(DATEDIFF(fin,debut),0)) nb_absences FROM ecoliers e LEFT JOIN absences a ON e.idd = a.qui GROUP BY idd, prenom;
toutefois si tu souhaites que les dates d'absences figurent dans le résultat sans pour autant en créer une nouvelle ligne d'un écolier tu peux utiliser la fonction mysql GROUP_CONCAT() qui permet de regrouper, en une seule ligne, les dates d'absences (début et fin) d'un écolier.

Code : Tout sélectionner

SELECT idd, prenom,SUM(IFNULL(DATEDIFF(fin,debut),0)) nb_absences,GROUP_CONCAT(CONCAT(debut,'/', fin )) periodes FROM ecoliers e LEFT JOIN absences a ON e.idd = a.qui GROUP BY idd, prenom;
où période représente le couple(date debut,date fin).chaque couple étant séparé par des virgules

Eléphant du PHP | 363 Messages

26 août 2015, 12:08

Kikoo,

C'est tout bon !!!!

:pouce:
Dis-donc fossoyeur, t'as une dent contre moi ou quoi ?