PHP|Débutant :: Forums

Advertisement

Besoin d'aide ? N'hésitez pas, mais respectez les règles

Vous n'êtes pas identifié(e).

#1 17-11-2012 19:48:02

ebouilleur
Membre
Lieu : Nantes
Inscription : 19-05-2009
Messages : 165
Site Web

Requete SQL avec tri suivant le contenu de la requete

Bonjour,

J'ai essayer de faire un titre clair, mais pas sur que ce soit le cas ^^
En fait, j'ai besoin de faire une requete qui me permet d'afficher les factures qui n'ont pas été payées (ou pas complètement).
J'ai une table facture qui contient entre autre le montant que le client a deja payé.
Le prix de la facture n'existe pas tel quel. Il est obtenu a partir de la somme des cout des prestations lié a la facture (chaque prestation est dans la table prestation).

L'idée pour afficher les factures non payées est donc de comparer le prix payés par le client aux totales des couts des prestation.
Est ce que l'on peut faire ca en 1 requetes?

Voila ce que j'ai essayer de faire, tout en sachant que ca ne fonctionnerait pas...


SELECT f.id_facture, f.numero_facture, f.date_facture, f.date_payement, f.montant_paye, c.nom, c.ville, c.societe, SUM( (
          p.prix_htva + ( (p.prix_htva * p.tva) /100 ) ) * p.quantite) AS prixFacture
        FROM fact_facture f
        LEFT OUTER JOIN fact_client c ON ( f.id_client = c.id_client )
        LEFT OUTER JOIN fact_prestation p ON ( f.id_facture = p.id_facture )
        WHERE f.id_membre=$sess_id_pseudo AND f.montant_paye<prixFacture GROUP BY f.id_facture ORDER BY date_facture LIMIT $limite,$nombre
 

Merci pour vos idées

Hors ligne

#2 17-11-2012 23:07:46

Maljuna Kris
Infantimigulo
Lieu : Douarnenez 29100 Breizh Izel
Inscription : 08-05-2009
Messages : 2 453
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Saluton,
Bon, tu y étais "presque".
Tu conviendras aisément avec moi qu'une facture sans client n'a pas de raison d'être, donc la jointure externe vers la table fact_client doit être remplacée par une jointure interne.
Mais ce n'est pas ce qui empêche ta requête d'aboutir.
prixfacture est le résultat d'une fonction d'agrégation SUM dont le résultat ne peut être inféré dans la clause WHERE mais seulement après le GROUP BY.
Pour ce faire il existe une clause HAVING.

SELECT f.id_facture,
       f.numero_facture,
       f.date_facture,
       f.date_payement,
       f.montant_paye,
       c.nom,
       c.ville,
       c.societe,
       SUM(( p.prix_htva + ( (p.prix_htva * p.tva) /100 ) ) * p.quantite) AS prixFacture
FROM fact_facture f
INNER JOIN fact_client c ON ( f.id_client = c.id_client )
LEFT OUTER JOIN fact_prestation p ON ( f.id_facture = p.id_facture )
WHERE f.id_membre=$sess_id_pseudo
GROUP BY f.id_facture
HAVING f.montant_paye < prixFacture
ORDER BY date_facture
LIMIT $limite,$nombre

Ça devrait aller mieux comme cela.


Gloire à qui n'ayant pas d'idéal sacro-saint,
Se borne à ne pas trop emmerder ses voisins. G. Brassens Don Juan 1976.
Avĉjo MoKo kantas
La chaîne YouTube MoKo Papy

Hors ligne

#3 18-11-2012 13:37:31

ebouilleur
Membre
Lieu : Nantes
Inscription : 19-05-2009
Messages : 165
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Ah oui c'est vrai, le having smile
Je ne l'utilise jamais (a tort peut etre)
Merci je vais tester ca (et merci pr les petites astuces/infos)

Hors ligne

#4 28-11-2012 22:43:37

ebouilleur
Membre
Lieu : Nantes
Inscription : 19-05-2009
Messages : 165
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Je reviens avec une autre question sur une requete similaire :


SELECT f.id_facture, f.numero_facture, f.date_facture, f.date_payement, f.montant_paye, c.nom, c.ville, c.societe, sum( (
          p.prix_htva + ( (p.prix_htva * p.tva) /100 ) ) * p.quantite) AS prixFacture,
          date_send_fact, date_send_doc
        FROM fact_facture f
        INNER JOIN fact_client c ON ( f.id_client = c.id_client )
        LEFT OUTER JOIN fact_prestation p ON ( f.id_facture = p.id_facture )
        LEFT OUTER JOIN fact_suivi s ON ( f.id_facture = s.id_facture )
        WHERE f.date_payement='0000-00-00'
        GROUP BY f.id_facture
        ORDER BY $order_by $order_dir limit $limite,$nombre
 

