JeuWeb (JeuPHP) - Crée ton jeu par navigateur

Version complète : [Résolu][SQL] Aide pour construire une requête
Vous consultez actuellement la version basse qualité d'un document. Voir la version complète avec le bon formatage.
Pages : 1 2
Plop !

C't'encore mwa ! Content de me revoir - déjà - ?

Cette fois-ci, j'ai cette requête :
Code PHP :
SELECT
  warehouses
.id AS warehouse_id,
  
warehouses.capacityMech,
  
warehouses.capacityWeight,
  
warehouses.countries_id,
  
player_has_warehouse.name AS warehouse_name,
//  player_has_warehouse.weight,
//  player_has_warehouse.nb_mechs,
  
countries.name AS country_name
FROM
  player_has_warehouse
,
  
warehouses
JOIN countries
  ON warehouses
.countries_id countries.id
WHERE player_has_warehouse
.players_id $this->playerSess['id']
  AND 
player_has_warehouse.warehouses_id warehouses.id 

Mon problème, c'est que les données en orange sont des données calculables. Des données que je ne souhaite donc pas avoir en dur dans ma BdD.

Pour avoir ces données, je pourrais faire respectivement :
Code PHP :
SELECT SUM(armors.weight)
FROM armorsplayer_has_armor
WHERE player_has_armor
.players_id $this->playerSess['id']
  AND 
player_has_armor.armors_id armors.id;

SELECT SUM(weapons.weight)
FROM weaponsplayer_has_weapon
WHERE player_has_weapon 
$this->playerSess['id']
  AND 
player_has_weapon.weapons_id weapons.id
J'peux ensuite faire la somme avec une addition PHP et j'ai mon poids.

J'passe ensuite au calcul de la propriété nb_mechs :
Code PHP :
SELECT COUNT(player_has_exomech.id)
FROM player_has_exomech
WHERE player_has_exomech
.players_id $this->playerSess['id']; 

Et j'ai toutes les infos que j'voulais.

Mais j'ai l'intime conviction qu'il est possible de construire une unique requête pour avoir tout ça, sauf qu'à part faire de multiples essais infructueux, j'ai pas la soluce. Et ça fait un ch'ti temps déjà que j'ai pas fait de SQL un peu plus high level. Ca me plait d'ailleurs ces 'tites problématiques 34

Après, sauf erreur de ma part, j'pense quand même que si une requête n'est pas suffisante, ce p'tit bout d'algo est largement optimisable.

Merci par avance pour le coup de main !

Et maintenant, j'm'en vais me coucher rejoindre ma femme. Ai bien bossé aujourd'hui !

@tchaOo° et bonne nuit !
Code PHP :
SELECT
  warehouses
.id AS warehouse_id,
  
warehouses.capacityMech,
  
warehouses.capacityWeight,
  
warehouses.countries_id,
  
player_has_warehouse.name AS warehouse_name,
((
SELECT SUM(armors.weight)
FROM armorsplayer_has_armor
WHERE player_has_armor
.players_id $this->playerSess['id']
  AND 
player_has_armor.armors_id armors.id) +
(
SELECT SUM(weapons.weight)
FROM weaponsplayer_has_weapon
WHERE player_has_weapon 
$this->playerSess['id']
  AND 
player_has_weapon.weapons_id weapons.id)) as weight,
  (
SELECT COUNT(player_has_exomech.id)
FROM player_has_exomech
WHERE player_has_exomech
.players_id $this->playerSess['id']) as.nb_mechs,
  
countries.name AS country_name
FROM
  player_has_warehouse
,
  
warehouses
JOIN countries
  ON warehouses
.countries_id countries.id
WHERE player_has_warehouse
.players_id $this->playerSess['id']
  AND 
player_has_warehouse.warehouses_id warehouses.id 
La première idée qui me vient est de simplement intégrer les calculs comme des sous-requêtes. Comme cela :
Code PHP :
SELECT    warehouses.id AS warehouse_id,
        
warehouses.capacityMech,
        
warehouses.capacityWeight,
        
warehouses.countries_id,
        
player_has_warehouse.name AS warehouse_name,
        (
            (
                
SELECT    SUM(armors.weight)
                
FROM    armorsplayers_has_armor
                WHERE    player_has_armor
.players_id $this->playerSess['id']
                AND        
player_has_armor.armors_id armors.id
            
)
            +
            (
                
SELECT    SUM(weapons.weight)
                
FROM    weaponsplayer_has_weapon
                WHERE    player_has_weapon 
$this->playerSess['id']
                AND        
player_has_weapon.weapons_id weapons.id
            
)
        ) AS 
