【问题标题】:SQL Conditional / Case Joining / Polymorphic Associations?SQL 条件/案例连接/多态关联?
【发布时间】:2026-02-13 07:20:03
【问题描述】:

我正在尝试实现类似于 Ruby on Rails 的多态关系的东西。 我有以下三个表:

活动 用户 组织

一个事件可以是用户或组织的所有者,所以我的事件表包括列:owner_type 和 owner_id。

我可以通过内部联接和 where 子句轻松列出属于用户或组织的所有事件,但是,有没有办法根据 owner_type 列的值使联接表有条件,允许所有事件一起列出,不管 owner_type 是什么?

我希望这是有道理的。

任何建议表示赞赏。

谢谢。

【问题讨论】:

    标签: sql polymorphic-associations


    【解决方案1】:

    您不能将连接表设置为有条件的,因此在这种情况下,您必须将事件连接到用户和组织,并使用 coalesce 将公共字段(例如名称)合并在一起。

    select e.id, coalesce(u.name, o.name) owner_name
    from events e
    left join users u on e.owner_id = u.id and e.owner_type = 'user'
    left join organisations o on e.owner_id = o.id and e.owner_type = 'org'
    

    但是,您可以考虑创建一个包含用户和组织的所有者表,其结构类似于 (id, type, org_id, name, ...)。这只需要一个连接,但可能会使您的架构的其他区域复杂化,例如。组织的用户成员资格。

    另一种方法是将用户和组织表联合在一起,然后从事件中加入一次。

    【讨论】:

    • +1,我在想,如果需要,您还可以将别名 U 和/或 O 中的任何列添加到选择列表中
    【解决方案2】:



    • Owner 具有所有所有者子类型共有的列。
    • PersonOrganization 各有特定的列。

    【讨论】:

      【解决方案3】:

      如何将所有权信息从Events 移到两个连接表EventsUsersEventsOrganisations(每个只有两列,FK 到Events 和相应的拥有对象表)?然后您可以UNION 两个查询,每个查询都通过连接表连接到拥有对象表。

      【讨论】:

        【解决方案4】:

        有点旧,但我认为它会很有用,这个版本在我的场景中比多个连接更好

        select e.id,
            case when e.owner_type = 'person' then
                (
                    select p.name from person p
                    where p.id=e.owner_id
                )
            else
                (
                    select o.name from organization o
                    where o.id=e.owner_id
                )
            end entityName,
        e.owner_type 
        from events e
        

        在 postgres 中,您甚至可以构建整个相关实体的 json

        【讨论】: