如何通过层次结构连接加入同一张表?

Posted

技术标签:

【中文标题】如何通过层次结构连接加入同一张表?【英文标题】:How to join to same table over hierarchy connections? 【发布时间】:2019-10-29 19:45:47 【问题描述】:

我有 2 个表的简单数据结构。第一个表保存 json 文档

CREATE TABLE public."TableData" (
    dataid integer,
    tableid integer,
    data jsonb,
    "addedOn" date,
    ownerid integer,
)

这是表中的测试json数据示例

dataid  data
1       ""email": "lbush@gmail.com", "items": "qty": 24, "product": "Diaper", "lastname": "Bush", "firstname": "Lily""  "2019-10-29"    1
5       ""city": "Boston", "state": "MA", "rating": 1, "school": "Harvard"
12      ""major": "English", "credits": 350, "field of study": "Aerospace Engineering""

第二个表用于将文档连接在一起。 TableData.dataid 根据连接连接到“left_id”或“right_id”。

CREATE TABLE public.relations (
    relationid integer
    left_id integer,
    right_id integer,
    "addedOn" date,
    ownerid integer
)

这里有 2 行连接 3 个文档

          relationid    left_id     _right_id   
            1               1       5   
            2               5       12

我正在寻找正确的查询语法,它可以让我将任何文档层次结构连接在一起,以便我可以查询/过滤并正确显示输出。例如,这是一个仅将前两个文档链接在一起时有效的查询。

     SELECT Contact.data -> 'firstname' as firstname,School.data -> 'school' as schoolname
      from "public"."relations" as connections 
      left join "public"."TableData" as Contact
      on Contact.dataid = connections.left_id
      left join "public"."TableData" as School
      on School.dataid = connections.right_id

这正确输出:

   firstname    schoolname
   "Lily"       "Harvard"

但是,我现在如何扩展它以包含其他连接?我尝试了以下方法来链接第三个文档,但没有得到正确的输出。

    SELECT Contact.data -> 'firstname' as firstname,
    School.data -> 'school' as schoolname,
    Major.data -> 'major' as majorname
    from "public"."relations" as connections
    left join "public"."TableData" as Contact
    on Contact.dataid = connections.left_id
    left join "public"."TableData" as School
    on School.dataid = connections.right_id
    left join "public"."TableData" as Major
    on major.dataid = connections.right_id 
    left join "public"."TableData" 
    on School.dataid = connections.left_id

这是错误的输出:

        firstname   schoolname    major
        "Lily"      "Harvard"
        null         null       "Aerospace Enginering"

我想要/正在寻找的是:

       firstname    schoolname  major
       "Lily"       "Harvard"   "Aerspace Engineering"

如何将多个连接串到“关系”表以获得此输出??

【问题讨论】:

为什么会有这么奇怪的架构?您不能正确地对其进行规范化,以便拥有单独的表而不是与其自身相关的 json 对象表吗? 此模式的目标是支持最终用户定义的真正动态数据结构。关于如何最好地支持动态数据结构,旧的/最知名的方法 EAV,有无休止的讨论。展示讨论的好文章。 ***.com/questions/5106335/… 我相信 json/jsob 有更好的模型,但我需要支持它们之间数据元素的链接。有关如何使此查询起作用的任何想法? 我知道你在那里做了什么,但为什么不让最终用户更改你的架构呢?您仍然可以将 JSON 或 EAV 用于原始属性值,但是一旦您需要在实体之间建立链接并对其进行查询,我建议您为每个用户定义的表创建一个表,并为每个用户创建一个表(或列) -定义的关系,以便您可以正确设置外键。 我们已经讨论过这一点,但只是认为它在可扩展性和可维护性方面不可行。想想成千上万的用户创建了数十万个表。 当然,这也取决于表有多大以及对它们的查询有多复杂,但我敢打赌,专用的 RDMS 比您可以实施和维护的任何东西都能更好地扩展到这些维度你自己。最重要的是,它已经提供了您需要的大部分工具。 【参考方案1】:

您需要再次使用relations 表进行另一个N:N 连接,并删除匿名TableData 表:

SELECT
  Contact.data -> 'firstname' as firstname,
  School.data -> 'school' as schoolname,
  Major.data -> 'major' as majorname
FROM
  "public"."TableData" as Contact
  INNER JOIN "public"."relations" as connection1 ON (Contact.dataid = connection1.left_id)
  INNER JOIN "public"."TableData" as School ON (connection1.right_id = School.dataid)
  INNER JOIN "public"."relations" as connection2 ON (School.dataid = connection2.left_id)
  INNER JOIN "public"."TableData" as Major ON (connection2.right_id = Major.dataid)

为了简单起见,我使用了内连接,不确定是否要使用外连接以及如何对它们进行分组。

【讨论】:

谢谢!我觉得可能有错别字?它抱怨未定义底线中的“连接”。那应该是“作为 (major.right_id-connection3.leftid) 上的连接 3 吗? nm,我认为它是 INNER JOIN "public"."TableData" 作为 Major ON (connection2.right_id = Major.dataid)。现在可以了,非常感谢! @mikehennessy 修正了错字,感谢提及!

以上是关于如何通过层次结构连接加入同一张表?的主要内容,如果未能解决你的问题,请参考以下文章

有条件加入同一张表两次

SQL Server内部加入同一张表

避免多次加入同一张表

java 实体类 注解 继承问题!

如何在 sql server 2008 的同一张表中使用计数和分组方式和自连接?

加入同一张表