weight,
        (
            
SELECT    COUNT(player_has_exomech.id)
            
FROM    player_has_exomech
            WHERE    player_has_exomech
.players_id $this->playerSess['id']
        ) AS 
nb_mechs,
        
countries.name AS country_name
FROM    player_has_warehouse
,
        
warehouses
JOIN    countries
ON        warehouses
.countries_id countries.id
WHERE    player_has_warehouse
.players_id $this->playerSess['id']
AND        
player_has_warehouse.warehouses_id warehouses.id

N'est-il pas plus propre (bien qu'un peu plus verbeux) d'effectuer les jointures explicitement (avec JOIN ON) plutôt que de les faire dans la clause WHERE ?

Par contre, ces informations ont tout intérêt à être mises en cache. 4


Sephi-Chan, qui va se coucher, lui aussi…
Huhu ! Merci les gens ! Encore une fois, c'était plutôt con comme requête.

Pour ce qui est du cache, je verrais quand j'aurais fini quelque chose de fonctionnel. Je ne connais pas les techniques de mises en cache et tout donc j'préfère pas perdre trop de temps, lancer une béta qui sera éprouvée. Pendant cette phase d'épreuve, j'pourrais me pencher sur les optimisations en même temps que les corrections.

Maintenant, j'dis ça mais j'suis ouvert à toutes pistes, propositions,... :]

Encore merci pour le coup de main !

@tchaOo°

[Edit]
J'allais oublié de dire :
Concernant les jointures dans la WHERE Clause, elles sont possibles, elles sont plus simples alors pourquoi s'en priver ?

J'ai cru lire effectivement que quelque part, c'est plus approprié de le faire dans les règles de l'art. Maintenant, si on me convainc du pourquoi du comment, j'suis prêt à faire l'effort. Sans ça, j'vois pas pourquoi je devrais me les casser si j'n'y perds rien ;]
Ben dans le where, tu obliges le moteur de MySQL à réécrire la requêtes pour y mettre les jointures, c'est tout simple 2
Mouarf ! Il est grand, vu la complexité de la jointure, ça doit pas le mettre à genouxx ?
Plume a écrit :[Edit]
J'allais oublié de dire :
Concernant les jointures dans la WHERE Clause, elles sont possibles, elles sont plus simples alors pourquoi s'en priver ?

J'ai cru lire effectivement que quelque part, c'est plus approprié de le faire dans les règles de l'art. Maintenant, si on me convainc du pourquoi du comment, j'suis prêt à faire l'effort. Sans ça, j'vois pas pourquoi je devrais me les casser si j'n'y perds rien ;]

d'un point de vue syntaxe, c'est plus correct de mettre les jointures via des JOIN, et de les séparer du WHERE.

pourquoi ?

le WHERE représente des conditions, des filtres sur les données, pas des liens entre tables.

Lorsque je fais une requête, je dessine les tables sur papier, avec les liens entre elles (JOIN) et ensuite je m'intéresse aux conditions (WHERE) c'est à dire quelles lignes récupérer.

c'est une question de lisibilité et de convention de programmation.

A+

Pascal
Grumpf !

J'verrais dans l'avenir pour changer mes habitudes. Par contre pas la motivation de revenir sur ce qui est déjà fait ^_^'

Cela dit, j'connais pas beaucoup de monde qui comprenne mieux :
Code PHP :
SELECT *
FROM
  player_has_warehouse
,
  
warehouses
JOIN countries
  ON warehouses
.countries_id countries.id
JOIN player_has_warehouse
  ON player_has_warehouse
.warehouses_id warehouses.id
WHERE player_has_warehouse
.players_id $this->playerSess['id']; 
Plutôt que :
Code PHP :
SELECT *
FROM
  player_has_warehouse
,
  
warehouses
JOIN countries
  ON warehouses
.countries_id countries.id
WHERE player_has_warehouse
.players_id $this->playerSess['id']
  AND 
player_has_warehouse.warehouses_id warehouses.id

En plus, j'suis même pas sûr que ma jointure soit correcte :/

@tchaOo°
Verdict : Ma requête n'était pas bonne. J'la corrige 34