La requete fonctionne bien, cependant, j'aimerais afficher que les résultats qui pour date "date_send_fact" et "date_send_doc" vide
Facile me direz vous, mais non, car ces champs sont des la tables fact_suivi et il est possible qu'il n'existe pas... et si il n'y a pas d'enregistrement il ne me les affiches pas (alors que si ils sont vides ou inexistant, pour moi c'est la meme chose)

Une idée svp?
Merci
Yves

Hors ligne

#5 29-11-2012 06:48:36

Maljuna Kris
Infantimigulo
Lieu : Douarnenez 29100 Breizh Izel
Inscription : 08-05-2009
Messages : 2 453
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Saluton,
Il faudrait savoir ce qui est prévu comme valeur par défaut dans ces colonnes.
En fait, j'ai besoin de savoir ce qu'elles contiennent lorsqu'elles sont vides. lol
Il faudrait aussi que tu me dises dans quel(s) cas elles peuvent ne pas exister.
Amike.


Gloire à qui n'ayant pas d'idéal sacro-saint,
Se borne à ne pas trop emmerder ses voisins. G. Brassens Don Juan 1976.
Avĉjo MoKo kantas
La chaîne YouTube MoKo Papy

Hors ligne

#6 29-11-2012 09:22:02

ebouilleur
Membre
Lieu : Nantes
Inscription : 19-05-2009
Messages : 165
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

En fait c'est un table qui permet de faire le suivi d'une facture.
Elle contient des informations comme : date d'envoi de la facture, méthode d'envoi, a qui elle a été envoyé, date d'envoi du doc complémentaire, etc...
L'enregistrement correspondant a une facture n'existe qu'a partir du moment ou le membre a renseigné (via un formulaire) l'une de ses informations (cad qu'il a déja commencer a faire le suivi).
"date_send_fact" et "date_send_doc" sont au format varchar(10).
DOnc en faite, ce que je veux faire, c'est afficher un tableau qui contient les informations suivante :
numéro de facture, la date d'envoie de la facture, la date de payement (contenu dans la table facture donc pas de soucis) et la date d'envoi du doc

Mais si les 3 champs date contiennent qqchose (ce qui veut donc dire que le suivi est complet), il n'est pas necessaire d'afficher la ligne de la facture.
Est ce que je suis plus clair?
Merci

Hors ligne

#7 29-11-2012 11:47:38

Jc
Membre
Lieu : Zillisheim - Alsace
Inscription : 15-04-2010
Messages : 1 629
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

bonjour,

permet moi de reformuler ton besoin histoire dêtre certain d'avoir bien compris tu as besoin d'afficher les factures initiées non payées et/ou les factures dont le doc n'a pas été envoyé.

Si c'est bien ça et si il ne peut y avoir de doc envoyé tant qu'elle n'est pas payée dans les procédures de l'entreprise concernée, il suffit de faire le test sur la date d'envoi du doc. Si la date est NULL et que la date d'envoi est NOT NULL, alors on affiche.

J'espère avoir pu t'aider.

++


POO PHP+Ajax en MVC avec PDO et Bases de données épaisses  : What else?

Hors ligne

#8 29-11-2012 12:30:01

ebouilleur
Membre
Lieu : Nantes
Inscription : 19-05-2009
Messages : 165
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Humm tu me donnes des idées, faudrait tester.
Mais ce que je voulais faire, c'est lister toutes les factures pour lesquelles une ou plusieurs étapes n'avaient pas été faite et donc avoir une requete du genre :


SELECT f.id_facture, f.numero_facture, f.date_facture, f.date_payement, f.montant_paye, c.nom, c.ville, c.societe, sum( (
          p.prix_htva + ( (p.prix_htva * p.tva) /100 ) ) * p.quantite) AS prixFacture,
          s.date_send_fact, s.date_send_doc
        FROM fact_facture f
        INNER JOIN fact_client c ON ( f.id_client = c.id_client )
        LEFT OUTER JOIN fact_prestation p ON ( f.id_facture = p.id_facture )
        LEFT OUTER JOIN fact_suivi s ON ( f.id_facture = s.id_facture )
        WHERE f.date_payement='0000-00-00' OR s.date_send_fact='' OR s.date_send_doc=''
        GROUP BY f.id_facture
        ORDER BY $order_by $order_dir limit $limite,$nombre
 

Mais si la facture n'a pas d'enregistrement dans la table fact_suivi, ca ne me ressort rien du coup..

Hors ligne

#9 29-11-2012 18:44:10

Maljuna Kris
Infantimigulo
Lieu : Douarnenez 29100 Breizh Izel
Inscription : 08-05-2009
Messages : 2 453
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

ebouilleur a écrit :

Mais si la facture n'a pas d'enregistrement dans la table fact_suivi, ca ne me ressort rien du coup..

Avec les jointures externes (LEFT JOIN) qui partent de la table facture, tu dois récupérer toutes les factures, qu'elles aient ou non d'enregistrement dans la table fact-suivi.
Si ce n'est pas le cas c'est que tes clauses WHERE ou HAVING sont trop restrictives.


Gloire à qui n'ayant pas d'idéal sacro-saint,
Se borne à ne pas trop emmerder ses voisins. G. Brassens Don Juan 1976.
Avĉjo MoKo kantas
La chaîne YouTube MoKo Papy

Hors ligne

#10 06-12-2012 01:53:41

Jc
Membre
Lieu : Zillisheim - Alsace
Inscription : 15-04-2010
Messages : 1 629
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

c'est lister toutes les factures pour lesquelles une ou plusieurs étapes n'avaient pas été faite

On en revient toujours au même, quand on est laxiste sur les processes d'entreprise, on en revient à perdre la consistence des données de l'entreprise, et c'est le début de la fin.
Les CMS ont encore de beaux jours devant eux, moi je vous l'dit !!!


POO PHP+Ajax en MVC avec PDO et Bases de données épaisses  : What else?

Hors ligne

#11 12-12-2012 21:04:42

ebouilleur
Membre
Lieu : Nantes
Inscription : 19-05-2009
Messages : 165
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Bonsoir smile
Je reviens avec ma requête fini.. enfin je croyais sad
Elle fonctionne, pas d'erreur, mais les valeurs obtenu pour prixFacture ne sont pas correctes.
Voici la requête :


SELECT f.id_facture, f.numero_facture, f.date_facture, f.date_payement, f.montant_paye, c.nom, c.ville, c.societe, SUM( (
          p.prix_htva + ( (p.prix_htva * p.tva) /100 ) ) * p.quantite) AS prixFacture,  
          MAX(CASE WHEN s1.TYPE = '1' THEN date_send END) AS date_send_fact,
          MAX(CASE WHEN s1.TYPE = '2' THEN date_send END) AS date_send_doc
FROM fact_facture f
INNER JOIN fact_client c ON ( f.id_client = c.id_client )
LEFT OUTER JOIN fact_prestation p ON ( f.id_facture = p.id_facture )
LEFT OUTER JOIN fact_suivi s1 ON ( f.id_facture = s1.id_facture )  
GROUP BY f.id_facture
HAVING f.montant_paye<prixFacture OR date_send_fact IS NULL OR date_send_doc IS NULL
 

J'ai des valeurs bizarre (et pour le moment inexpliqué) pour prixFacture.
Si je simplifie la requête a ça, je n'ai plus de soucis :


SELECT f.id_facture, f.numero_facture, f.date_facture, f.date_payement, f.montant_paye, c.nom, c.ville, c.societe, SUM( (
          p.prix_htva + ( (p.prix_htva * p.tva) /100 ) ) * p.quantite) AS prixFacture
FROM fact_facture f
INNER JOIN fact_client c ON ( f.id_client = c.id_client )
LEFT OUTER JOIN fact_prestation p ON ( f.id_facture = p.id_facture )
GROUP BY f.id_facture
HAVING f.montant_paye<prixFacture
 

Mais ce n'est pas ce que j'ai besoin... une idée de ce qu'il se passe? On dirait que la requete boucle ce qui fait grimper la valeur de prixFacture

Merci pour votre aide
Yves

Dernière modification par ebouilleur (12-12-2012 21:06:00)

Hors ligne

#12 13-12-2012 05:16:16

Jc
Membre
Lieu : Zillisheim - Alsace
Inscription : 15-04-2010
Messages : 1 629
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Bonjour,

La première chose que j'allais te dire après avoir lu tes requêtes c'est qu'on a déjà évoqué ce problème dans ton premier post sur ce forum à savoir qu'il faut remettre la fonction d'agrégation dans le HAVING pour prixFacture au lieu de son alias. Mais lorsque tu dis

"On dirait que la requête boucle ce qui fait grimper la valeur de prixFacture", je ne suis plus certain de la nature de ton problème en fait.
Tu pourrais nous dire ce que tu obtiens concrètement et ce que tu devrais obtenir sur 1 ou 2 lignes d'exemple ?

De plus ton HAVING dans ta première requête ne corresponds pas au cahier des charges de ta requête.

10.HAVING f.montant_paye<prixFacture OR date_send_fact IS NULL OR date_send_doc IS NULL

En effet
1) f.montant_paye < prixFacture n'exclue pas le montant_paye =0 ce qui sort du contexte souhaité
2) le OR appliqué à la fois sur date_send_fact IS NULL OR date_send_doc IS_NULL non seulement n'exclue pas f.montant_paye=0 mais même si montant_paye=0 a été exclu dans la première condition, cette partie la rendrait à nouveau inclusive.
3) il te faudrait plutôt un


