Requête particulière, comment faire ?

sanceray3
Invité n'ayant pas de compte PHPfrance

02 nov. 2010, 19:04

Bonjour à tous,

Voilà je vais essayer de vous expliquer mon petit cas de figure sur lequel je me prends la tête. Je travaille sur une petite application qui permet de gérer des pointages.

J’ai deux tables regroupant un certains nombre de champs dont ceux présentés ci-dessous :

Pointage
Id_pointage | id_user | semaine | temps | …….

Users
Id_user | nom | prenom | ………

Mon souhait est de faire une requête qui me ressorte toutes les personnes n’ayant pas pointé 5 jours (temps) / semaine et ce pour toutes les semaines passées, avec un résultat sous la forme suivante :

Id_user | semaine | temps

J’ai donc crée la requête suivante :
SELECT semaine,id_user,SUM(temps) AS totalJ FROM pointage WHERE semaine<42
GROUP BY id_user,semaine HAVING totalJ<5 ORDER BY id_user
Le hic avec cette requête, c’est que seules les lignes des personnes ayant effectué au moins un pointage pour une semaine donnée apparaissent.

Si par exemple l’id_user 1 n’a effectué aucun pointage pour la semaine 40, il n’apparaitra pas. Un peu embêtant pour une requête devant me donner toutes les personnes en retard de pointage. Par contre si il avait juste pointé 1 jour, il serait apparu.

Alors j’ai essayé de modifier ma requête dans tous les sens, en créant une table semaine, en faisant de LEFT / RIGHT JOIN mais rien n’y fait, je ne m’en sors pas !

Avez-vous une idée de comment je peux construire cette « foutu » requête !?

Par avance grand merci pour votre aide.

Mammouth du PHP | 19672 Messages

02 nov. 2010, 23:03

Essaye en faisant une requête externe à partir de ta table Users : pour ma part je tenterais ceci :
SELECT 
  u.id_user,
  p.semaine,
  SUM(p.temps) AS totalJ 
FROM users u
  LEFT OUTER join pointage p ON u.id_user = p.id_user
WHERE p.semaine < 42
GROUP BY u.id_user, p.semaine 
HAVING totalJ < 5 
ORDER BY u.id_user
En option si ça ne fonctionne pas, parce que j'ai un petit doute :
SELECT 
  u.id_user,
  p.semaine,
  IFNULL(SUM(p.temps), 0) AS totalJ 
FROM users u
  LEFT OUTER join pointage p ON u.id_user = p.id_user
WHERE p.semaine < 42
GROUP BY u.id_user, p.semaine 
HAVING totalJ < 5 
ORDER BY u.id_user
Modifié en dernier par Cyrano le 03 nov. 2010, 10:11, modifié 1 fois.
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

sanceray3
Invité n'ayant pas de compte PHPfrance

03 nov. 2010, 10:08

Tout d'abord merci pour votre aide.

Alors c'est marrant parce qu'on arrive finalement tous à la même chose. J'avais essayé ces syntaxes. Elles me retournent bien les retards de pointages mais uniquement si la personne a effectué au moins un pointage pour une semaine. Je n'ai aucune ligne de ce style par exemple : id_user : 1 - semaine : 42 - totalJ : 0

Mammouth du PHP | 19672 Messages

03 nov. 2010, 10:16

Je serais tenté de me tourner vers une alternative simple et rapide : d'abord rajouter le numéro de semaine dans la clause ORDER BY et ensuite par traitement détecter un trou dans les numéros de semaines et en conclure logiquement qu'on peut le boucher avec ce numéro manquant et un nombre de jours correspondant de zéro. :-k
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Invité
Invité n'ayant pas de compte PHPfrance

03 nov. 2010, 11:34

Merci pour votre aide. Je ne suis pas loin du but en utilisant la requête ci-dessous :

Code : Tout sélectionner

SELECT T1.id_semaine AS semaine,T1.id_user, SUM(temps) AS totalJ FROM pointage p RIGHT JOIN ( SELECT u.id_user,s.id_semaine FROM utilisateur u,semaine s WHERE id_semaine <= 42 GROUP BY id_user,id_semaine ) T1 ON p.id_user = T1.id_user WHERE T1.id_user=55 GROUP BY T1.id_semaine, T1.id_user ORDER BY semaine
En faites j'arrive bien à avoir un résultat sous forme id_user / semaine. Par contre mon "SUM" me fait la somme de tous les pointages de la personnes. Du coup mon résultat se présente de la manière suivante : id_user : 1 / semaine : 40 / totalJ : 225, alors que pour une semaine complète j'aurais aimé un résultat sous cette forme : id_user : 1 / semaine : 40 / totalJ : 5

Avez vous une idée de comment je peux résoudre ce dernier point !

Mammouth du PHP | 19672 Messages

03 nov. 2010, 11:40

Il manque une condition de jointure dans la sous-requête ;)
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

sanceray3
Invité n'ayant pas de compte PHPfrance

03 nov. 2010, 11:54

Je pense aussi mais mon manque de connaissance fait que je sais pas comment m'y prendre ! Pouvez vous me guider svp....

Mammouth du PHP | 19672 Messages

03 nov. 2010, 12:13

Comme ceci par exemple ?
SELECT T1.id_semaine AS semaine,T1.id_user, SUM(temps) AS totalJ
FROM pointage p
  RIGHT JOIN
  (
      SELECT
          u.id_user,
          s.id_semaine
      FROM utilisateur u
        INNER JOIN semaine s ON u.id_user = s.id_user
      WHERE id_semaine <= 42
      GROUP BY id_user, id_semaine
  ) T1 ON p.id_user = T1.id_user
WHERE T1.id_user=55
GROUP BY T1.id_semaine, T1.id_user
ORDER BY semaine;
Si on ne fait pas ça, ça crée un beau produit cartésien et des résultats pour le moins fantaisistes :-k
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

ViPHP
ViPHP | 2291 Messages

03 nov. 2010, 17:41

Salut,

Donc si je comprends bien tu souhaites sortir tous les utilisateurs qui ne sont pas dans la table pointage pour une semaine précise ??
Si c'est bien cela, moi je ferais peut-être un WHERE NO EXIST :)

Exemple : Quel utilisateur n'est pas présent dans pointage
SELECT id_user, nom , prenom FROM users
    WHERE NOT EXISTS
        (SELECT *
            FROM pointage
            WHERE pointage.id_user = users.id_user
            AND pointage.semaine = 42 )
Si je ne me trompe pas elle va te sortir tous les utilisateurs qui ne se trouvent pas dans la table pointage de la semaine 42 :)
Mais j'ai peut-être pas capter l'idée :(
ImageCe que l'on apprend par l'effort reste toujours ancré beaucoup plus longtemps.