【问题标题】:How to migrate IDs from JOIN table into foreign key column in PostgreSQL如何将 JOIN 表中的 ID 迁移到 PostgreSQL 中的外键列
【发布时间】:2020-05-13 05:28:31
【问题描述】:

我的 PostgreSQL 数据库中有以下表格:

CREATE TABLE "User" (
  id VARCHAR(25) PRIMARY KEY NOT NULL
);

CREATE TABLE "Post" (
  id VARCHAR(25) PRIMARY KEY NOT NULL
);

CREATE TABLE "_PostToUser" (
  "A" VARCHAR(25) NOT NULL REFERENCES "Post"(id) ON DELETE CASCADE,
  "B" VARCHAR(25) NOT NULL REFERENCES "User"(id) ON DELETE CASCADE
);

UserPost 之间的关系现在通过_PostToUser JOIN 表进行管理。

但是,我想摆脱这个额外的 JOIN 表,只需要一个从 PostUser 的外键引用,所以我运行了这个查询来创建外键:

ALTER TABLE "Post" ADD COLUMN "authorId" VARCHAR(25);
ALTER TABLE "Post" 
  ADD CONSTRAINT fk_author
  FOREIGN KEY ("authorId") 
  REFERENCES "User"("id");

现在,我想知道需要运行什么 SQL 查询才能将数据从 JOIN 表迁移到新的 authorId 列?如果我理解正确,我需要一个查询来读取_PostToUser 关系表中的所有行以及每一行:

  1. 通过查找列A 中的值来查找相应的Post 记录
  2. 将列 B 中的值作为 authorId 的值插入到该 Post 记录中

编辑:正如@Nick 在 cmets 中提到的,我应该澄清我确实想将关系从 m-n 更改为 1-n:一篇帖子可以在大多数只有一位作者。一位作者/用户可以写多篇文章。

【问题讨论】:

  • 我不明白。如果_PostToUser 表已经包含作者和帖子ID 值,那么为什么不能使用它呢?顺便说一句,您当前的设计已经是最优的,您不应该更改它。
  • 感谢您的回复!所以,现在我需要两个 JOIN 来获取关于帖子作者的信息(加入 Post_PostToUser 并从那里加入 User)。据我了解,直接在Post 上包含FK 将允许我通过一个JOIN(从PostUser)获取作者信息。这有意义吗?
  • 很可能没有理由走这条路。为什么你认为你需要这样做?在放弃连接之前,您应该首先查看连接表,以便更快地进行查找。您的建议是非标准做法,只有在没有其他方法可以使用您当前的设计时才应该这样做。
  • 哈,谢谢你的上下文。您能否推荐有关如何优化联结表中的查找的任何资源?另外,我喜欢任何能解释这是非标准做法的指针,我不是数据建模专家,但我认为将关系建模为 FK 将是常见做法,所以我很想了解更多相关信息! :)
  • 您应该注意,按照您的建议更改结构意味着您将 Posts:Authors 限制为 N:1 关系;即一个帖子不能有很多作者。如果这是您对该项目生命周期的期望,那么进行此更改并不是一件不合理的事情。

标签: sql postgresql


【解决方案1】:

您当前的设计已经正确,并使用适当的联结表来存储用户与其帖子之间的关系。在这个设计中,给定的关系只需要存储两个 ID 值,这是精益的。朝着您建议的方向前进是对数据进行非规范化,并将导致数据重复。要了解为什么会出现这种情况,您建议的表现在将存储作者表中的元数据。原则上,此元数据将是重复的,因为给定作者的元数据对于新帖子表中的每条记录都是相同的。

相反,我建议索引联结表:

CREATE INDEX idx ON "_PostToUser" (B, A);

例如,上面的索引应该有助于以下查询:

SELECT u.*, p.*
FROM "User" u
INNER JOIN "_PostToUser" pu ON pu.B = u.id       -- index helps here
INNER JOIN "Post" p ON p.id = pu.A;              -- Post.id is already a primary key

查找表的连接现在应该更快了,因为 Postgres 可以使用索引获取给定的用户 id 值并尝试在连接的另一侧找到相应的 A 值。

【讨论】:

  • 非常感谢这个上下文,这非常有帮助!
【解决方案2】:

只要你乐意将PostsUsers之间的关系限制为N:1,并且只在Post中存储User的外键,那么我认为你在做的是美好的。更新Post 表的查询是:

UPDATE "Post" p
SET "authorId" = pu."B"
FROM "_PostToUser" pu 
WHERE pu."A" = p."id"

Demo on dbfiddle

【讨论】:

  • @nburk 不用担心 - 我很高兴能帮上忙。
猜你喜欢
  • 2020-08-30
  • 1970-01-01
  • 1970-01-01
  • 2015-07-04
  • 2012-06-03
  • 2019-04-11
  • 1970-01-01
  • 2022-07-06
  • 1970-01-01
相关资源
最近更新 更多