Partage
  • Partager sur Facebook
  • Partager sur Twitter

Catégories et sous-catégories

    20 juin 2010 à 16:52:49

    Bonjour à tous :)

    Je suis entrain de mettre au point dans ma base de données des catégories et sous catégories dans lesquelles se trouveront des objets.
    Il y a quelques subtilités qui me compliquent la tâche.
    En effet, chaque catégorie à un nom mais dans plusieurs langues !
    Chaque catégorie peut avoir une ou aucune catégorie mère.
    Mais chaque catégorie peut avoir aucune, une ou plusieurs sous catégories.
    Par contre pour le moment en tout cas, un objet n'appartient qu'à une seule catégorie !
    (Je pense qu'une table supplémentaire serait nécessaire si je le voulais).

    Voilà comment je voix le truc pour le moment, j'aimerais avoir votre avis,
    Pensez vous que je m'y prend bien où bien peut on faire plus simple ou plus propre ?

    J'ai donc une table catégorie avec les champs suivants
    - id (INT) : Simplement l'id de la catégorie (Primary Key)
    - mere_id (INT) : Est l'id de la catégorie mère (peut être NULL) (Foreign Key)
    - position (INT) : Simplement un paramètre pour l'ordre d'affichage des catégories

    Et une table langue_categorie
    - categorie_id : L'id de la catégorie dont on contient le nom (Fait partie de la Primary Key)
    - langue : Simplement la langue de traduction. Exemple : fr en es etc... (Fait partie de la Primary Key)
    - nom : Enfin, le nom de la catégorie dans la langue spécifiée au dessus.

    Image utilisateur

    Merci d'avance pour vos conseils !!

    Bonne journée.

    Balzard

    EDIT : Pour ceux qui préfère le SQL
    -- -----------------------------------------------------
    -- Table `db`.`categorie`
    -- -----------------------------------------------------
    CREATE  TABLE IF NOT EXISTS `db`.`categorie` (
      `id` INT NOT NULL AUTO_INCREMENT ,
      `mere_id` INT NULL DEFAULT NULL ,
      `position` INT NOT NULL DEFAULT 0 ,
      PRIMARY KEY (`id`) ,
      INDEX `fk_categorie_categorie` (`mere_id` ASC) ,
      CONSTRAINT `fk_categorie_categorie`
        FOREIGN KEY (`mere_id` )
        REFERENCES `db`.`categorie` (`id` )
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB;
    
    
    -- -----------------------------------------------------
    -- Table `db`.`langue_categorie`
    -- -----------------------------------------------------
    CREATE  TABLE IF NOT EXISTS `db`.`langue_categorie` (
      `categorie_id` INT NOT NULL ,
      `langue` VARCHAR(2) NOT NULL ,
      `nom` VARCHAR(45) NOT NULL ,
      PRIMARY KEY (`categorie_id`, `langue`) ,
      INDEX `fk_langue_categorie_categorie` (`categorie_id` ASC) ,
      CONSTRAINT `fk_langue_categorie_categorie`
        FOREIGN KEY (`categorie_id` )
        REFERENCES `db`.`categorie` (`id` )
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB;
    
    • Partager sur Facebook
    • Partager sur Twitter
      20 juin 2010 à 18:33:39

      Quelle est la question exactement ?

      La structure semble bonne, mais comme tu n'as pas la possibilité d'utiliser les requêtes récursives avec MySQL, tu ne pourras pas, par exemple, sélectionner toutes les catégories et leurs enfants d'une manière hiérarchique.
      • Partager sur Facebook
      • Partager sur Twitter
        20 juin 2010 à 19:05:54

        Ta structure est très bonne rien à dire. Ce que tu as crée s'appelle une structure d'arbre, avec ses nœuds et ses feuilles.

        Personnellement c'est la façon que j'utilise pour coder toutes mes arborescences en BD, comme un menu avec des sous-menu, sous-sous-menu...

        Tu ne peux pas faire plus simple puisque ton schéma est normalisé en Boyce-Codd.

        Petite remarque histoire de dire quelque chose :p . Tu marques cela :
        `id` INT NOT NULL AUTO_INCREMENT ,
        

        Pas besoin du NOT NULL puisque tu dis plus bas PRIMARY KEY pour id ce qui signifie UNIQUE+NOT NULL.

        Et ça `mere_id` INT NULL DEFAULT NULL ,


        Enfin c'est vraiment chercher la petite bête :p
        • Partager sur Facebook
        • Partager sur Twitter
        Anonyme
          20 juin 2010 à 19:36:15

          Pour aller plus loin dans la perfection il est important d'être rigoureux dans le nom des objets en général et des colonnes.

          Les clé étrangères doivent avoir le même nom que les clé primaires auxquelles elles font référence.
          C'est à la fois cohérent, une même info a le même nom dans toute la BDD et c'est extrèmement pratique => jointure naturelle.

          Donc dans la table categorie remplace id par categorie_id comme tu l'as fais dans l'autre table.
          • Partager sur Facebook
          • Partager sur Twitter
            26 juin 2010 à 21:35:28

            Merci beaucoup pour vos réponses :)

            Je me permet de faire remonter le topic car j'ai un peu de difficulté pour créer une requête ...

            Donc voilà, j'essaie d'écrire une requête SQL qui irait chercher l'ensemble des catégories et associé à chacune d'elle son nom dans toute les langues disponibles (dans la table langue_categorie)

            Le début serait :

            SELECT c.id, c.position FROM categorie c
            


            Et après je dois encore récupérer les entrées dans la table langue_categorie là où c.id = lc.categorie_id. Mais je n'y parviens pas, je pense que je dois faire une jointure mais aussi un GROUP BY :/

            Si quelqu'un pouvait m'aider un peu, ce serait vraiment sympa :)

            Bonne soirée à tous !

            Balzard.
            • Partager sur Facebook
            • Partager sur Twitter
              26 juin 2010 à 23:09:38

              Tu essaie de créer l'arborescence c'est ça ?
              • Partager sur Facebook
              • Partager sur Twitter
                26 juin 2010 à 23:29:31

                Non non !
                Pour le moment je veux juste récupérer la liste des entrée dans la table catégories indépendamment de savoir si c'est une catégorie ou une sous-catégorie.

                Mon problème c'est que je n'arrive pas à lier la table langue_categories dans ma requête :/
                • Partager sur Facebook
                • Partager sur Twitter
                  26 juin 2010 à 23:31:38

                  Pourquoi veux-tu les lier tout de suite ? Une jointure serait inutile si tu ne recherches pas à obtenir l'arborescence.
                  • Partager sur Facebook
                  • Partager sur Twitter
                    26 juin 2010 à 23:37:50

                    Tu peux faire une simple jonction, auquel cas tu auras autant de ligne par catégorie que tu as de langue... Donc ça risque d'être assez moche.

                    Si tu veux avoir une seule ligne par catégorie, à 23h37 je vois pas :p
                    • Partager sur Facebook
                    • Partager sur Twitter
                      26 juin 2010 à 23:47:01

                      Haha :p

                      Oui donc pour encore préciser :

                      Je cherche donc à lister le contenu de la table catégorie (sans gérer l'arborescence ni rien) et en joignant pour chaque catégorie, ses traductions.

                      Donc au final c'est pour afficher ça :

                      ID---ID_Mere---Nom
                      1---NULL---fr:Bonjour, en:Hello
                      2---1---fr:Aurevoir, it:ciao
                      ...
                      ...

                      Le problème comme Ulspider le signale c'est que si je fais une jointure, j'aurai autant de fois chaque catégorie qu'elle a de traduction. C'est à dire :
                      ID---ID_Mere---Nom
                      1---NULL---fr:Bonjour
                      1---NULL---en:Hello
                      2---1---fr:Aurevoir
                      2---1---it:ciao
                      ...
                      ...

                      Et ça évidement ça va pas.
                      Je pense donc que je dois utiliser un GROUP BY mais je sais pas comment :/

                      Merci :)
                      • Partager sur Facebook
                      • Partager sur Twitter
                        26 juin 2010 à 23:56:49

                        Si tu veux récupérer toutes les informations dans la même colonne, tu n'as qu'à utiliser GROUP_CONCAT :

                        SELECT c.categorie_id, c.mere_id, GROUP_CONCAT(CONCAT(l.langue, ':', l.nom) SEPARATOR ', ')
                        FROM categorie c
                        INNER JOIN langue_categorie l
                            ON c.categorie_id = l.categorie_id
                        GROUP BY c.categorie_id, c.mere_id;
                        


                        J'ai jamais utilisé GROUP_CONCAT, si c'est pas exactement comme ça essaie de modifier un peu.
                        • Partager sur Facebook
                        • Partager sur Twitter
                          27 juin 2010 à 0:19:37

                          Merci beaucoup !

                          Je sens que c'est tout proche :D

                          Euh petite question, n'y a t il pas moyen de récupérer un array plutôt que la concaténation ? :/

                          En fait au final, j'aimerais avoir quelque chose comme ceci :
                          Array
                          (
                              [0] => Array
                                  (
                                      [id] => 1
                                      [mere_id] => 
                                      [position] => 0
                                      [created_at] => 2010-06-27 00:09:15
                                      [updated_at] => 2010-06-27 00:09:17
                                      [traduction] => Array
                                      (
                                      	[1] => Array
                                      	(
                                      		[langue] => it
                                      		[nom] => Ciao
                                      	)
                                      	[2] => Array
                                      	(
                                      		[langue] => fr
                                      		[nom] => Au revoir
                                      	)
                                      )
                                  )
                          
                              [1] => Array
                                  (
                                      [id] => 2
                                      [mere_id] => 
                                      [position] => 0
                                      [created_at] => 2010-06-27 00:09:29
                                      [updated_at] => 2010-06-27 00:09:31
                                      [traduction] => Array
                                      (
                                      	[1] => Array
                                      	(
                                      		[langue] => fr
                                      		[nom] => Bonjour
                                      	)
                                      	[2] => Array
                                      	(
                                      		[langue] => en
                                      		[nom] => Hello
                                      	)
                                      )
                                  )
                          )
                          


                          Si c'est vraiment nécessaire, je ferai du post-traitement en php pour réorganiser mon array :)

                          Et dans le GROUP BY, pourquoi mets-tu c.categorie_id et aussi c.mere_id ?

                          Encore merci pour ton aide ! :D
                          • Partager sur Facebook
                          • Partager sur Twitter
                            28 juin 2010 à 13:19:14

                            Bon et bien me revoilà :D

                            J'ai un peu chipoté et en fait en utilisant GROUP_CONCAT ça le fait avec un petit post-traitement :)

                            Par contre, ce serait plus approprié dans la catégorie PHP mais que pensez vous de mon post traitement ?
                            N'est il pas trop lourd ? :/

                            <?php
                            $request = $pdo->prepare("SELECT
                            			c.id,
                            			c.mere_id,
                            			c.created_at,
                            			c.updated_at,
                            			GROUP_CONCAT(CONCAT(l.langue, '" . ADMIN_CATEGORIES_TRANSLATION_SEPARATOR_ONE . "', l.nom) SEPARATOR '" . ADMIN_CATEGORIES_TRANSLATION_SEPARATOR_TWO . "') as translations
                            			FROM categorie c
                            			INNER JOIN langue_categorie l ON c.id = l.categorie_id
                            			GROUP BY c.id, c.mere_id
                            			ORDER BY $pOrderBy $pDirection");
                            		$request->execute();
                            		if ($result = $request->fetchAll(PDO::FETCH_ASSOC))
                            		{
                            			$request->closeCursor();
                            			// Nous devons séparer les traductions
                            			foreach ($result as &$categorie)
                            			{
                            				$temp = explode(ADMIN_CATEGORIES_TRANSLATION_SEPARATOR_TWO, $categorie['translations']);
                            				$categorie['translations'] = Array();
                            				foreach ($temp as $traduction)
                            				{
                            					$tempTwo = explode(ADMIN_CATEGORIES_TRANSLATION_SEPARATOR_ONE, $traduction);
                            					$categorie['translations'][$tempTwo[0]] = $tempTwo[1];
                            				}
                            			}
                            			return $result;
                            		}
                            ?>
                            


                            Voilà le résultat :)
                            Array
                            (
                                [0] => Array
                                    (
                                        [id] => 2
                                        [mere_id] => 
                                        [position] => 0
                                        [scl_visible] => 1
                                        [scl_commission] => 1
                                        [scnl_visible] => 1
                                        [scnl_commission] => 1
                                        [created_at] => 2010-06-27 00:09:29
                                        [updated_at] => 2010-06-27 00:09:31
                                        [translations] => Array
                                            (
                                                [en] => Hello
                                                [fr] => Bonjour
                                            )
                            
                                    )
                            
                                [1] => Array
                                    (
                                        [id] => 1
                                        [mere_id] => 
                                        [position] => 0
                                        [scl_visible] => 1
                                        [scl_commission] => 1
                                        [scnl_visible] => 1
                                        [scnl_commission] => 1
                                        [created_at] => 2010-06-27 00:09:15
                                        [updated_at] => 2010-06-27 00:09:17
                                        [translations] => Array
                                            (
                                                [fr] => Au revoir
                                                [it] => Ciao
                                            )
                            
                                    )
                            
                            )
                            


                            Merci d'avance :)
                            • Partager sur Facebook
                            • Partager sur Twitter

                            Catégories et sous-catégories

                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                            • Editeur
                            • Markdown