JeuWeb - Crée ton jeu par navigateur
Bug d'enchainement de requêtes - 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 : Bug d'enchainement de requêtes (/showthread.php?tid=5120)

Pages : 1 2 3


Bug d'enchainement de requêtes - Hiztaar - 27-08-2010

Bonjour à tous,

Je me permets de demander de l'aide car je suis confronté à un problème que je n'arrive pas à corriger et ce depuis un mois. Je dois avoir codé quelque chose d'affreux mais malgré tout je n'identifie pas l'origine du problème.

Synthèse :
- Application développée en PHP 5 / mysql à l'aide de Code Igniter.

Le problème survient dans mon modèle "knowledge_model"

Code PHP :
<?php 
function Get_available_knowledges()
{

// On va chercher les savoirs disponibles.
// Les savoirs disponibles répondent a toutes les conditions de liaison et de descendance des autres savoirs
// Il faut d'abord récupérer tous les savoirs détenus par un country

$this->db->where('id_country', $this->session->userdata('current_view_fief'));
$owned_knowledges = $this->db->get('utg_country_knowledge');

// Nous avons un objet $query qui contient tous les id de knowledges connus.

// On va chercher tous les knowledges qui dépendent des knowledges possédés
// Pour l'instant, les knowledges ne peuvent être débloqués que par d'autres knowledges et rien d'autre type_parent = 1.
$count = 0; // On met le compteur a 1 pour préparer le array.
$available;
foreach(
$owned_knowledges->result() as $row)
{
$count ++;
$this->db->where('id_knowledge_parent', $row->id_knowledge);
$this->db->where('type_parent', 1);
$this->db->select('id_knowledge_child');
$result = $this->db->get('utg_knowledge_links');
$potential_knowledges[$count] = $result->row();
$potential_knowledges[0] = $count;

}

// On a récupéré le tableau $potential_knowledges qui contient des objets id_knowledge_child
// On va créer un tableau avec tous les knowledges child et le comparer au tableau des knowledges possédés.
$count = 0; // On réinitialise le compteur

while($count < $potential_knowledges[0])
{
$count++;
$this->db->where('id_knowledge_child', $potential_knowledges[$count]->id_knowledge_child);
$this->db->where('type_parent', 1);
$this->db->select('id_knowledge_parent');
$child_knowledges = $this->db->get('utg_knowledge_links');


$available_knowledge[$count] = 0;
foreach(
$child_knowledges->result() as $row)
{
//$available_knowledge[$count] = 1;
if(in_array($row->id_knowledge_parent, $owned_knowledges->row_array()) != FALSE && $available_knowledge[$count] < 2 )
{
$available_knowledge[$count] = 1;
}
else
{
$available_knowledge[$count] = 2;
}
}

$available_knowledge[0] = $count;

}

// On a tous les id de knowledges pouvant être recherchés
// Il faut a présent les récupérer en détail et classés par famille

$count = 1;
if(isset(
$available_knowledge) && $available_knowledge[0] !=0)
{
while(
$count < $available_knowledge[0])
{
if(
$available_knowledge[$count] = 1)
{
$this->db->where('id', $available_knowledge[$count]);
}
}
$this->db->where('active',1);
$this->db->order_by('family');
$final_result = $this->db->get('utg_knowledge');
return
$final_result;
}
return
FALSE;

}

Voici le principe :
- Je suis un seigneur owner d'un "country".
- Je cherche à ressortir tous les "savoirs" ( recherche ) pouvant être recherchés à l'heure actuelle, les autres n'apparaissent pas.
- Un savoir est "débloqué" lorsque le "country" possède déjà tous les savoirs dont le savoir débloqué est dépendant. ( table de liaison utg_knowledge_links )

Mais voilà, avec ce que je fais, je n'arrive pas à obtenir ce résultat. Il me sort TOUS les savoirs que je n'ai pas et parfois même les savoirs que je détiens déjà...

Si quelqu'un pouvait m'aider à identifier le problème, ce serait vraiment sympa. Je peux décrire les tables de bdd à la demande mais les informations de champ sont déjà dans le code normalement.

Merci d'avance Smile


RE: Bug d'enchainement de requêtes - srm - 28-08-2010

J'ai refait ton truc à ma sauce.
En admettant ce modèle de données :
-- phpMyAdmin SQL Dump
-- version 3.3.5.1deb1
-- http://www.phpmyadmin.net
--
-- Serveur: localhost
-- Généré le : Sam 28 Août 2010 à 18:57
-- Version du serveur: 5.1.49
-- Version de PHP: 5.3.2-2

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

