【问题标题】:How to build relationships using data from two tables?如何使用来自两个表的数据建立关系?
【发布时间】:2016-12-09 20:29:47
【问题描述】:

我正在 Postgres 中构建迁移,我需要为每个组织添加一个新用户。

假设我有树表:

  • 用户
  • 组织
  • user_org

并且组织列表已经存在于数据库中。

现在我正在根据其他用户和修改过的数据创建新用户,如下所示:

insert into users
select
  ...
from users where ...
returning id

我现在需要将每个用户与一个组织相关联(假设创建的用户数和组织数匹配)。

cross join 不起作用,因为它会将所有用户关联到所有组织。

鉴于新创建的用户具有不同的键,我从中复制的用户列表已经与组织关联,是否有一种简单的方法可以基于此构建我的查询?

【问题讨论】:

  • 不确定我是否完全理解您的问题。假设您有 10 个组织,您想插入 10 个用户,每个组织 1 个?也许样本数据和预期结果会有所帮助。
  • Postgres 版本和表定义会膨胀。

标签: sql postgresql many-to-many sql-insert


【解决方案1】:

鉴于新创建的用户具有不同的键,我从中复制的用户列表已经与组织关联,是否有一种简单的方法可以基于此构建我的查询?

如果有任何列子集可以在没有 PK 的情况下识别唯一用户,则可以使用具有数据修改 CTE 的安全解决方案。您甚至可以一次插入多个用户副本:

WITH template_user AS (
   SELECT u.*, uo.org_id  -- include the connected org_id
   FROM   users    u
   JOIN   user_org uo ON uo.user_id = u.id  -- guessing column names
   WHERE  ...  --  make sure exactly *one* desired org is joined
   )
, ins_user AS (
   INSERT INTO users u (...)
   SELECT ... 
   FROM   template_user t
   WHERE  ...
   RETURNING *
   )
INSERT INTO user_org (user_id, org_id)
SELECT iu.id, tu.org_id
FROM   ins_user      iu
JOIN   template_user tu USING (<list of columns that secures distinct join>)
RETURNING *;  -- optional

在不太可能的情况下,您不应该有一组可靠的列来连接到模板用户:添加一个行号,例如 @sgeddes already suggested,但在实际有效的查询中:

WITH template_usr AS (
   SELECT u.*, uo.org_id  -- include the connected org_id
          row_number() OVER () AS rn  -- arbitrary number
   FROM   usr     u
   JOIN   usr_org uo ON uo.usr_id = u.id  -- guessing column names
   WHERE  ...  --  make sure exactly *one* desired org is joined
   )
, ins_usr AS (
   INSERT INTO usr u (...)  -- add target columns
   SELECT ... 
   FROM   template_usr
   ORDER  BY rn             -- insert in same order!
   RETURNING id
   )
INSERT INTO usr_org (usr_id, org_id)
SELECT iu.id, tu.org_id
FROM  (
   SELECT id, row_number() OVER (ORDER BY id) AS rn
   FROM   ins_usr
   ) iu
JOIN   template_usr tu USING (rn)
RETURNING *;  -- optional

相关:

【讨论】:

    【解决方案2】:

    如果我理解正确,这是一个使用inner join 的选项,然后在每个表上建立一个row_number 到join:

    insert into user_org
    select u.id, o.id 
    from (select id, row_number() over (order by id) rn
          from usr) u join 
         (select id, row_number() over (order by id) rn
          from org) o on u.rn = o.rn
    

    【讨论】:

    • 看起来它可以满足我的需要,我会做更多的测试并回复。谢谢!
    • order by id 在两个子查询中都要求usr.id 和org.id 的值 同步——这是一个非常不可能的假设。当然不是基于问题中的信息。通常,此查询不起作用。
    • @ErwinBrandstetter -- 同意 -- 我在发帖之前提出的原始问题也类似。我认为给出答复是任意的,因此row_number 的这种实现应该可以工作。但是,最好在用户和组织之间存在相关性。
    • @ErwinBrandstetter -- 在阅读了您的帖子(在实际有效的查询中)之后,您假定用户组织是在用户创建时创建的。如果不是这种情况,正如我没有假设的那样,您的查询将无法与join... ,并在连接表中插入 1-1(不知道为什么)。除了我对 OP 的问题之外,这对我来说很突出(assuming that number of created users and numbers of orgs matching) 不管怎样,你有 imo 的烦躁反应......
    • 将特定用户与特定组织匹配并不重要,唯一重要的是每个组织都拥有这些用户之一。所以解决方案工作正常。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-20
    • 1970-01-01
    • 2020-01-17
    • 1970-01-01
    相关资源
    最近更新 更多