PostgreSQL。更新联结点 table

PostgreSQL. Update junction table

我想更新我的交汇点 table 的行。不是字面上的更新,只插入新的元组并删除未插入的元组。

这是我的 tables:

用户table

-----------------------
|user_id   |FullName |
-----------------------
|1      | John    |
|2      | Michael |
|3      | Bryce   |

地址table

-----------------------------------------
|address_id|    country    |    city     |
-----------------------------------------
|    1     |      USA      |    New-York |
|    2     |     Russia    |    Moscow   |
|    3     |    Germany    |    Berlin   |
|    4     |      UK       |    London   |

这是连接 table 的路口 现在两个。

"user_address"

------------------------
| user_id | address_id |
------------------------
|   1     |      1     |
|   1     |      2     |
|   2     |      3     |
|   3     |      1     |

例如,我想在我的连接中插入一个新值,并使其像这样:

------------------------
| user_id | address_id |
------------------------
|   1     |      1     |
|   1     |      3     |
|   2     |      4     |

而且,是的,我可以做到这一点:

DELETE FROM user_address WHERE address_id = 1;
INSERT INTO user_address VALUES (1, 3);

但是,如果我有 100 万行,而用户只想删除一行怎么办。
在这种情况下,我将删除所有 100 万,并仅为一行插入 999.999.999。

那么,我怎样才能只插入新行并删除没有为我插入的行呢?

P.S。我正在使用 PostgreSQL。

更新
希望这个截图能解释我的问题。 这是我的路口 table:
我正在尝试更新用户的地址 - 在 junction:

中更改 user_id
UPDATE user_address SET user_id = 100 WHERE address_id = 25 RETURNING user_id

但是如果我使用这个查询,当我只想有一行 user_id = 100
时,它会将 user_id 都更改为 100
所以,问题是如何避免联结 table 更新中的重复。

首先要避免和防止“连接点 table”中的重复项,您需要通过添加约束使行唯一:

ALTER TABLE user_address ADD CONSTRAINT uq_user_addr UNIQUE(user_id, address_id)

-- OR if there is no primary key in your user_address table

ALTER TABLE user_address ADD PRIMARY KEY (user_id, address_id)

这将确保您在指定的 table 中没有重复项。为了删除单行,您将必须指定两个列值。如果要删除具有特定 user_id 的所有行,则指定 user_id;如果要删除带有 address_id 的所有行,请指定 address_id.

您可以对您找到的 MySQL 解决方案执行相同的操作,只是语法不同。

对于INSERT,你应该添加一个UNIQUE INDEX:

CREATE UNIQUE INDEX idx_address_users ON user_address (address_id, user_id);

...然后您可以使用 ON CONFLICT 子句(在 PostgreSQL 9.5 中引入)来忽略重复的行,例如:

INSERT INTO user_address (user_id, address_id)
VALUES (100, 25), (101, 25), (102, 25)
ON CONFLICT (idx_address_users) DO NOTHING -- ignore duplicate new rows
RETURNING user_id;

DELETE FROM user_address WHERE address_id = 25 AND user_id NOT IN (100, 101, 102);

...或从用户端:

INSERT INTO user_address (user_id, address_id)
VALUES (100, 25), (100, 26), (100, 27)
ON CONFLICT (idx_address_users) DO NOTHING -- ignore duplicate new rows
RETURNING address_id;

DELETE FROM user_address WHERE user_id = 100 AND address_id NOT IN (25, 26, 27);

但是,这两种方法都需要您的应用程序执行完整的 load-modify-save 循环,因为您在这里处理完整的集合。

除此之外,附加的主键几乎没有用。