HAVING (f.montant_paye >0 AND f.montant_paye <= prixFacture) AND (date_send_fact IS NULL OR date_send_doc IS NULL)
 

Tu remarqueras aussi le inférieur ou égal car la facture soldée rentre aussi dans le CDC que tu as exprimé, et normalement en n'oubliant pas de remplacer l'alias par la fonction d'agrégation.

Merci smile

Dernière modification par Jc (13-12-2012 05:26:52)


POO PHP+Ajax en MVC avec PDO et Bases de données épaisses  : What else?

Hors ligne

#13 13-12-2012 10:10:50

ebouilleur
Membre
Lieu : Nantes
Inscription : 19-05-2009
Messages : 165
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Salut,

Dans mon 1er post, Kris me disait juste de mettre f.montant_paye <= prixFacture dans le having à la place du where, mais il ne me disait pas de mettre SUM( (p.prix_htva + ( (p.prix_htva * p.tva) /100 ) ) * p.quantite) à la place de prixFacture, enfin si j'ai bien compris.

Donc ça donnerai la requête suivante :


    SELECT f.id_facture, f.numero_facture, f.date_facture, f.date_payement, f.montant_paye, c.nom, c.ville, c.societe, SUM( (
    p.prix_htva + ( (p.prix_htva * p.tva) /100 ) ) * p.quantite) AS prixFacture,
    MAX(CASE WHEN s1.TYPE = '1' THEN date_send END) AS date_send_fact,
    MAX(CASE WHEN s1.TYPE = '2' THEN date_send END) AS date_send_doc
    FROM fact_facture f
    INNER JOIN fact_client c ON ( f.id_client = c.id_client )
    LEFT OUTER JOIN fact_prestation p ON ( f.id_facture = p.id_facture )
    LEFT OUTER JOIN fact_suivi s1 ON ( f.id_facture = s1.id_facture )
    GROUP BY f.id_facture
    HAVING f.montant_paye<SUM( (p.prix_htva + ( (p.prix_htva * p.tva) /100 ) ) * p.quantite) OR date_send_fact IS NULL OR date_send_doc IS NULL
 

