Besoin d'aide pour une requête MySQL jointe + affichage (hiérarchisation de données)

WRInaute accro
Bonjour,

Je suis en train de développer un site web mais mes connaissances en MySQL me font bloquer sur ce que pas mal d'entre vous doivent considérer comme une broutille.
M'apporteriez-vous un peu d'aide ?

J'ai deux tables dans ma base MySQL.

Je souhaiterais afficher, à partir des données suivantes :
taxonomie_data
original.jpg

taxonomie_hierarchie
original.jpg


La liste qui suit :
Entrées
  • Salades
  • Feuilletés
  • Légumes
  • Fromage
Plats
  • Viande
  • Volaille

En sachant que dans la table taxonomie_hierarchie, 'parent' est l'équivalence du tid de la table taxonomie_data (afin de pouvoir recouper les données).

Quelle requête effectuer ?
Comment l'afficher en regroupant les termes relatifs aux "Entrées" et ceux relatifs aux "Plats" ?

Je suis paumé, j'ai repris cette structure de la taxonomie de Drupal qui est très très bien faite.

Merci à vous !

Mais je suis totalement infoutu d'y arriver.
 
WRInaute impliqué
Code:
SELECT
    Data.nom
    Data2.nom
FROM
    taxo_data as Data,
    taxo_data as Data2,
    taxo_hier as Hier
WHERE 
    Data.tid = Hier.tid AND
    Hier.parent <> 0    AND
    Hier.parent = Data2.tid
ORDER BY
    Hier.parent ASC, Data.poids ASC

et dans ton PHP tu affiche ton Data2.nom que si il est différent de celui d'avant :
Code:
$oldNom = ''
foreach($mesResultats as $thisResult):
    if($oldNom != $thisResult->Data2->nom):
        $oldNom = $thisResult->Data2->nom;
        echo $oldNom
    endif
    echo $thisResult->Data->nom
endforeach


A toi de remplacer par ta syntaxe.
A essayer (je ne promet rien)... Bonne chance !

Au pire, envoi un export des 2 tables en sql pour que l'on puisse tester en "vrai"

EDIT : il y a surement bcp plus optimisé je pense ...
 
WRInaute accro
Evidemment ça ne marchera que sur deux niveaux (sinon il faut multiplier le nombre de références à taxo_data et taxo_hier).

Une autre option consiste à faire une requête pour chaque "niveau", et d'utiliser une procédure récursive (qui s'appelle elle-même).

Genre:
Code:
function affiche_niveau($niveau)
{
  ... requete SQL genre select * from taxo_data td,taxo_hier as th where td.tid=th.tid and th.parent=$niveau
  boucle sur résultats
  {
    ... afficher résultat ...
    affiche_niveau($resultat->tid);
  }
}

Evidemment ça fait plus de requêtes SQL, ce qui n'est pas forcément idéal, mais un petit cache peut aider.

Jacques.
 
WRInaute impliqué
J'ai jamais osé faire de la récursivité en PHP ... et je me demande à l'instant pourquoi ...
bonne idée Jacques !

Bon courage et tiens nous au courant
 
WRInaute accro
Merci je regarde tout ça demain, par contre Drupal core arrive à faire le résultat en UNE requête.
Je pense que tout se joue au niveau du tri de l'array des résultats en PHP.
C'est surement moins gourmand en ressources.
 
WRInaute accro
Ben plusieurs options:
- tu limites à 2 niveaux, et la requête donnée plus tôt fait effectivement tout ça en une seule requête
- tu fais une série de union avec 1 niveau, 2 niveaux, 3 niveaux, etc.
- tu fais une seule requête avec juste une jointure entre les deux tables, et le traitement se fait au niveau php pour reconstruire l'"arbre" et l'afficher. Pas top difficile ceci dit. Je ne m'aventurerai pas à l'écrire en php parce que je n'ai pas l'habitude mais en perl par exemple ça donnerait quelque chose du genre (pas testé):

Code:
sub display_tree
{
  my $children = shift;
  my $node = shift;

  print "<UL>";
  print "<LI>$node->{name}</LI>";
  display_tree($children,$_) for @{$children->{$node->{tid}};
  print "</UL>";
}

sub read_tree
{
  my $dbh = shift;

  my $nodes = $dbh->selectall_arrayref("SELECT * FROM taxo_data td,taxo_hier th WHERE td.tid=td.tid");
  my $children;
  for my $node (@$nodes)
  {
    push @{$children->{$node->{parent}}}, $node;
  }
  display_tree($children,$children->{0});
}

Je pense que ça montre bien qu'un peu de récursivité ça aide. Sinon on peut y arriver en gérant une pile, mais ça revient au même.

Il y a peut-être aussi une option avec un group_concat qui permet de déplacer la préparation de la liste des enfants dans la bdd.

Bref, there's more than one way to do it :)

Jacques.
 
WRInaute impliqué
milkiway a dit:
Merci je regarde tout ça demain, par contre Drupal core arrive à faire le résultat en UNE requête.
Je pense que tout se joue au niveau du tri de l'array des résultats en PHP.
C'est surement moins gourmand en ressources.
Tu peux surement echo la requête de drupal et la copier non ?
 
WRInaute accro
Bon et bien j'ai beau tout essayer je n'y arrive pas :(
Voici la table (j'ai regroupé les deux tables puisqu'il n'y avait pas d'intérêt d'en avoir deux) :
Code:
-- phpMyAdmin SQL Dump
-- version 3.1.3.1
-- http://www.phpmyadmin.net
--
-- Serveur: localhost
-- Généré le : Ven 24 Juillet 2009 à 10:11
-- Version du serveur: 5.1.33
-- Version de PHP: 5.2.9-2

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

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

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

--
-- Structure de la table `taxonomie_data`
--

CREATE TABLE IF NOT EXISTS `taxonomie_data` (
  `tid` tinyint(4) NOT NULL AUTO_INCREMENT,
  `vid` tinyint(4) NOT NULL,
  `hid` tinyint(4) NOT NULL,
  `nom` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `description` text COLLATE utf8_unicode_ci NOT NULL,
  `poids` tinyint(4) NOT NULL,
  PRIMARY KEY (`tid`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=9 ;

--
-- Contenu de la table `taxonomie_data`
--

INSERT INTO `taxonomie_data` (`tid`, `vid`, `hid`, `nom`, `description`, `poids`) VALUES
(1, 1, 0, 'Entrées', 'Recettes d''entrées.', 1),
(2, 1, 0, 'Plats', 'Recettes de plats.', 2),
(3, 1, 1, 'Salades', 'Recettes de salade.', 1),
(4, 1, 1, 'Feuilletés', '', 2),
(5, 1, 1, 'Légumes', '', 3),
(6, 1, 2, 'Fromage', '', 4),
(7, 1, 2, 'Viande', '', 1),
(8, 1, 2, 'Volaille', '', 2);
Mon but étant d'avoir un résultat du type :
-Entrées
--Salades
--Feuilletés
--Légumes
-Plats
--Fromage
--Viande
--Volaille

Je sais que c'est tout bête, mais je vous assure, après avoir passé plus d'une heure, je n'arrive à rien, pire, je sature le serveur avec des boucles infinies !

Je pense qu'il doit y avoir un moyen d'y arriver facilement et surtout sans consommer trop de ressources, en tout cas c'est le but.

A vot' bon coeur et un grand merci d'avance.

tid = id du terme
vid = id du vocabulaire, ici 1 à chaque fois
hid = indication de hiérarchie
poids = juste pour classer
 
Discussions similaires
Haut