如何使用连接从两个表中 select 分层记录

How to select hierarchical records from two tables using join

实际上我想 select 匹配来自两个 table 的记录和第一个 table

的分层数据

我有两个 table:

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

  2. tmpos_menu_child table 与 列 (id(pk),title,category_ref_ids(fk))。 category_ref_ids 来自 tmpos_menu_child 的字段 table 引用了 tmpos_category table.[=16 的 category_refid 字段=]

this is a tmpos_category table with hierarchical categories

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

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 table 和 tmpos_menu_child table 时,我将获得所有不同的匹配类别,但我也想要 selected类别父记录

因此,当在 category table 上将此架构与 parent_ref_id 一起使用时,很难向上移动层次结构并获取所有祖先类别,而无需为每个 [ 编写硬编码 1 连接的查询=39=].

如果你只会有 2 或 3 代(例如 child、parent、grandparent)那么这没问题,但有更多(或可变级别)它会变得混乱。一种解决方案是使用 "recursive syntax",但据我所知并非所有 SQL 实现都支持它。

Bill Karwin 有一个出色的幻灯片,其中详细介绍了您的架构的 pros/cons(通常称为 "adjacency lists")。

您可以在此处找到幻灯片 6-17:

https://www.slideshare.net/billkarwin/models-for-hierarchical-data

他很好地详细说明了您的问题,并提供了其他几种建模层次结构的策略,如果您最终在使用当前模式时遇到问题。我个人喜欢那副牌中详细介绍的最后一张,它被称为 "closure table"

编辑

如果您实际上只是想包含一个或两个 parent 级别,那么您的查询将看起来与任何连接 3 个或更多 table 的查询非常相似,只是您必须将 categories table 加入自身。如果你 google "join a table to itself" 或类似的

应该很容易找到这样的例子

如果您的层次结构中只能有 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(常见的 table 表达式)完成的。

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 和 [=35] 不允许=] 服务器.


更新

来自

i want there parents as record(in seperate row)

要将父记录作为单独的行获取,运行 查询两次并与 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