Pour mon having, j'ai du mal a comprendre ta proposition, car j'ai besoin de voir toutes les factures dont au moins 1 des 3 actions (payement, envoie de facture et envoie de doc) ne sont pas effectuées. Donc si le client n'a rien payé, ça doit être listé alors que si je met (f.montant_paye >0 AND f.montant_paye <= prixFacture) ca ne listera rien, non?

Pour visualisé un peu mon tableau d'affichage, ca donne qqchose du genre :

Facture    Payé   Facture envoyé     Doc envoyé
31             OK             OK                   NOK
13             OK             NOK                 NOK
58             NOK           NOK                  NOK 

Sinon voici une exemple de résultat de la requête actuelle :
id_facture                montant_paye             prixFacture                     date_send_fact              date_send_doc
31                               716.00                  2860.260920000000             2012-12-09          2012-12-09
13                                   12.00                  7.260000000000                        2012-12-01             NULL

Et ce que je devrais avoir :
31                               716.00                  715.065230000000             2012-12-09          2012-12-09
13                                   12.00                  2.420000000000                        2012-12-01             NULL


Voila,
Merci

Hors ligne

#14 14-12-2012 02:16:37

Jc
Membre
Lieu : Zillisheim - Alsace
Inscription : 15-04-2010
Messages : 1 629
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Bonsoir,

Je vais faire un petit rappel pour aide mémoire.