Code PHP :
/* SELECT
     *  warehouses.id AS warehouse_id,
     *  warehouses.capacityMech,
     *  warehouses.capacityWeight,
     *  warehouses.countries_id,
     *  player_has_warehouse.name AS warehouse_name,
     *  (
     *    (
     *      SELECT SUM(armors.weight)
     *      FROM armors, player_has_armor
     *      WHERE player_has_armor.players_id = $this->playerSess['id']
     *        AND player_has_armor.armors_id = armors.id
     *    )
     *    +
     *    (
     *      SELECT SUM(weapons.weight)
     *      FROM weapons, player_has_weapon
     *      WHERE player_has_weapon = $this->playerSess['id']
     *        AND player_has_weapon.weapons_id = weapons.id
     *    )
     *  ) AS weight,
     *  (
     *    SELECT COUNT(player_has_exomech.id)
     *    FROM player_has_exomech
     *    WHERE player_has_exomech.players_id = $this->playerSess['id']
     *  ) AS nb_mechs,
     *  countries.name AS country_name
     * FROM
     *  warehouses
     * JOIN countries
     *  ON warehouses.countries_id = countries.id
     * JOIN player_has_warehouse
     *  ON player_has_warehouse.warehouses_id = warehouses.id
     * WHERE player_has_warehouse.players_id = $this->playerSess['id']
     */
    
$selectWarehouse =
        
'SELECT ' .
        
' %s, ' .
        
' %s, ' .
        
' %s, ' .
        
' %s, ' .
        
' %s, ' .
        
' ( ' .
        
'   ( ' .
        
'     SELECT SUM(%s) ' .
        
'     FROM %s, %s ' .
        
'     WHERE %s = %d ' .
        
'       AND %s = %s ' .
        
'   ) ' .
        
'   + ' .
        
'   ( ' .
        
'     SELECT SUM(%s) ' .
        
'     FROM %s, %s ' .
        
'     WHERE %s = %d ' .
        
'       AND %s = %s ' .
        
'   ) ' .
        
' ) AS %s, ' .
        
' (' .
        
'   SELECT COUNT(%s) ' .
        
'   FROM %s ' .
        
'   WHERE %s = %d ' .
        
' ) AS %s, ' .
        
' %s ' .
        
'FROM %s ' .
        
'JOIN %s ' .
        
' ON %s = %s ' .
        
'JOIN %s' .
        
' ON %s = %s ' .
        
'WHERE %s = %d;';
    
$selectWarehouseQuery sprintf(
      
$selectWarehouse,
      
$this->tableWarehouses.'.id AS warehouse_id',
      
$this->tableWarehouses.'.capacityMech',
      
$this->tableWarehouses.'.capacityWeight',
      
$this->tableWarehouses.'.countries_id',
      
$this->tablePlayerHasWarehouse.'.name AS warehouse_name',
      
$this->tableArmors.'.weight',
      
$this->tableArmors,
      
$this->tablePlayerHasArmor,
      
$this->tablePlayerHasArmor.'.players_id',
      
$this->playerSess['id'],
      
$this->tablePlayerHasArmor.'.armors_id',
      
$this->tableArmors.'.id',
      
$this->tableWeapons.'.weight',
      
$this->tableWeapons,
      
$this->tablePlayerHasWeapon,
      
$this->tablePlayerHasWeapon.'.players_id',
      
$this->playerSess['id'],
      
$this->tablePlayerHasWeapon.'.weapons_id',
      
$this->tableWeapons.'.id',
      
'weight',
      
'*',
      
$this->tablePlayerHasExomech,
      
$this->tablePlayerHasExomech.'.players_id',
      
$this->playerSess['id'],
      
'nb_mechs',
      
$this->tableCountries.'.name AS country_name',
      
$this->tableWarehouses,
      
$this->tableCountries,
      
$this->tableWarehouses.'.countries_id',
      
$this->tableCountries.'.id',
      
$this->tablePlayerHasWarehouse,
      
$this->tablePlayerHasWarehouse.'.warehouses_id',
      
$this->tableWarehouses.'.id',
      
$this->tablePlayerHasWarehouse.'.players_id',
      
$this->playerSess['id']
    ); 

Nice ! Ca tourne et c'est propre, nan ? 11
Je pense que rendre constant le nom des tables et des colonnes améliorerait la lisibilité de l'ensemble, les placeholders (ou marques substitutives 45) ont plutôt intérêt à être utilisés pour les paramètres variables.

Si jamais tes noms de table ou de colonnes changent, tu peux au pire lancer un rechercher et remplacer dans ton modèle : ça ne nuit pas à la maintenabilité du projet.


Sephi-Chan
Pages : 1 2
URLs de référence