--
-- Base de données: `test`
--

-- --------------------------------------------------------

--
-- Structure de la table `connu`
--

CREATE TABLE IF NOT EXISTS `connu` (
`id_player` int(10) NOT NULL,
`id_savoir` int(10) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

--
-- Contenu de la table `connu`
--

INSERT INTO `connu` (`id_player`, `id_savoir`) VALUES
(1, 5);

-- --------------------------------------------------------

--
-- Structure de la table `connu_country`
--

CREATE TABLE IF NOT EXISTS `connu_country` (
`id_country` int(10) NOT NULL,
`id_savoir` int(10) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

--
-- Contenu de la table `connu_country`
--

INSERT INTO `connu_country` (`id_country`, `id_savoir`) VALUES
(1, 6),
(1, 2),
(1, 1);

-- --------------------------------------------------------

--
-- Structure de la table `player`
--

CREATE TABLE IF NOT EXISTS `player` (
`id` int(10) NOT NULL,
`nom` varchar(20) NOT NULL,
`id_country` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

--
-- Contenu de la table `player`
--

INSERT INTO `player` (`id`, `nom`, `id_country`) VALUES
(1, 'oxman', 1);

-- --------------------------------------------------------

--
-- Structure de la table `savoir`
--

CREATE TABLE IF NOT EXISTS `savoir` (
`id` int(10) NOT NULL,
`nom` varchar(20) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

--
-- Contenu de la table `savoir`
--

INSERT INTO `savoir` (`id`, `nom`) VALUES
(1, 'magie'),
(2, 'magie inferieur'),
(3, 'magie superieure'),
(4, 'voyance'),
(5, 'mensonge'),
(6, 'parler'),
(7, 'marchander');

-- --------------------------------------------------------

--
-- Structure de la table `savoir_dependance`
--

CREATE TABLE IF NOT EXISTS `savoir_dependance` (
`id_savoir` int(10) NOT NULL,
`id_savoir_dependant` int(10) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

--
-- Contenu de la table `savoir_dependance`
--

INSERT INTO `savoir_dependance` (`id_savoir`, `id_savoir_dependant`) VALUES
(3, 2),
(3, 1),
(4, 7),
(4, 6),
(5, 6);



Voici la requête qui remplis ton besoin :
SELECT s.id, s.nom FROM savoir s WHERE
s.id NOT IN (
SELECT id_savoir FROM savoir_dependance sd
WHERE sd.id_savoir_dependant NOT IN (SELECT id_savoir FROM connu_country WHERE id_country = (select id_country from player where id = 1)))
AND s.id NOT IN (select c.id_savoir FROM connu c WHERE c.id_player = 1)


RE: Bug d'enchainement de requêtes - Hiztaar - 28-08-2010

Super, ça marche !

J'ai adapté le code, au final ça donne :

Code PHP :
<?php 
$available_knowledges
= $this->db->query("
SELECT knowledge.id, knowledge.name, knowledge.family, knowledge.description, knowledge.img_url,
knowledge.time_to_discover, knowledge.price
FROM utg_knowledge knowledge
WHERE knowledge.id
NOT IN (
SELECT id_knowledge_parent
FROM utg_knowledge_links
WHERE utg_knowledge_links.id_knowledge_child
NOT IN (
SELECT id_knowledge
FROM utg_country_knowledge
WHERE id_country =
$fief
)
)
AND knowledge.active = 1
"
);

La prochaine fois je laisserai plus de calcul au serveur SQL <_<

Merci !


RE: Bug d'enchainement de requêtes - srm - 28-08-2010

Et surtout la prochaine fois donne ton modèle de table avec un jeu de données Wink


RE: Bug d'enchainement de requêtes - atra27 - 29-08-2010

Juste comme ça...
Les requêtes dans les requêtes... c'est pas super conseillé sa il me semble?

J'en fait pas mais j'ai entendu parler de sa sur IRC un jour... (il me semble que c'est colmea... pour pas balancer :p)

Donc au final... les requetes dans les requetes... c'est vraiment lourd (genre double la charge) ou pas tellement? (je parle dans un cas général! avec les index mal foutus etc on peut vraiment tout alourdir Smile )


RE: Bug d'enchainement de requêtes - Sephi-Chan - 29-08-2010

Ben non c'est pas déconseillé… Ça ne fait jamais que 3 requêtes ici, ça n'a rien de mal. Smile


Sephi-Chan


RE: Bug d'enchainement de requêtes - srm - 29-08-2010

C'est comme tout ça dépend ce que tu fais, même un SELECT * FROM A WHERE LENGTH© = 5 peut-être lourd Wink
C'est une boucle sur les requêtes qui est pas conseillé, donc X dizaines/centaines/milliers de fois une requête Smile


RE: Bug d'enchainement de requêtes - Hiztaar - 29-08-2010

En fait, après avoir bouclé mon modèle, j'ai rajouté des "knowledges" et ça repart en vrille malgré cette requête. Je poste le schéma de base de donnée.

Code :
-- phpMyAdmin SQL Dump
-- version 3.2.5
-- http://www.phpmyadmin.net
--
-- Serveur: 127.0.0.1
-- Généré le : Dim 29 Août 2010 à 14:53
-- Version du serveur: 5.1.43
-- Version de PHP: 5.3.2

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- Base de données: `bdd_ultima_thulee`
--

-- --------------------------------------------------------

--
-- Structure de la table `utg_country`
--

CREATE TABLE IF NOT EXISTS `utg_country` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(25) COLLATE latin1_general_ci NOT NULL,
  `description` text COLLATE latin1_general_ci NOT NULL,
  `vassal_tax` int(3) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=5 ;

--
-- Contenu de la table `utg_country`
--

INSERT INTO `utg_country` (`id`, `name`, `description`, `vassal_tax`) VALUES
(1, 'Saint Asrock', 'trop fort les meilleurs', 15),
(2, 'Marches d''Argent', 'blablabla bla', 10),
(3, 'Malt Saviör', '', 9),
(4, 'Eren-Saviör', '', 5);

-- --------------------------------------------------------

--
-- Structure de la table `utg_country_knowledge`
--

CREATE TABLE IF NOT EXISTS `utg_country_knowledge` (
  `id_country` int(11) NOT NULL,
  `id_knowledge` int(11) NOT NULL,
  `knowledge_acquired` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `knowledge_status` int(1) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id_country`,`id_knowledge`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

--
-- Contenu de la table `utg_country_knowledge`
--

INSERT INTO `utg_country_knowledge` (`id_country`, `id_knowledge`, `knowledge_acquired`, `knowledge_status`) VALUES
(1, 1, '2010-08-15 12:52:29', 2),
(1, 2, '2010-08-29 12:52:13', 1);

-- --------------------------------------------------------

--
-- Structure de la table `utg_knowledge`
--

CREATE TABLE IF NOT EXISTS `utg_knowledge` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `family` varchar(50) COLLATE latin1_general_ci NOT NULL,
  `name` varchar(50) COLLATE latin1_general_ci NOT NULL,
  `description` text COLLATE latin1_general_ci NOT NULL,
  `img_url` varchar(100) COLLATE latin1_general_ci NOT NULL,
  `active` int(1) NOT NULL,
  `time_to_discover` int(10) NOT NULL,
  `price` int(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=5 ;

--
-- Contenu de la table `utg_knowledge`
--

INSERT INTO `utg_knowledge` (`id`, `family`, `name`, `description`, `img_url`, `active`, `time_to_discover`, `price`) VALUES
(1, 'Culture', 'Théâtre', 'Le théâtre est l''épanouissement de soi !', '', 1, 86400, 1000),
(2, 'Guerre', 'Archérie', 'L''art de cribler un ennemi de flèches sans prendre de risques !', '', 1, 3600, 5000),
(3, 'Art', 'Peinture', 'L''ère des grands artistes !', '', 1, 36000, 10000),
(4, 'none', 'Superpuissance', 'La puissance des dieux', '', 1, 24575, 100000);

-- --------------------------------------------------------

--
-- Structure de la table `utg_knowledge_links`
--

CREATE TABLE IF NOT EXISTS `utg_knowledge_links` (
  `id_knowledge_parent` int(11) NOT NULL,
  `id_knowledge_child` int(11) NOT NULL,
  `type_parent` int(2) NOT NULL,
  PRIMARY KEY (`id_knowledge_parent`,`id_knowledge_child`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

--
-- Contenu de la table `utg_knowledge_links`
--

INSERT INTO `utg_knowledge_links` (`id_knowledge_parent`, `id_knowledge_child`, `type_parent`) VALUES
(1, 2, 1),
(2, 4, 1),
(3, 4, 1);

Voici tout le knowledge_model

Code PHP :
<?php 
class Knowledges_model extends Model
{
function
Knowledges_model()
{
parent::Model();
}

function
Get_knowledges()
{
$fief = $this->session->userdata('current_view_fief');
$knowledges = $this->db->query("
SELECT utg_knowledge.id AS id_knowledge, utg_knowledge.name AS name_knowledge, utg_knowledge.description AS description_knowledge,
utg_knowledge.price AS price_knowledge
FROM utg_knowledge INNER JOIN utg_country_knowledge ON utg_knowledge.id = utg_country_knowledge.id_knowledge
WHERE utg_country_knowledge.id_country =
$fief
AND utg_country_knowledge.knowledge_status = 2

"
);
return
$knowledges;

}

function
Get_started_knowledges()
{
$fief = $this->session->userdata('current_view_fief');

$started_knowledges = $this->db->query("
SELECT utg_knowledge.id AS id, utg_knowledge.time_to_discover AS research_time, utg_country_knowledge.knowledge_acquired AS start_date,
utg_knowledge.name AS name, utg_knowledge.description AS description, utg_knowledge.family AS family
FROM utg_knowledge INNER JOIN utg_country_knowledge ON utg_knowledge.id = utg_country_knowledge.id_knowledge
WHERE utg_country_knowledge.id_country =
$fief
AND utg_country_knowledge.knowledge_status = 1
ORDER BY family ASC

"
);
return
$started_knowledges;
}

function
Get_available_knowledges()
{

// On va chercher les savoirs disponibles.
// Les savoirs disponibles répondent a toutes les conditions de liaison et de descendance des autres savoirs
// Il faut d'abord récupérer tous les savoirs détenus par un country
$fief = $this->session->userdata('current_view_fief');

$available_knowledges = $this->db->query("
SELECT knowledge.id, knowledge.name, knowledge.family, knowledge.description, knowledge.img_url,
knowledge.time_to_discover, knowledge.price
FROM utg_knowledge knowledge
WHERE knowledge.active = 1 AND knowledge.id
NOT IN (
SELECT utg_knowledge_links.id_knowledge_parent
FROM utg_knowledge_links
WHERE utg_knowledge_links.id_knowledge_child
NOT IN (
SELECT utg_country_knowledge.id_knowledge
FROM utg_country_knowledge
WHERE utg_country_knowledge.id_country =
$fief
)
)
"
);

return
$available_knowledges;
}
}

Et dans le controller on retrouve

Code PHP :
<?php 
function knowledges()
{
$data = $this->Retrieve_informations();
$data['to_be_researched_knowledge'] = $this->Get_available_knowledges();
$data['knowned_knowledge'] = $this->Get_knowledges();
$data['started_knowledges'] = $this->Get_started_knowledges();

foreach(
$data['started_knowledges']->result() as $row)
{
$data['time_left'][$row->id] = $this->TimeToJourJ($row->start_date, $row->research_time);
}
$data["main_content"] = "game/knowledges.php";

$this->load->view("game/includes/template", $data);
}

function
Get_available_knowledges()
{
$this->load->model('knowledges_model');
$available_knowledges = $this->knowledges_model->Get_available_knowledges();
return
$available_knowledges;
}

function
Get_knowledges()
{
$this->load->model('knowledges_model');
$knowledges = $this->knowledges_model->Get_knowledges();
return
$knowledges;
}

function
Get_started_knowledges()
{
$this->load->model('knowledges_model');
$started_knowledges = $this->knowledges_model->Get_started_knowledges();
return
$started_knowledges;
}

En l'état, ma vue affiche "Théâtre" (id 1) et "Surpuissance" (id 4) en savoirs à rechercher alors que "Théâtre" est déjà acquis et que le savoir "Peinture" (id 3) nécessaire à "Surpuissance" n'est pas possédé par le country Saint Asrock (id 1)

Par défaut $fief = 1 (saint asrock)

J'ai sans doute fait une bourde <_<


RE: Bug d'enchainement de requêtes - srm - 29-08-2010

Regarde déjà si Get_available_knowledges() te retourne ce qu'il faut


RE: Bug d'enchainement de requêtes - Hiztaar - 29-08-2010

Négatif, il me renvoie que "théâtre" et "superpuissance" au lieu de "Peinture" seul
J'ai essayé en ajoutant un id 5 "artillerie".

Sans dépendance il est apparu a la suite de superpuissance.
Quand j'ai mis superpuissance en id parent d'artillerie, superpuissance a disparu mais artillerie est resté apparent <_<