Quand le moteur de base de données doit parser la requête, il faut savoir que la clause SELECT est évaluée en dernier, et donc après les clauses FROM, WHERE, GROUP BY et HAVING (dans l'ordre). Ainsi les alias définis dans la clause SELECT sont inconnus au moment de l'évaluation des mêmes clauses.

Ensuite pour les alias je te recommande d'utiliser le mot clé AS systématiquement, car c'est une source d'erreur fréquente et difficile à déboguer surtout dans les requêtes complexes

Imagine par exemple que tu oublies une simple virgule en écrivant SELECT order_id order_date FROM orders ne retournera pas d'erreur mais order_date sera considéré comme un alias de order_id et donc une seule colonne sera affichée.

En plus je n'ai pas vérifié mais je crois que MySQL ne supporte pas l'absence de mot clé AS (l'ayant toujours mis en fait).

Pour ce qui est de l'obligation de répéter des formules un peu longues dans les clauses WHERE et HAVING, elles sont reconnues par l'optimiseur et sont évaluées qu'une seule fois contrairement à ce que l'on pourrait penser. Du moins sur SQL Server c'est certain à 100%, j'ai pas vérifié dans la doc MySQL^^.

Si tu veux éviter de te retaper 10 fois le calcul à la main dans ta requête, la solution peut être de créer une requête dérivée intégrant les calculs, ainsi il est possible d'y faire référence à l'extérieur via un alias (la clause FROM étant évaluée en premier).

Pour ton problème d'expression dans ton HAVING, excuse moi mais ton besoin précis ne m'apparaît pas clairement sad

Dernière modification par Jc (22-06-2013 17:18:47)


POO PHP+Ajax en MVC avec PDO et Bases de données épaisses  : What else?

Hors ligne

#15 14-12-2012 09:38:15

ebouilleur
Membre
Lieu : Nantes
Inscription : 19-05-2009
Messages : 165
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Merci pour ton aide mémoire wink

Pour le AS c'est vrai que je le met quasiment toujours, même si là je l'ai oublié pour les tables. Sinon, si mysql gère aussi quand tu ne met pas le AS, mais j'aime bien le mettre, c'est plus clair au niveau du code, je suis d'accord.

Donc ca donnerai :


    SELECT f.id_facture, f.numero_facture, f.date_facture, f.date_payement, f.montant_paye, c.nom, c.ville, c.societe, SUM( (
    p.prix_htva + ( (p.prix_htva * p.tva) /100 ) ) * p.quantite) AS prixFacture,
    MAX(CASE WHEN s1.TYPE = '1' THEN date_send END) AS date_send_fact,
    MAX(CASE WHEN s1.TYPE = '2' THEN date_send END) AS date_send_doc
    FROM fact_facture AS f
    INNER JOIN fact_client AS c ON ( f.id_client = c.id_client )
    LEFT OUTER JOIN fact_prestation AS p ON ( f.id_facture = p.id_facture )
    LEFT OUTER JOIN fact_suivi AS s1 ON ( f.id_facture = s1.id_facture )
    GROUP BY f.id_facture
    HAVING f.montant_paye<SUM( (p.prix_htva + ( (p.prix_htva * p.tva) /100 ) ) * p.quantite) OR date_send_fact IS NULL OR date_send_doc IS NULL
 

Pour le HAVING et ce que je souhaite, c'est simple pourtant, disons que ce tableau de suivi de facture permet de :
- voir si la facture a été envoyé
- ou voir le le doc a été envoyé
- ou voir si la facture a été payé

Mais que ce soit le "problème" de AS ou de Having, le résultat de prixFacture bizarre ne s'explique pas
(pour info j'ai aussi tester ma requête sans le having, et prixFacture est tjs aussi bizarre)

Edit :
Par contre, après d'autres tests, j'ai remarqué que si dans ma table fact_suivi, je n'ai aucun enregistrement, ou 1 seul, la valeur de prixFacture sera bonne, et elle devient fausse quand j'ai 2 ou plus d'enregistrement. (pour 2 enregistrement, prixFacture est en fait le double de la valeur qu'il devrait avoir)

Dernière modification par ebouilleur (14-12-2012 10:16:04)

Hors ligne

#16 14-12-2012 15:57:29

Jc
Membre
Lieu : Zillisheim - Alsace
Inscription : 15-04-2010
Messages : 1 629
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

smile

Oui comme ça je comprends mieux. En fait ton regroupement sur id_facture tu le fais sur la table fact_facture, alors que cette table n'est censée contenir qu'une seule référence à chaque facture, (ou une référence par paiement ?) si j'ai bien compris.
Tu as deux agrégations à faire, celle du calcul du montant de la facture dans la table fact_suivi qui je pense doit être faite dans une requête dérivée justement, et si tu as qu'une seule référence facture dans fact_facture alors tu reprends la même requête et ca doit être bon, sinon dans le cas où tu as une référence par paiement partiel, tu refais l'agrégation sur le montant payé dans ta requête principale.

Si c'est pas tout à fait ça et que ca ne te suffit pas, donne moi l'analyse fonctionnelle des tables et leur structure ca aidera wink

Dernière modification par Jc (14-12-2012 15:58:21)


POO PHP+Ajax en MVC avec PDO et Bases de données épaisses  : What else?

Hors ligne

#17 14-12-2012 16:14:15

ebouilleur
Membre
Lieu : Nantes
Inscription : 19-05-2009
Messages : 165
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Oui la table fact_facture ne contient qu'1 seul enregistrement par facture.
Pour le reste j'ai pas tout compris, donc je colle mes table pour déjà etre sur que tu es sur la bonne voie wink


CREATE TABLE IF NOT EXISTS `fact_facture` (
  `id_facture` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `id_client` INT(11) NOT NULL,
  `id_membre` INT(11) NOT NULL,
  `numero_facture` VARCHAR(15) NOT NULL,
  `date_facture` DATE NOT NULL,
  `date_echeance` DATE NOT NULL,
  `date_payement` DATE NOT NULL,
  `montant_paye` DECIMAL(10,2) UNSIGNED NOT NULL,
  `provenance` VARCHAR(40) NOT NULL,
  `prestataire` VARCHAR(40) NOT NULL,
  `note` text NOT NULL,
  `date_creation` DATE NOT NULL,
  UNIQUE KEY `id_facture` (`id_facture`),
  KEY `id_client` (`id_client`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=34 ;

CREATE TABLE IF NOT EXISTS `fact_prestation` (
  `id_prestation` INT(11) NOT NULL AUTO_INCREMENT,
  `id_facture` INT(11) NOT NULL,
  `type` tinyint(3) UNSIGNED NOT NULL,
  `autre` text NOT NULL,
  `date_prestation` DATE NOT NULL,
  `adresse` text NOT NULL,
  `cp` INT(10) NOT NULL,
  `ville` VARCHAR(50) NOT NULL,
  `pays` VARCHAR(50) NOT NULL,
  `quantite` DECIMAL(6,4) NOT NULL,
  `prix_htva` DECIMAL(10,4) NOT NULL,
  `tva` tinyint(4) NOT NULL,
  UNIQUE KEY `id_prestation` (`id_prestation`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;


CREATE TABLE IF NOT EXISTS `fact_suivi` (
  `id_suivi` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `id_facture` INT(10) UNSIGNED NOT NULL,
  `date_send` VARCHAR(10) NOT NULL,
  `who_send` VARCHAR(50) NOT NULL,
  `how_send` VARCHAR(50) NOT NULL,
  `type` tinyint(3) UNSIGNED NOT NULL,
  UNIQUE KEY `id_suivi` (`id_suivi`),
  KEY `id_facture` (`id_facture`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=29 ;
 

voilà...

Hors ligne

#18 14-12-2012 21:54:03

Jc
Membre
Lieu : Zillisheim - Alsace
Inscription : 15-04-2010
Messages : 1 629
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete


SELECT f.id_facture, f.numero_facture, f.date_facture, f.date_payement, f.montant_paye, c.nom, c.ville, c.societe, t.prixFacture,
     MAX(CASE WHEN s1.TYPE = 1 THEN date_send END) AS date_send_fact,
     MAX(CASE WHEN s1.TYPE = 2 THEN date_send END) AS date_send_doc
FROM fact_facture AS f
INNER JOIN fact_client AS c ON f.id_client = c.id_client
LEFT JOIN fact_suivi AS s1 ON f.id_facture = s1.id_facture
LEFT JOIN (SELECT id_facture, SUM(prix_htva + (((prix_htva * tva) /100) * quantite)) AS prixFacture
                 FROM fact_prestation
                 GROUP BY id_facture) AS t ON f.id_facture=t.id_facture
WHERE f.montant_paye < t.prixFacture OR date_send_fact IS NULL OR date_send_doc IS NULL
 

Essaye ça pour voir.

PS: Encore une BD qui a été modélisée à l'arrache sad

Dernière modification par Jc (15-12-2012 00:29:26)


POO PHP+Ajax en MVC avec PDO et Bases de données épaisses  : What else?

Hors ligne

#19 14-12-2012 22:20:09

ebouilleur
Membre
Lieu : Nantes
Inscription : 19-05-2009
Messages : 165
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Ah... ca te plait pas comme bdd? qu'est ce qui te convient pas? qu'est ce qui doit être amélioré?

La requete telle qu'elle ne passe pas, il ne connais pas date_send_fact et date_send_doc dans le where. En remplacant le where par un having, ca passe sans erreur, mais ca ne ressort qu'une ligne... je fais des tests, mais j'arrive pas a adapté ta requête pour qu'elle ressorte ce que j'ai besoin, je continu

Dernière modification par ebouilleur (14-12-2012 23:23:26)

Hors ligne

#20 15-12-2012 00:31:44

Jc
Membre
Lieu : Zillisheim - Alsace
Inscription : 15-04-2010
Messages : 1 629
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete


SELECT f.id_facture, f.numero_facture, f.date_facture, f.date_payement, f.montant_paye, c.nom, c.ville, c.societe, t.prixFacture,
     CASE WHEN s1.TYPE = 1 THEN date_send END AS date_send_fact,
     CASE WHEN s1.TYPE = 2 THEN date_send END AS date_send_doc
FROM fact_facture AS f
INNER JOIN fact_client AS c ON f.id_client = c.id_client
LEFT JOIN fact_suivi AS s1 ON f.id_facture = s1.id_facture
LEFT JOIN (SELECT id_facture, SUM(prix_htva + (((prix_htva * tva) /100) * quantite)) AS prixFacture
                 FROM fact_prestation
                 GROUP BY id_facture) AS t ON f.id_facture=t.id_facture
WHERE f.montant_paye < t.prixFacture OR date_send IS NULL
ORDER BY date_send DESC
 

La ligne unique venait du MAX...
Mais du coup, en essayant de comprendre la pertinence de ton MAX, je pense qu'il va falloir faire une requête dérivée au niveau du suivi pour retomber sur nos pattes car cela sous entend qu'il y a plusieurs suivis pour une même facture avec des dates d'envoi différentes... D'où l'ajout ici du ORDER BY, mais cela ne suffira pas.
En plus tes CASE... WHEN sont peu pertinents un simple date_send suffit avec l'information du type pour gérer l'affichage.


SELECT f.id_facture, f.numero_facture, f.date_facture, f.date_payement, f.montant_paye, c.nom, c.ville, c.societe, t.prixFacture, s1.TYPE, s1.date_send
FROM fact_facture AS f
INNER JOIN fact_client AS c ON f.id_client = c.id_client
LEFT JOIN fact_suivi AS s1 ON f.id_facture = s1.id_facture
LEFT JOIN (SELECT id_facture, SUM(prix_htva + (((prix_htva * tva) /100) * quantite)) AS prixFacture
                 FROM fact_prestation
                 GROUP BY id_facture) AS t ON f.id_facture=t.id_facture
WHERE f.montant_paye < t.prixFacture OR date_send IS NULL
ORDER BY date_send DESC
 

sera plus pertinent et plus performant, sutout en MyISAM...

Dernière modification par Jc (15-12-2012 00:43:18)


POO PHP+Ajax en MVC avec PDO et Bases de données épaisses  : What else?

Hors ligne

#21 15-12-2012 01:08:30

ebouilleur
Membre
Lieu : Nantes
Inscription : 19-05-2009
Messages : 165
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Oui il y a avoir plusieurs enregistrement dans la table suivi pour la meme facture (en principe quand c tout bien fait il y a a minimum 2 ligne : 1 facture et 1 doc). Si il y a 4 envoie de doc, c'est comme si il y en avait que 1 seul. 1 ou plus c'est quand meme 1 ^^

Humm j'ai du mal a saisir ta 2eme requete. Il est possible que le MAX n'était pas très utile, mais la impossible d'avoir l'information de la date d'envoie de ma facture (s1.type=1) et en meme temps la date d'envoie du doc (s1.type=2)

J'en profite pour te glisser le code d'affichage du résultat de la requete :


<table align="center" width="100%" cellpadding="0" cellspacing="0" class="">       
  <tr align="center">
    <td class="about">
    <b><?php echo sort_link('N° Factures', 'id_facture') ?></b>
    </td>  
    <td class="about">
    <b>Facture envoyée</b>
    </td>
    <td class="about">
    <b>Payement reçu</b>
    </td>    
    <td class="about">
    <b>PEB envoyé</b>
    </td>  
    <td class="about">
    <b><?php echo sort_link('Date Facture', 'date_facture') ?></b>    
    </td>                          
  </tr>  
  <?php
  while($var_news = mysql_fetch_array($req)) {   
  ?> 
  <tr class="topjoueur" onmouseover="this.className='topjoueur2';" onMouseOut="this.className='topjoueur';" align="center">
    <td class="">
    <?php
    $date_du_jour = date('Y-m-d');
    //if (date_diff($var_news['date_facture'], $date_du_jour) > 240 ) $style=' style="color:#FF0000" ';
    ?>
    <a href='m_facture_suivi.php?id_facture=<?php echo $var_news['id_facture'];?>'>
      <span <?php echo $style; ?>><?php echo $var_news['numero_facture']; ?></span>
    </a> 
    </td>
    <td>
    <?php if(!empty($var_news['date_send_fact'])) {echo "<img src='images/OK.png' />"; }else{ echo "<img src='images/No.png' />";} ?>
    </td>      
    <td>
    <?php if($var_news['montant_paye']>=$var_news['prixFacture']) {echo "<img src='images/OK.png' />"; }else{ echo "<img src='images/No.png' />";} ?>
    </td>  
    <td>
    <?php if(!empty($var_news['date_send_doc'])) {echo "<img src='images/OK.png' />"; }else{ echo "<img src='images/No.png' />";} ?> 
    </td>
    <td>
    <?php echo convert_date_us2fr($var_news['date_facture']); ?> 
    </td>                  
  </tr>
  <?php $style=''; } ?>                                          
</table>
 

je vais au lit wink
Bye

Hors ligne

#22 15-12-2012 01:21:16

Jc
Membre
Lieu : Zillisheim - Alsace
Inscription : 15-04-2010
Messages : 1 629
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Bonsoir,

Avant de te répondre sur ton dernier post, je vais te répondre concernant ta base de données

- Elle n'est pas normalisée 3FN minimum
- Elle est en MyISAM et donc les contraintes de clé étrangères sont inopérantes et les performances ne seront pas au rendez-vous, surtout que des indexs ont été oubliés de manière à les rendre efficaces et d'autant plus en MyISAM.
- Tes contraintes de domaine ne sont pas standardisées, ainsi on se retrouve par exemple avec un id_facture sur fact_facture défini en INT UNSIGNED NOT NULL et un id_facture en INT NOT NULL sur fact_prestation, rendant ainsi les jointures inopérantes (fulls scans en perspective), date en VARCHAR, etc...

Sinon c'est bien ce qu'il me semblait il va falloir passer par des requêtes dérivées pour gérer tes dates. Dis-moi, tu as un seul enregistrement par facture et par type de suivi dans la table fact_suivi? Je te pose la question quand même, car normalement la réponse devrait être non si ton MAX était pertinent, mais n'ayant aucune certitude...

Dernière modification par Jc (15-12-2012 01:24:55)


POO PHP+Ajax en MVC avec PDO et Bases de données épaisses  : What else?

Hors ligne

#23 15-12-2012 09:56:30

ebouilleur
Membre
Lieu : Nantes
Inscription : 19-05-2009
Messages : 165
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Oula, il y a des termes que je lis pour la 1ere fois hmm je vais aller me documenter un peu...

Et pour ta question :
- dans la table fact_facture : OUI 1 seul enregistrement par facture
- dans la table fact_suivi : NON, pas toujours. En principe il doit y avoir au minimum 2 enregistrements (1 pour la facture et 1 pour le doc), mais il est possible (dans 20% des cas) de trouver plusieurs ligne pour le doc (ou la facture) si celui-ci a été envoyé plusieurs fois (pour plusieurs personne par exemple)
Merci

Hors ligne

#24 15-12-2012 18:11:43

Jc
Membre
Lieu : Zillisheim - Alsace
Inscription : 15-04-2010
Messages : 1 629
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

Bonjour,

C'est bien ce qui me semblait.
Tu es victime pour ta requête de ton absence de modélisation correcte car ta table suivi est redondante donc dénormalisée. Il ne faut pas confondre la gestion des statuts de tes factures, et la gestion des logs action sur les factures émises. Dans ta modélisation actuelle donc, quel est le critère qui doit être retenu en interne pour dire parmi x dates d'envoi quel est la date qui doit être considérée comme étant la date d'envoi officielle pour la facture? Si c'est la dernière, ton MAX est justifié, si c'est la première, ton MAX est faux. Si en interne il suffit de vérifier qu'une date d'envoi existe pour dire qu'elle a été envoyée, alors tu peux t'en sortir avec ta modélisation actuelle et adapter ta requête en conséquence. Sinon tu es dans une impasse fonctionnelle, sauf si c'est l'envoi à une personne particulière qui donne date certaine à l'envoi de la facture.

Bon week-end.

Dernière modification par Jc (15-12-2012 18:16:10)


POO PHP+Ajax en MVC avec PDO et Bases de données épaisses  : What else?

Hors ligne

#25 15-12-2012 18:31:08

Jc
Membre
Lieu : Zillisheim - Alsace
Inscription : 15-04-2010
Messages : 1 629
Site Web

Re : Requete SQL avec tri suivant le contenu de la requete

ebouilleur a écrit :

Oula, il y a des termes que je lis pour la 1ere fois hmm je vais aller me documenter un peu...

Ah bon? il me semble pourtant que MK dans un autre post t'as répondu ceci

Maljuna Kris a écrit :

Étant moi-même assez partisan des SGBD "épais" je t'engage à favoriser la résolution de ce type de problème plutôt en amont de PHP.
Cela sous-entend, bien-entendu, d'avoir optimisé la base de données (choix des types de colonnes, des index, modélisation au plus près des formes normales, contraintes d'intégrité, etc...)

et que rien dans ta réaction ne semblait laisser penser que se sont des notions qui t'étaient étrangères

hmm

Dernière modification par Jc (15-12-2012 18:32:24)


POO PHP+Ajax en MVC avec PDO et Bases de données épaisses  : What else?

Hors ligne

Pied de page des forums