JeuWeb - Crée ton jeu par navigateur
[Résolu][SQL] Aide pour construire une requête - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : [Résolu][SQL] Aide pour construire une requête (/showthread.php?tid=3167)



[Résolu][SQL] Aide pour construire une requête - Plume - 12-10-2008

Plop !

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

Cette fois-ci, j'ai cette requête :
Code PHP :
<?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 :
<?php 
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;
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 :
<?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 ^^

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 !


RE: Aide pour construire une requête - Sephi-Chan - 13-10-2008

La première idée qui me vient est de simplement intégrer les calculs comme des sous-requêtes. Comme cela :
Code PHP :
<?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, players_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 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. :O


Sephi-Chan, qui va se coucher, lui aussi…


RE: [Resolved] Aide pour construire une requête - Plume - 13-10-2008

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 ;]


RE: [Resolved] Aide pour construire une requête - Anthor - 13-10-2008

Ben dans le where, tu obliges le moteur de MySQL à réécrire la requêtes pour y mettre les jointures, c'est tout simple Smile


RE: [Resolved] Aide pour construire une requête - Plume - 13-10-2008

Mouarf ! Il est grand, vu la complexité de la jointure, ça doit pas le mettre à genouxx ?


RE: [Resolved] Aide pour construire une requête - pascal - 13-10-2008

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


RE: [Resolved] Aide pour construire une requête - Plume - 13-10-2008

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 :
<?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 :
<?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°


RE: [Résolu][SQL] Aide pour construire une requête - Plume - 13-10-2008

Verdict : Ma requête n'était pas bonne. J'la corrige ^^

Code PHP :
<?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 ? :$


RE: [Résolu][SQL] Aide pour construire une requête - Sephi-Chan - 13-10-2008

Je pense que rendre constant le nom des tables et des colonnes améliorerait la lisibilité de l'ensemble, les placeholders (ou marques substitutives xD) 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


RE: [Résolu][SQL] Aide pour construire une requête - Plume - 13-10-2008

Uè, j'vais modifier ça, ça économisera quelques lignes ^_^'

@tchaOo°