如何使用联接从两个表中选择层次记录

时间:2020-02-15 04:33:07

标签: sql join hierarchy

实际上我想从两个表中选择匹配的记录,并从第一个表中选择分层数据

我有两个表:

  1. tmpos_category表,其中包含列(category_refid(pk),category_name,parent_ref_id)。我在其中存储分层数据。

  2. tmpos_menu_child表具有列(id(pk),title,category_ref_ids(fk))。 tmpos_menu_child表中的category_ref_ids字段引用了tmpos_category表中的 category_refid字段

this is a tmpos_category table with hierarchical categories

enter image description here

tmpos_menu_child table with category_ref_ids as fk refrances category(category_refid ) column

enter image description here

SELECT DISTINCT ct.category_name,ct.category_refid,ct.parent_ref_id
from tmpos_category ct
JOIN tmpos_menu_child tmc
ON ct.category_refid = tmc.category_ref_ids

现在我的问题是,当我加入tmpos_category表和tmpos_menu_child表时,我将获得所有不同的匹配类别,但我还希望选择类别的父记录

2 个答案:

答案 0 :(得分:0)

因此,当将此架构与parent_ref_id上的category table一起使用时,将很难向上移动层次结构并获得所有祖先类别,而无需编写每个父代都要硬编码1加入的查询。 / p>

如果您只有2或3代(例如孩子,父母,祖父母),那么这可以,但是如果使用更多(或可变级别),可能会变得凌乱。一种解决方案是使用“递归语法”,但据我所知并不是所有的SQL实现都支持它。

Bill Karwin具有出色的幻灯片组,详细介绍了架构的优缺点(通常称为“邻接列表”)。

您可以在幻灯片6-17上找到它:

setInterval()

他相当不错地详细说明了您的问题,并且如果您最终无法使用当前架构,则可以提供其他几种建模层次结构的策略。我个人喜欢该平台中最后一个细节,称为“封闭表”

编辑

实际上,如果您仅尝试包含一个或两个父级,那么您的查询将与连接3个或更多表的任何查询非常相似,只需要将categories表与其自身连接即可。如果您通过Google“将表自身连接”或类似的方法,应该很容易找到此类示例

答案 1 :(得分:0)

如果您的层次结构中只能有2个级别,即父级本身不能有父级,那么两个JOIN都可以。

SELECT i.id AS item_id, i.title AS item_title
     , c.category_refid, c.category_name
     , c.parent_ref_id, p.category_name AS parent_name
  FROM tmpos_menu_child i
  JOIN tmpos_category c ON c.category_refid = i.category_ref_ids
  LEFT JOIN tmpos_category p ON p.category_refid = c.parent_ref_id

如果层次结构可以很深,则应使用层次结构查询,在大多数DBMS中,它是通过递归CTE(公用表表达式)完成的。

WITH RECURSIVE Item_and_Cat (item_id, item_title, category_level,
                             category_refid, category_name, parent_ref_id) AS (
   SELECT i.id AS item_id, i.title AS item_title
        , c.category_refid, c.category_name
        , 1 AS category_level, c.parent_ref_id
     FROM tmpos_menu_child i
     JOIN tmpos_category c ON c.category_refid = i.category_ref_ids
   UNION ALL
   SELECT i.item_id, i.item_title
        , p.category_refid, p.category_name
        , i.category_level + 1 AS category_level, p.parent_ref_id
     FROM Item_and_Cat i
     JOIN tmpos_category p ON p.category_refid = i.parent_ref_id
)
SELECT item_id, item_title, category_refid, category_name, category_level
  FROM Item_and_Cat

注意: PostgreSQL和MySQL需要RECURSIVE关键字,而Oracle DB和SQL Server则不允许。


更新

来自comment

我希望有父母作为记录(在单独的行中)

要使父记录作为单独的行,请运行两次查询,然后与UNION组合。

SELECT i.id AS item_id, i.title AS item_title
     , c.category_refid, c.category_name, 0 AS is_parent
  FROM tmpos_menu_child i
  JOIN tmpos_category c ON c.category_refid = i.category_ref_ids
UNION ALL
SELECT i.id AS item_id, i.title AS item_title
     , p.category_refid, p.category_name, 1 AS is_parent
  FROM tmpos_menu_child i
  JOIN tmpos_category c ON c.category_refid = i.category_ref_ids
  JOIN tmpos_category p ON p.category_refid = c.parent_ref_id