(16-01-2012, 04:33 PM)niahoo a écrit : Je ne comprends pas ton code, où fais tu la récursion/boucle sur les villages suivants ?
Bon, visiblement, l'utilisation des sous requêtes n'est pas si claire.
Je décompose pour mieux expliquer.
Reprenons les données de base.
J'ajoute également une village supplémentaire pour l'exemple
Citation :on doit diminuer de 1000 ressources:
le village 1 en contient 300, on diminue celui ci de 300
le village 2 en contient 400, on diminue celui ci de 400
le village 3 en contient 1000, on diminue celui ci de 300 seulement
le village 4 en contient 500, on ne diminue pas
Cela signifie que on doit retirer le maximum de ressources possible de chaque village jusqu'à ce que le montant total demandé ait été prélevé. Pour commencer, il me faut donc savoir combien de ressources sont disponibles sur les villages précédents.
Ces valeurs sont déterminées par la sous requête la plus profonde de mon exemple.
Dans un premier temps, j'enlève les GREATEST pour plus de compréhension
SELECT
ID,
(
SELECT IFNULL(SUM(Res),0)
FROM Village V2
WHERE V2.ID < V1.ID
)
FROM Village V1
Cela va donner les résultats suivantsVillage 1 : 0
Village 2 : 300
Village 3 : 700
Village 4 : 1700
Cela se traduit par
Je dois retirer du village 1 la quantité demandée
Je dois retirer du village 2 la quantité demandée - 300 (le contenu du village 1)
Je dois retirer du village 3 la quantité demandée - 700 (le contenu du village 1 + village 2)
Je dois retirer du village 4 la quantité demandée - 1700 (le contenu du village 1 + 2 + 3)
Note : sur cet exemple de code, je travaille avec les ID des villages mais on peut imaginer travailler avec un champ Village_Sequence qui permettrait d'organiser les prélèvements dans l'ordre souhaité.
J'utilise la fonction GREATEST pour appliquer deux règles supplémentaires.
- Je ne peux pas retirer plus de ressources qu'il en existe dans un village
- Une fois que toutes les ressources nécessaires ont été récupérées, inutiles d'en prendre plus
SELECT
ID,
GREATEST(Res - GREATEST(1000-(
SELECT IFNULL(SUM(Res),0)
FROM Village V2
WHERE V2.ID < V1.ID),0),0)
FROM Village V1
Avec cette requête, je récupère les nouvelles valeurs de ressource de chaque village.Je décompose les calculs pour chaque ligne affectées par MySQL
Village 1 : GREATEST(300 - GREATEST(1000 - 0,0) , 0) -> 0
Village 2 : GREATEST(400 - GREATEST(1000 - 300,0), 0) -> 0
Village 3 : GREATEST(1000 - GREATEST(1000 - 700,0) , 0) -> 300
Village 4 : GREATEST(500 - GREATEST(1000 - 1700,0) , 0) -> 500
Comme dans ma requête principale, ces résultats sont stockés dans une table temporaire, avec l'ID du village et du joueur, un simple update avec jointure me permet, en une requête, de mettre à jour les ressources de tous les villages.
Pas besoin de boucle par village !
Il est à noter qu'il est également possible de mettre à jour tous les joueurs d'un coup pour un même montant de ressource via cette méthode.
Il suffit de remplacer la clause WHERE JID=1 de mon exemple par un GROUP BY JID
De la même manière, si on veut retirer un nombre de ressource différent à chaque joueur en une seule passe, c'est tout à fait possible.
Il suffit d'avoir une table contenant l'ID du joueur et la quantité de ressource à prendre et de faire une jointure appropriée dans la requête la plus profonde
SELECT
ID,
GREATEST(Res - GREATEST(G.Res-(
SELECT IFNULL(SUM(Res),0)
FROM Village V2
WHERE V2.ID < V1.ID),0),0)
FROM Village V1 INNER JOIN GetRes G ON V1.JID = GetRes.JID
Simple, efficace et tout en une requête.Donc, ces histoires de boucle, de fraction et de transaction sont inutiles.
Quand on te dit qu'un projet est terminé à 90%, prépare toi pour les 90% suivant
Ninety-Ninety Rule
"Une guerre de religions, c'est quand deux peuples s'entretuent pour savoir qui a le meilleur ami imaginaire"
Vu sur IRC
Ninety-Ninety Rule
"Une guerre de religions, c'est quand deux peuples s'entretuent pour savoir qui a le meilleur ami imaginaire"
Vu sur IRC