【问题标题】:How to select hierarchical records from two tables using join如何使用连接从两个表中选择分层记录
【发布时间】:2020-02-15 04:33:07
【问题描述】:

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

我有两张桌子:

  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

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

【问题讨论】:

  • 您现在可以检查问题吗
  • 如果你不打算使用tmpos_menu_child 的任何栏目,为什么还要加入它?
  • 您说第一个表包含名为idcategory nameparent id 的列,但它们似乎被命名为category_refidcategory_nameparent_ref_id。 --- 你说第二个表包含名为iditem namecategory_id 的列,但前两个未显示在图像或查询中,最后一个似乎名为category_ref_ids。 --- 那是什么?请准确并指定正确的名称。编程要求你写的东西准确无误,你在写问题时也应该保持同样的严谨。
  • 这个不清楚。使用足够多的单词、句子和对部分示例的引用来清楚完整地表达你的意思。在给出业务关系(船舶)/关联或表(基础或查询结果)时,说明其中的一行根据其列值说明了业务情况。请use text, not images/links, for text--including tables & ERDs。仅将图像用于无法表达为文本或增强文本的内容。在图片中包含图例/键和说明。
  • 请在代码问题中给出minimal reproducible example--剪切&粘贴&运行代码;具有期望和实际输出(包括逐字错误消息)的示例输入(作为初始化代码);标签和版本;明确的规范和解释。对于包含最少代码的错误,您可以给出的代码是您显示的代码可以通过您显示的代码扩展为不正常。 (调试基础。)How to Ask 适用于包含 DBMS 和 DDL 的 SQL,其中包括约束、索引和表格初始化。

标签: sql join hierarchy


【解决方案1】:

如果您的层次结构中只能有 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

注意:RECURSIVE 关键字对于 PostgreSQL 和 MySQL 是必需的,但对于 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

【讨论】:

  • # category_name, category_refid, parent_ref_id, parent_name '冬季特餐', '4563', '0', NULL '太极碗饭', '4564', '0', NULL '素食宝', '4573', '4572', 'Bao' 'Non Veg Bao', '4574', '4572', 'Bao' '素点心', '4569', '4568', '点心' '素汤' , '4566', '4565', '汤' '鸡肉点心', '4570', '4568', '点心' '非蔬菜汤', '4567', '4565', '汤' '海鲜点心', '4571', '4568', 'Dimsum' 'Veg Starter', '4576', '4575', 'Starter' 'Chicken & Lamb Starter', '4577', '4575', 'Starter' 输出正确,但我希望有父母作为记录(在单独的行中)
  • @Nilesh 您在问题中从未说过,但请参阅答案的第二部分,它将分别返回所有父、祖父等行,category_level 指定父链到多远行来自。
  • 如何在 MySQL 工作台中运行答案脚本的第二部分给出错误
  • @Nilesh 必须是 MySQL 8。
【解决方案2】:

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

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

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

您可以在此处的幻灯片 6-17 上找到该内容:

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

他很好地详细说明了您的问题,并提供了其他几种建模层次结构的策略,如果您最终遇到当前架构的问题。我个人喜欢那副牌中的最后一张,它被称为“闭包表”

编辑

如果您实际上只尝试包含一个或两个父级别,那么您的查询看起来与连接 3 个或更多表的任何查询非常相似,只是您必须将 categories 表连接到自身。如果你用谷歌搜索“将一个表加入自身”或类似的东西,应该很容易找到这样的例子

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-23
    相关资源
    最近更新 更多