2009-07-24 8 views
3

Avec seulement un peu d'expérience avec les bases de données et sans éducation formelle avec eux, je suis un peu coincé quant à la façon de modéliser cela (et de récupérer les données dont j'ai besoin en PHP). C'est ce que j'essaie de modéliser:Comment modéliser une relation plusieurs à plusieurs?

Pour chaque article sur mon site, il est permis d'avoir plusieurs tags tels que fichier, upload, php, récursif etc. Cependant les tags sont réutilisables, je peux avoir deux tags différents articles et ils pourraient chacun avoir l'étiquette php.

J'ai essayé de lire sur la façon de faire cela et si c'est un manque d'expérience ou quelque chose d'autre que je ne sais pas, mais je n'arrive pas à saisir le concept. Apparemment, vous avez besoin d'une table du milieu qui relie les deux ensemble?

Aussi, une fois que j'ai cette relation et les tables définies, comment ferais-je des choses telles que: - Récupérer tous les éléments avec un certain tag? - Récupérer toutes les étiquettes d'un article?

Merci pour votre aide, même si quelqu'un pouvait ajouter d'autres lectures à ce sujet pour renforcer ma compréhension du concept qui serait génial.

Répondre

7

La partie db est facile. Ceci est juste un exemple, donc vous pouvez voir comment peut ressembler la base de données, pas de requêtes SQL particulières.

CREATE TABLE posts (
    id INT PRIMARY KEY, 
    subject VARCHAR(100), 
    body TEXT 
) 

CREATE TABLE tags (
    id INT PRIMARY KEY, 
    name VARCHAR(50) 
) 

CREATE TABLE post_tags (
    post_id INT, 
    tag_id INT, 
    FOREIGN KEY (post_id) REFERENCES posts (id), 
    FOREIGN KEY (tag_id) REFERENCES posts (id) 
) 

pour obtenir des éléments avec le tag yourTag vous suffit d'exécuter la requête comme celui-ci

SELECT P.* 
FROM posts P 
    LEFT JOIN post_tags PT ON (PT.post_id = P.id) 
    LEFT JOIN tags T ON (T.id = PT.tag_id) 
WHERE T.name = 'yourTag'; 

Pour obtenir des tags associés à poste avec id de 123 vous exécutez cette requête:

SELECT T.* 
FROM tags T 
    LEFT JOIN post_tags PT ON (T.id = PT.tag_id) 
    LEFT JOIN posts P ON (PT.post_id = P.id) 
WHERE P.id = 123; 

Pour la partie PHP vous pouvez utiliser un framework. De nombreux cadres (sinon tous) peuvent facilement modéliser de telles relations. Par exemple, dans CakePHP ce fait comme ça:

class Post extends AppModel { 
    $useTable = 'posts'; 
    $hasAndBelongsToMany = array(
     'Tag' => array(
      'className' => 'Tag' 
      'joinTable' => 'post_tags' 
      'foreignKey' => 'post_id' 
      'associationForeignKey' => 'tag_id' 
     ) 
    ); 
} 

class Tag extends AppModel { 
    $useTable = 'tags'; 
    $hasAndBelongsToMany = array(
     'Post' => array(
      'className' => 'Post' 
      'joinTable' => 'post_tags' 
      'foreignKey' => 'tag_id' 
      'associationForeignKey' => 'post_id' 
     ) 
    ); 
} 
+0

ITYM Tag -> $ hasAndBelongsToMany = array ('Post' ... etc. – Stobor

+0

Merci pour la partie base de données des thats fantastique. J'utilise CodeIgniter et cela ne modélise pas les relations comme ça, vous devez le faire vous-même. De plus, je préférerais comprendre les requêtes SQL impliquées plutôt que de me fier à automagic. – Zim

+0

@Stobor - merci de trouver cela, c'était une erreur de copie – RaYell

0

Vous avez raison, beaucoup à plusieurs relations sont mises en œuvre en utilisant le tableau supplémentaire, par exemple:

Blog_entry(entry_id, entry_body) 
Tag(tag_id, tag_name) 
Entry_tag(entry_id, tag_id) 

Toutes les opérations sont effectuées à l'aide de multiples joint. Par exemple, si vous voulez sélectionner toutes les entrées avec le tag « foo », en utilisant des tables de mon exemple, vous devez exécuter:

select * 
from 
    blog_entry, tag, entry_tag 
where 
    tag.tag_name = 'foo' and 
    entry_tag.tag_id = tag.tag_id and 
    entry_tag.entry_id = blog_entry.entry_id 

(mise à jour) Pour récupérer tous les tags entrée particulière (ici avec ID 123) a:

select tag_name 
from 
    blog_entry, tag, entry_tag 
where 
    Blog_entry.entry_id = 123 
    entry_tag.tag_id = tag.tag_id and 
    entry_tag.entry_id = blog_entry.entry_id 
0

Ouais, la relation plusieurs-à-plusieurs a besoin d'une troisième table appelée table d'association.

partie de la base de données est pas si difficile, il est plus difficile de l'utiliser dans le code avec tous ceux de gauche se joint et il peut être assez en désordre :)

Mon conseil est d'utiliser le cadre ORM, comme Doctrine ou Propel (bien que je préférez Doctrine), qui gère même des requêtes complexes pour vous.

5

Vous devez utiliser une table intermédiaire, pour relier les deux entités:

 
--------  1:n ------------   --------- 
| ITEM |-¦---------<| ITEM_TAG | n:1 | TAG | 
| Id |   | ItemId |>-------¦-| Id | 
| Name |   | TagId |   | Name | 
¯¯¯¯¯¯¯¯   ¯¯¯¯¯¯¯¯¯¯¯¯   ¯¯¯¯¯¯¯¯¯ 

Ensuite, pour interroger les données, vous devez join vos tables dans une instruction select:

Tous les éléments de l'étiquette "FooTag"

SELECT item.* FROM item 
       JOIN item_tag on item.id = item_tag.itemId 
       JOIN tag on item_tag.tagId = tag.id 
WHERE tag.Name = 'FooTag' 

Toutes les balises pour l'élément avec le nom "FooItem "

SELECT tag.* FROM tag 
      JOIN item_tag on tag.id = item_tag.tagId 
      JOIN item on item_tag.itemId = item.id 
WHERE item.Name = 'FooItem' 
+0

joli diagramme :) +1 –

Questions connexes