从mysql自联接中检索父值

时间:2010-10-01 22:51:24

标签: sql mysql hierarchical-data

我有一个包含字段的表:

  • ID
  • 名称
  • PARENT_ID
  • grandparent_id

我想选择id,name,parent name,grandparent name。

我可以通过自我加入来做到这一点吗?我基本上想要检索“name”值,其中parent_id = id并返回一行。

示例:

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

所以我想选择第3行(id = 3),但不是只返回parent_id和grandparent_id,我希望查询根据它们的id返回这些记录的名称。我可以创建一个复合字段,比如称为parent_id_name和grandparent_id_name吗?

我很确定我正在做的事情可以通过自我加入或子查询来实现,但到目前为止我尝试过的所有代码都无法正常工作。任何帮助都会非常感激。

3 个答案:

答案 0 :(得分:2)

这是您要求的查询:

# 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

但我还要补充说,拥有一个字段grandparent_id的冗余对我来说听起来不对...

你的桌子应该只是:

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

请注意,如果我知道12的父级,我就不需要在记录3上再次重复相同的信息......

在最后一种情况下,你的选择可能是这样的:

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

查询的工作方式相同,您也可以使用更多“规范化”的数据库。

编辑:这是非常基本的东西,但我想这与这个答案有关......

不应使用这种非规范化(即在同一记录上同时具有parent_idgrandparent_id),因为它允许数据库不一致。

例如,假设插入了一条新记录:

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

没有任何意义,对吗?记录4表明3是其祖父母。因此,3应该是记录2的父级。但这不是记录3本身所述的内容。哪条记录是对的?

您可能认为这是一个奇怪的错误,并且您的数据库永远不会像这样。但我的经验却说不然 - 如果可能发生错误,最终会发生错误。应该避免非规范化,不仅仅是因为某些数据库大师这样说,而是因为它确实增加了不一致性,并使维护更加困难。

当然,非规范化数据库可能更快。但是,根据经验,您应该考虑性能系统准备好生产后 之后,通过一些自动化或经验测试,存在瓶颈。相信我,我已经看到更糟糕的设计选择被错误的表现预期所证明......

答案 1 :(得分: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

答案 2 :(得分:1)

尝试这样,这是针对单亲

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

或 检查以下链接:

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