Sommes plus "filtrage"?

ViPHP
ViPHP | 3607 Messages

01 janv. 2009, 22:58

Bonsoir à tous,
Pardonnez mon titre peu explicite... mais je ne vois pas commetn expliquer le problème en trois mots :lol:
Je suis face à un petit problème... Un peu trop compliqué pour moi...
Pour une application intranet qui sert à compter les temps de fabrication des produits, je cherche à faire une requête un peu particulière...
Bon commençons par la structure des tables:

Code : Tout sélectionner

-- -- Structure de la table `actions` -- CREATE TABLE IF NOT EXISTS `actions` ( `id_action` int(10) unsigned NOT NULL auto_increment, `nom` varchar(50) collate utf8_unicode_ci NOT NULL, PRIMARY KEY (`id_action`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=6 ; -- -------------------------------------------------------- -- -- Structure de la table `actionsEmployes` -- CREATE TABLE IF NOT EXISTS `actionsEmployes` ( `id_actionsEmployes` int(10) unsigned NOT NULL auto_increment, `id_employe` int(10) unsigned NOT NULL, `id_action` int(10) unsigned NOT NULL, `date_debut` timestamp NOT NULL default '0000-00-00 00:00:00', `date_fin` timestamp NOT NULL default '0000-00-00 00:00:00', `BF` int(10) unsigned NOT NULL, PRIMARY KEY (`id_actionsEmployes`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=8 ; -- -------------------------------------------------------- -- -- Structure de la table `employes` -- CREATE TABLE IF NOT EXISTS `employes` ( `id_employe` int(10) unsigned NOT NULL auto_increment, `nom` varchar(50) collate utf8_unicode_ci NOT NULL, `prenom` varchar(50) collate utf8_unicode_ci NOT NULL, PRIMARY KEY (`id_employe`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=3 ;
Le shéma des tables est assez simple, on a des employes, des actions diverses, dont certaines ont un numéro de BF...
Bon je souhaiterais pouvoir afficher tout les enregistrements dont la date de début est égale à celle d'aujourd'hui, et dont le date de fin n'est pas renseigné... ça c'est bon, mais je souhaiterais en plus lorsque que l'on a un enregistrement comportant un numéro de BF obtenir le temps total passé dessus (quelque soit la date...)

Et c'est là que je bloque, j'ai pas l'impression que ce soit possible uniquement en SQL?
Et si c'est en php, ça va faire de trop gros traitements...

Bon voici la requête actuelle qui fonctionne (sans la dernière fonctionnalité):

Code : Tout sélectionner

SELECT ae.date_debut as date_debut, e.nom as nomEmploye, e.prenom as prenomEmploye, ae.BF as BF, a.nom as nomAction FROM actionsEmployes as ae JOIN employes as e ON ae.id_employe=e.id_employe LEFT JOIN actions as a ON ae.id_action=a.id_action WHERE DATE(date_debut)=CURDATE() AND ae.date_fin='0000-00-00 00:00:00'
et voici une requête qui calcul le temps total passé sur un BF donné

Code : Tout sélectionner

SELECT TIME(SUM(TIMEDIFF(ae.date_fin,ae.date_debut))) as tempTotal, ae.BF as BF FROM actionsEmployes as ae WHERE BF=245
Je ne sais pas s'il est possible d'imbriquer les deux étant donné que sur la première requête on filtre trop pour pouvoir faire nos sommes ensuite...

Voilà merci d'avance!!!

EDIT:
J'avance à tatons, voici ce que j'ai fait:

Code : Tout sélectionner

SELECT ae.date_debut as date_debut, TIME(SUM(TIMEDIFF(ae2.date_fin,ae2.date_debut))) as tempTotal, e.nom as nomEmploye, e.prenom as prenomEmploye, ae.BF as BF, a.nom as nomAction FROM actionsEmployes as ae JOIN employes as e ON ae.id_employe=e.id_employe LEFT JOIN actions as a ON ae.id_action=a.id_action JOIN actionsEmployes as ae2 ON ae2.BF<>0 WHERE DATE(ae.date_debut)=CURDATE() AND ae.date_fin='0000-00-00 00:00:00' GROUP BY ae.id_actionsEmployes
Mais ça ne fonctionne pas, puisque tempTotal vaut le temps passé sur toutes les actions (avec ou sans BF...)
Je doute de plus de la faisabilité "tout SQL"...
D'autres idées?

EDIT2:
J'ai crier hourra! ... trop tôt :(
Alors voici une requête qui marche dans un cas spécifique:

Code : Tout sélectionner

SELECT ae.date_debut AS date_debut, TIME( SUM( TIMEDIFF( ae2.date_fin, ae2.date_debut ) ) ) AS tempsTotal, e.nom AS nomEmploye, e.prenom AS prenomEmploye, ae.BF AS BF, a.nom AS nomAction FROM actionsEmployes AS ae JOIN employes AS e ON ae.id_employe = e.id_employe LEFT JOIN actions AS a ON ae.id_action = a.id_action LEFT JOIN actionsEmployes AS ae2 ON ae2.BF = ae.BF AND ae2.date_fin<>\'0000-00-00 00:00:00\' WHERE DATE( ae.date_debut ) = CURDATE( ) AND ae.date_fin = \'0000-00-00 00:00:00\' GROUP BY ae.id_actionsEmployes
Elle fonctionne seulement quand la table ne contient qu'une seule entrée correspondante (C.a.d. même BF et date_fin renseignée)
Dès qu'il y en a plusieurs... pfioute... plus rien!
On se rapproche on se rapproche, mais cest de plus en plus flou pour moi!

ViPHP
ViPHP | 5924 Messages

01 janv. 2009, 23:53

Ce n'est pas logique de se faire renvoyer un résultat pour un BF donné dans un cas, et pour un BF et une action donnée dans un autre cas… Je ne vois pas trop du coup ce que tu veux obtenir exactement…

Eléphant du PHP | 254 Messages

01 janv. 2009, 23:57

Salut,

J'ai lu en diagonal comme dirait Hywan :) mais peut etre que la fonction IF te donnerais une solution si il s'agit juste de mettre a null le tempTotal si le BF n'est pas renseigné dans ta derniere requete

ViPHP
ViPHP | 3607 Messages

01 janv. 2009, 23:59

Euh, je n'ai pas trop compris ce que tu ne trouves pas logique?
Peux tu t'expliquer un peu plus?

Sinon grande nouvelle, j'ai réussit à faire ce que je voulais avec une requête imbriquée:

Code : Tout sélectionner

SELECT ae.date_debut AS date_debut, ( SELECT TIME( SUM( TIMEDIFF( ae2.date_fin, ae2.date_debut ) ) ) FROM actionsEmployes AS ae2 WHERE ae2.BF = ae.BF AND ae2.date_fin <> '0000-00-00 00:00:00' ) AS tempsTotal, e.nom AS nomEmploye, e.prenom AS prenomEmploye, ae.BF AS BF, a.nom AS nomAction FROM actionsEmployes AS ae JOIN employes AS e ON ae.id_employe = e.id_employe LEFT JOIN actions AS a ON ae.id_action = a.id_action WHERE DATE( ae.date_debut ) = CURDATE( ) AND ae.date_fin = '0000-00-00 00:00:00' GROUP BY ae.id_actionsEmployes

Modérateur PHPfrance
Modérateur PHPfrance | 2575 Messages

02 janv. 2009, 00:05

Bonsoir et bonne annnée.

Primo, il faut savoir d'abord que les deux requêtes ne sont pas similaires car la première est programmée pour sélectionner les enregistrements dont la date de début est la date actuelle, alors que la seconde doit opérer sur toutes les dates. Donc, il ne faut pas espérer joindre les deux requêtes en une seule.

secundo, la première requête nécessite que la date de fin soit nulle (non renseignée) pour les enregistrements ayant une date égale à la date courante. Donc, le champ "date_fin" doit autoriser les valeurs nulles, alors que toi, tu l'a déclaré NOT NULL dans la structure de la table. Il faut enlever alors la contrainte NOT NULL.

Tertio, de même pour la seconde requête, il faut que le BF autorise les valeurs nulles car, comme tu dis, pour certains enregistrements le champ BF n'est pas renseigné. Il faut aussi enlever la contrainte NOT NULL sur ce champ dans la structure de la table.

Ce qui donnera ça:

Code : Tout sélectionner

CREATE TABLE IF NOT EXISTS `actionsEmployes` ( `id_actionsEmployes` int(10) unsigned NOT NULL auto_increment, `id_employe` int(10) unsigned NOT NULL, `id_action` int(10) unsigned NOT NULL, `date_debut` timestamp NOT NULL default '0000-00-00 00:00:00', `date_fin` timestamp, `BF` int(10) unsigned, PRIMARY KEY (`id_actionsEmployes`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=8 ;
Et finalement pour la seconde requête de sommation des différences de date de début et de fin, il faut ajouter un GROUP BY sur le champ "BF" que tu sélectionne dans le SELECT.

Une fois les requêtes sont bonnes, tu peux alors les imbriquer pour fusionner les résultats.
--------//////----//---//----//////
-------//---//----//---//----//---//
------//////----//////-----//////
-----||--------||--||---||
Prendre le recul n'est pas une perte de temps.


ps: Affrontez moi dans l'arène

ViPHP
ViPHP | 3607 Messages

02 janv. 2009, 00:13

Bonsoir,
Alors pour la structure de la table, je suis d'accord que c'est mieux comme tu le dis!
Vaut mieux tester une valeur nulle qu'un zero ou une date qui vaut zero...
Je vais faire le nécessaire!
Sinon pour ma requête (en changeant les null ou il faut...) c'est correct?
Faudrait concevoir la bdd autrement?
Merci encore ;)