Lier plusieurs requêtes imbriquées entre elles

Résolu
Bonjour à tous,

J'ai écrit plusieurs requêtes qui fonctionnent bien indépendamment les unes des autres et j'aimerai
savoir comment faire pour les regrouper en une seule ? ou si je dois lancer 3 commandes séparées en php ?
(Je n'ai pas les connaissances suffisantes pour les regrouper sans tout faire planter)

Les voici :
1. Récupération du client, de la date de début de son contrat, son N° de contrat et du total de ses prestations restauration :
SELECT CLIENT,T.date_debut,T.id_contrat, SUM(T.TABLE_HOTES)
FROM (SELECT contrats.id_contrat, contrats.date_debut,CONCAT(clients.nom,' ',clients.prenom) AS CLIENT, compositions.prix*compositions.quantites AS TABLE_HOTES
      FROM compositions
      INNER JOIN contrats ON contrats.id_contrat = compositions.id_contrat
      INNER JOIN clients ON clients.id_client = contrats.id_client      
      INNER JOIN prestations ON prestations.id_prestation = compositions.id_prestation
      WHERE prestations.type = 3)AS T
      GROUP BY T.id_contrat


2. Récupération du n° de contrat et du total des prestations dans le bâtiment 1
SELECT contrats.id_contrat, compositions.prix*compositions.quantites AS VILLAGE
      FROM compositions
      INNER JOIN contrats ON contrats.id_contrat = compositions.id_contrat
      INNER JOIN clients ON clients.id_client = contrats.id_client      
      INNER JOIN prestations ON prestations.id_prestation = compositions.id_prestation
      WHERE prestations.type = 1
      GROUP BY contrats.id_contrat


3. Récupération du n° de contrat et du total des prestations dans le bâtiment 2
SELECT contrats.id_contrat, compositions.prix*compositions.quantites AS JARDIN
      FROM compositions
      INNER JOIN contrats ON contrats.id_contrat = compositions.id_contrat
      INNER JOIN clients ON clients.id_client = contrats.id_client      
      INNER JOIN prestations ON prestations.id_prestation = compositions.id_prestation
      WHERE prestations.type = 2
      GROUP BY contrats.id_contrat


4. Récupération du n° de contrat et du total des taxes de séjour TS sur batiment 1
SELECT contrats.id_contrat, batiments.id_batiment,compositions.prix*compositions.quantites AS TS
      FROM compositions
      INNER JOIN contrats ON contrats.id_contrat = compositions.id_contrat
      INNER JOIN clients ON clients.id_client = contrats.id_client      
      INNER JOIN prestations ON prestations.id_prestation = compositions.id_prestation
      INNER JOIN batiments ON batiments.id_batiment = contrats.id_batiment
      WHERE prestations.id_prestation = 21 AND batiments.id_batiment = 1
      GROUP BY contrats.id_contrat


Etc.... avec Taxe de séjour TS sur batiment 2...

Merci d'avance pour votre aide !

L'idée c'est de remplir ensuite à l'aide d'une boucle ce tableau :


Configuration: Linux / Chrome 99.0.4844.84

14 réponses

Résumé de la discussion

Le fil porte sur la fusion de requêtes SQL indépendantes en une seule pour regrouper les totaux par contrat et par bâtiment, afin d’éviter l’exécution séquencée en PHP. Une solution propose d’assembler les résultats via une requête unique qui agrège les montants selon les prestations et les bâtiments, utilisant des conditions IF pour distinguer les types et les valeurs. La solution efficace illustre une requête calculant les totaux des repas, des bâtiments et des taxes grâce à des sommes conditionnelles et à des jointures entre contrats, clients, prestations et bâtiments. En pratique, certains contrats ressortent vides et il peut être utile d’examiner la cohérence des données ou d’envisager une adaptation de structure, par exemple en centralisant les types de prestations.

Bobot (l’IA à votre service)
  1. Contributeur
    et ainsi?
    SELECT CLIENT,date_debut,id_contrat, 
     SUM( IF (PRESTTYP=3, PRIX, 0 ) ) AS REPAS,
     SUM( IF (PRESTID=21 and BAT=1, PRIX, 0 ) ) AS TS1
    FROM (SELECT contrats.id_contrat, contrats.date_debut,
      CONCAT(clients.nom,' ',clients.prenom) AS CLIENT, 
      compositions.prix*compositions.quantites AS PRIX,
      prestations.type as PRESTTYP, 
      batiments.id_batiment as BAT,
      prestations.id_prestation as PRESTID
          FROM compositions
          INNER JOIN contrats ON contrats.id_contrat = compositions.id_contrat
          INNER JOIN clients ON clients.id_client = contrats.id_client      
          INNER JOIN prestations ON prestations.id_prestation = compositions.id_prestation
       INNER JOIN batiments ON batiments.id_batiment = contrats.id_batiment
          ) AS X
          GROUP BY CLIENT,date_debut,id_contrat
    1
    1. Je te remercie beaucoup yg_be, tu as solutionné mon problème avec une requête de la mort qui tue !
      C'est génial les conditions dans le SELECT, du coup on peut écrire ce qu'on veut sans trop la rallonger !
      Ce que j'ai fait pour détecter des erreurs dans mon programme avec la saisie de Taxes de séjour dans
      des contrats TABLE D'HOTES uniquement !
      Il faut maintenant que de mon côté je bloque ce type d'insertion !
      Encore mille mercis !



      0
  2. Contributeur
    bonjour,
    peux-tu, pour chaque colonne du tableau, indiquer de quel champ et de quel table il s'agit?
    0
    1. Bonjour yg_be,

      Tu as raison, ce sera plus clair...

      Colonne 'NOM' : Table clients, champs CONCAT(clients.nom,' ',clients.prenom) AS CLIENT

      Colonne DATES : Table contrats, champs : contrats.date_debut

      Colonne VILLAGE : Table compositions + prestations, champs compositions.prix*compositions.quantites AS VILLAGE WHERE prestations.type = 1

      Colonne TS(1°) : Table compositions + prestations, champs compositions.prix*compositions.quantites AS TS_VILLAGE WHERE prestations.id_prestation = 21 AND batiments.id_batiment = 1

      Colonne JARDIN : Table compositions + prestations, champs compositions.prix*compositions.quantites AS JARDIN WHERE prestations.type = 2

      Colonne TS(2°) : Table compositions + prestations, champs compositions.prix*compositions.quantites AS TS_JARDIN WHERE
      prestations.id_prestation = 21 AND batiments.id_batiment = 2

      Colonne CHAMBRES : Table compositions + prestations, champs compositions.prix*compositions.quantites AS CHAMBRES WHERE prestations.type = 5

      Colonne REPAS : Table compositions + prestations, champs compositions.prix*compositions.quantites AS TABLE_HOTES WHERE prestations.type = 3

      compositions


      prestations
      0
      1. Je suis sur la bonne voie ? :

        SELECT th.id_contrat,SUM(th.TABLE_HOTES) AS TH, SUM(v.VILLAGE) AS VILLAGE
        FROM (SELECT contrats.id_contrat, (compositions.prix*compositions.quantites) AS TABLE_HOTES
        FROM compositions
              
        INNER JOIN contrats ON contrats.id_contrat = compositions.id_contrat
        INNER JOIN prestations ON prestations.id_prestation = compositions.id_prestation
        WHERE prestations.type=3)th
        
        LEFT JOIN(SELECT compositions.id_contrat ,(compositions.prix*compositions.quantites) AS VILLAGE
                        FROM compositions
                        INNER JOIN prestations ON prestations.id_prestation=compositions.id_prestation
                        WHERE prestations.type=1)v ON v.id_contrat=th.id_contrat
        
        GROUP BY th.id_contrat
        
        
        0
        1. Contributeur
          peut-être:
          SELECT CLIENT,date_debut,id_contrat, 
          	SUM( IF (PREST=3, PRIX, 0 ) ) AS TABLE_HOTE,
          	SUM( IF (PREST=21 and BAT=1, PRIX, 0 ) ) AS TS1
          FROM (SELECT contrats.id_contrat, contrats.date_debut,
          		CONCAT(clients.nom,' ',clients.prenom) AS CLIENT, 
          		compositions.prix*compositions.quantites AS PRIX,
          		prestations.type as PREST, batiments.id_batiment as BAT
                FROM compositions
                INNER JOIN contrats ON contrats.id_contrat = compositions.id_contrat
                INNER JOIN clients ON clients.id_client = contrats.id_client      
                INNER JOIN prestations ON prestations.id_prestation = compositions.id_prestation
          	  INNER JOIN batiments ON batiments.id_batiment = contrats.id_batiment
                )
                GROUP BY CLIENT,date_debut,id_contrat
          0
        2. @yg_beLa réponse de PhpMyAdmin à ta requête : #1248 - Every derived table must have its own alias

          Cela dit, tu as raison sur un point, il faut que mon GROUPBY se fasse sur les clients et non pas sur les
          id_contrat comme je l'ai fait !

          EDIT : Après test, le tri sur client est impossible car on fait 3 contrats par client par weekend :
          un par bâtiment puis un autre pour les prestations table d'hôtes


          SELECT th.id_client,th.id_contrat,SUM(th.TABLE_HOTES) AS TH, SUM(v.VILLAGE) AS VILLAGE
          FROM (SELECT clients.id_client,contrats.id_contrat, (compositions.prix*compositions.quantites) AS TABLE_HOTES
          FROM compositions
          
          
          INNER JOIN contrats ON contrats.id_contrat = compositions.id_contrat
          INNER JOIN clients ON  clients.id_client = contrats.id_client
          INNER JOIN prestations ON prestations.id_prestation = compositions.id_prestation
          WHERE prestations.type=3)th
          
          LEFT JOIN(SELECT compositions.id_contrat ,(compositions.prix*compositions.quantites) AS VILLAGE
                          FROM compositions
                          INNER JOIN prestations ON prestations.id_prestation=compositions.id_prestation
                          WHERE prestations.type=1)v ON v.id_contrat=th.id_contrat
          
          GROUP BY th.id_contrat
          ORDER BY th.id_client ASC
          
          


          ça semble fonctionner :


          Le contrat 85 a bien de l'hébergement ET une prestation repas
          0
        3. Contributeur
          @emrhil suffit peut-être d'ajouter
          AS X
          en ligne 13.
          0
      2. Contributeur
        Je me demande si les tables sont bien structurées. Je crains qu'une structure incorrecte des tables te conduise à faire des requêtes excessivement compliquées.
        Je suis étonné par la présence d'un prix dans la table compositions. Je trouve cela suspect.
        0
        1. Contributeur
          Quel logiciel de base de données utilises-tu?
          0
          1. J'administre mes tables avec phpmyadmin en hébergement chez Ionos...
            Les prix par défaut des prestations sont stockés dans la table prestations ils sont ainsi proposés à la réalisation du contrat mais comme l'utilisateur les adapte selon le client facturé (cas de remises par exemple) ces prix sont stockés avec la prestation, sin descriptif, son prix et les quantités...
            0
            1. Le tarif par défaut de la chambre est proposé (table prestations)


              Le tarif de la chambre peut être modifié, et ce chiffre modifié sera stocké dans la table compositions


              La table compositions


              Au même titre qu'un descriptif par défaut est proposé avec la fiche de la prestation mais qui peut être modifié
              (exemple pour les prestations repas, dont le menu peut être changé selon les arrivages du marché !)
              0
            2. Contributeur
              Donc ce serait une base de données MySQL?
              0
            3. Contributeur
              @emrhJe suppose qu'un bâtiment est associé à chaque contrat.
              0
            4. @yg_beOui, c'est ça....
              1 - Village
              2 - Jardin

              3 - pour les contrats table d'hôtes donc pas proprement parlé de bâtiment mais de contrat
              4 - Non utilisé comme contrat
              5 - Chambres individuelles
              0
            5. @yg_beOui, une bdd MySQL
              0
          2. SELECT th.id_client,th.id_contrat,SUM(th.TABLE_HOTES) AS TH, SUM(v.VILLAGE) AS VILLAGE,SUM(j.JARDIN) AS JARDIN
            FROM (SELECT clients.id_client,contrats.id_contrat, (compositions.prix*compositions.quantites) AS TABLE_HOTES
            FROM compositions
            
            
            INNER JOIN contrats ON contrats.id_contrat = compositions.id_contrat
            INNER JOIN clients ON  clients.id_client = contrats.id_client
            INNER JOIN prestations ON prestations.id_prestation = compositions.id_prestation
            WHERE prestations.type=3)th
            
            LEFT JOIN(SELECT compositions.id_contrat ,(compositions.prix*compositions.quantites) AS VILLAGE
                            FROM compositions
                            INNER JOIN prestations ON prestations.id_prestation=compositions.id_prestation
                            WHERE prestations.type=1)v ON v.id_contrat=th.id_contrat
            
            LEFT JOIN(SELECT compositions.id_contrat ,(compositions.prix*compositions.quantites) AS JARDIN
                            FROM compositions
                            INNER JOIN prestations ON prestations.id_prestation=compositions.id_prestation
                            WHERE prestations.type=2)j ON j.id_contrat=th.id_contrat
            GROUP BY th.id_contrat
            ORDER BY th.id_client ASC
            


            Ça ne fonctionne plus !
            0
            1. Pour bien faire il faudrait qu'à la création d'un contrat on ne puisse pas saisir de prestations repas sur le même contrat (cf mon #11)...
              Mais si un client prend un chambre pour une nuit + une repas on regroupe tout sur le même....
              il faut donc aller chercher les prestations non pas par leur rattachement à un contrat par bâtiment mais plutôt par leur type
              0
          3. Compte tenu de la complexité, je me demande si je ne devrais pas remplir un array avec des requêtes successives avant de remplir ma table ?
            0
            1. Contributeur
              Je peux difficilement t'aider si tu ne testes pas mes suggestions.
              0
            2. @yg_beSi Si, je teste ce que tu me proposes mais c'était juste une question...Je me demandais si dans le cas de requêtes complexes il n'arrivait pas des fois où il valait mieux essayer par plusieurs requêtes construire un array...

              Ta requête donne donc : #1248 - Every derived table must have its own alias et ajouter AS X en ligne 13 donne ça :



              Pour être sûr, j'ai ajouté des Taxes de Séjour dans les contrats 58 et 61 mais ils ne ressortent pas...
              0
            3. Contributeur
              @emrhDans ce cas-ci, je pense que nous trouverons une solution simple.
              Sinon, je suggérerais plutôt d'adapter la structure de la base de données.
              0
          4. Table compositions


            Table contrats
            0
            1. Table prestations


              Comme il est possible qu'un contrat contienne :
              - soit un gîte avec taxe séjour,
              - soit une ou des chambres,
              - soit un gîte ou des chambres avec prestations table d'hôtes,
              - soit QUE de la table d'hôtes,

              ne pourrait on pas imaginer des requêtes avec comme clause WHERE une ou des informations se basant sur le prestations.type de la prestation facturée ?

              C'est à dire :

              prestations.type (1) = Bâtiment "village" pour remplir la colonne VILLAGE
              batiments.id_batiment (1) + prestations.id_prestation (21) - Taxe séjour pour remplir la colonne TS n°1
              prestations.type (2) = Bâtiment "jardin" pour remplir la colonne JARDIN
              batiments.id_batiment (2) + prestations.id_prestation (21) - Taxe séjour pour remplir la colonne TS n°2
              prestations.type (5) = Bâtiment "chambres" pour remplir la colonne CHAMBRES
              prestations.type (3) = Bâtiment "table d'hôtes" pour remplir la colonne REPAS

              0
              1. Contributeur
                Tu fais des suggestions de solution. S'agit-il de résoudre le problème initial, ou suggères-tu d'adapter le problème pour pouvoir le résoudre plus facilement?
                0
            2. Par contre des contrats ressortent complètement vide comme le 60 et 61 ?
              0
              1. Contributeur
                Il devrait y avoir REPAS ou TS1 pour les contrats 60 ou 61?
                0
              2. @yg_be60 ne contient qu'une chambre
                et 61 1 chambre et des taxes de séjour
                0
              3. Contributeur
                @emrhdonc la requête est correcte, non?
                0
              4. @yg_beoui, excuse moi, tu as raison, nous sommes en présence d'une chambre dont le prix intègre la taxe de séjour, il ne devrait pas y en avoir une en plus sur le contrat....
                il faut que je bloque ça pour éviter que l'utilisateur le fasse, moi je l'ai fait juste pour le test, d'où ma confusion, désolé
                0
              5. @yg_bedonc c'est normal si 60 et 61 ressortent qd même ? alors qu'ils ne sont concernés ni par la requête TABLEDHOTES ni par TS1 ?
                0