如何通过层次结构连接加入同一张表?
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 修正了错字,感谢提及!以上是关于如何通过层次结构连接加入同一张表?的主要内容,如果未能解决你的问题,请参考以下文章