2010-10-01 3 views
1

J'ai une table avec des champs:valeur parent Récupération de l'auto mysql rejoindre

  • id
  • Nom
  • PARENT_ID
  • grandparent_id

Je veux sélectionner l'identifiant, le nom , nom du parent, nom du grand-parent. Puis-je le faire avec une auto-jointure? Je veux essentiellement récupérer la valeur "name" où parent_id = id et retourner une ligne.

Exemple:

id  name  parent_id  grandparent_id 
----------------------------------------------- 
1  Milton  NULL   NULL 
2  Year 3  1    NULL 
3  Class A 2    1 

Donc, je veux choisir le 3ème rang (id = 3), mais au lieu de retourner tout le parent_id et grandparent_id, je veux la requête pour renvoyer les noms de ces documents en fonction de leur ids. Puis-je créer un champ composite, par exemple appelé parent_id_name et grandparent_id_name? Je suis assez sûr que ce que je fais peut être réalisé par une auto-jointure ou une sous-requête, mais tout le code que j'ai essayé jusqu'ici n'a pas fonctionné. Toute aide sera grandement appréciée.

Répondre

2

C'est la requête que vous avez demandé:

# By using LEFT JOINs you will be able to read any record, 
# even one with missing parent/grand-parent... 
SELECT 
    child.id, 
    child.name, 
    parent.id, 
    parent.name, 
    gparent.id, 
    gparent.name 
FROM 
    some_table child 
    LEFT JOIN some_table parent ON 
     parent.id = child.parent_id 
    LEFT JOIN some_table gparent ON 
     gparent.id = child.grandparent_id 
WHERE 
    child.id = 3 

mais j'ajouter que la redondance d'avoir un champ de grandparent_id ne sonne pas juste pour moi ...

Votre table doit être juste:

id  name  parent_id 
1  Milton  NULL 
2  Year 3  1 
3  Class A 2 

Notez que, si je sais que 1 est le parent de 2, je ne suis pas besoin de répéter cette même information à nouveau au dossier 3 ...

Dans ce dernier cas, votre sélection pourrait ressembler à ceci:

SELECT 
    child.id, 
    child.name, 
    parent.id, 
    parent.name, 
    gparent.id, 
    gparent.name 
FROM 
    some_table child 
    LEFT JOIN some_table parent ON 
     parent.id = child.parent_id 
    LEFT JOIN some_table gparent ON 
     gparent.id = parent.parent_id -- See the difference? 
WHERE 
    child.id = 3 

La requête ne fonctionnerait même, et vous auriez aussi plus base de données « normalisée ».

Edit: Ce est assez des trucs de base, mais je pense qu'il est pertinent pour cette réponse ...

Ce genre de dénormalisation (c.-à-parent_id ont tous les deux et grandparent_id sur le même dossier) ne devrait pas être utilisé car cela permet à la base de données d'être incohérente.

Par exemple, supposons qu'un nouvel enregistrement est inséré:

id  name   parent_id grandparent_id 
1  Milton   NULL  NULL 
2  Year 3   1   NULL 
3  Class A   2   1 
4  Invalid Rec  2   3 

Il ne fait pas de sens, non? Record 4 indique que 3 est ses grands-parents. Donc, 3 devrait être le parent de l'enregistrement 2. Mais ce n'est pas ce qui est déclaré sur le dossier 3 lui-même. Quel disque a raison?

Vous pensez peut-être que c'est une erreur étrange, et que votre base de données ne deviendra jamais comme ça. Mais mon expérience dit le contraire - si une erreur peut arriver, elle finira par se produire. La dénormalisation devrait être évitée, non seulement parce que certains gourous de la base de données le disent, mais parce que cela augmente réellement les incohérences et rend la maintenance plus difficile.

Bien sûr, les bases de données dénormalisées peuvent être plus rapide. Mais, en règle générale, vous devriez penser à la performance après votre système est prêt pour la production, et après vous avez perçu, au moyen d'un test automatisé ou empirique, qu'un goulot d'étranglement existe. Croyez-moi, je l'ai vu bien pire choix de conception étant justifiées par de fausses attentes de performance avant ...

+0

Je suis d'accord. La dénormalisation peut sauver une jointure comme dans ma réponse. –

+0

La raison pour le champ parent et grand-parent est parce que lire sur le net, les gens ont dit que la récursivité (juste parent_id) n'est pas très efficace, et le moyen le plus efficace (ensembles imbriqués) est complexe. Donc, cette structure de type «lignage» est un moyen heureux. Dans mon cas, je sais qu'il n'y aura qu'un maximum de deux niveaux de hiérarchie. –

+0

De plus, avec juste parent_id, est-il facile de sélectionner vers le bas dans la hiérarchie? par exemple. si je veux obtenir tous les enregistrements enfants/petits-enfants de l'enregistrement 1, comment cela pourrait-il être réalisé dans le modèle «normalisé»? –

1
SELECT t1.name, 
    MAX(CASE WHEN t2.id = t1.parent_id then t2.name end) as Parent, 
    MAX(CASE WHEN t2.id = t1.grandparent_id then t2.name end) as GrandParent 
FROM your_table t1 
LEFT OUTER JOIN your_table t2 ON t2.id IN (t1.parent_id, t1.grandparent_id) 
WHERE t1.id = 3 
group by t1.id, t1.name 
1

Essayez comme ça, c'est pour parent seul

SELECT e.entity_name AS 'entity', 
     m.entity_name AS 'parent' 
FROM table_name AS e 
LEFT OUTER JOIN table_name AS m ON e.entity_parent =m.entity_id 

ou vérifier le lien ci-dessous:

http://databases.about.com/od/sql/a/selfjoins.htm