Postgres 使用多个 Returns 保留顺序更新多行
Postgres Update Multiple Rows with Multiple Returns Preserving Order
所以我有一个 Table A 缺少与 Table B 的关系,因此我想添加关系信息以保留基于插入的顺序。 Table B 可以有多个部分,其中 UUID 对于一个分组是唯一的,并且顺序由索引保存。
所以我可以在 Table B:
| dfe63310-6a01-40e1-a44e-b9cc2f4ed37a | 0 |
| dfe63310-6a01-40e1-a44e-b9cc2f4ed37a | 1 |
我想要做的是将这些列添加到 Table A 中,然后按照我们可以假设 Table A 具有条目的顺序将该信息复制到 Table A匹配与 Table B.
相同的计数
示例数据:
id | uuid | name
----+--------------------------------------+---------
1 | f9b0de79-3f38-4cbb-9275-6d68b472e943 | Alice
2 | 13df1b18-5c6e-4879-9b2f-c78ea215c809 | Bob
3 | 21f5e0ee-1e1b-4d8d-8768-d0acc276efd5 | Charlie
select * from test_b;
id | uuid | idx | location | traveler
----+--------------------------------------+-----+------------+--------------------------------------
1 | b972acfc-d5b2-4e65-bf31-0a515ee1a2f1 | 0 | Chicago | f9b0de79-3f38-4cbb-9275-6d68b472e943
2 | 676143d6-abe1-48d6-bf78-c72b3186ede3 | 0 | Pittsburgh | 13df1b18-5c6e-4879-9b2f-c78ea215c809
3 | b0cb5e4f-3070-4403-89dd-6063864233c4 | 0 | Denver | 21f5e0ee-1e1b-4d8d-8768-d0acc276efd5
4 | b972acfc-d5b2-4e65-bf31-0a515ee1a2f1 | 1 | Charlotte | f9b0de79-3f38-4cbb-9275-6d68b472e943
5 | 676143d6-abe1-48d6-bf78-c72b3186ede3 | 1 | Las Vegas | aeae809f-13df1b18-5c6e-4879-9b2f-c78ea215c809
6 | b0cb5e4f-3070-4403-89dd-6063864233c4 | 1 | New York | 21f5e0ee-1e1b-4d8d-8768-d0acc276efd5
select * from test_c;
id | uuid | traveler | log
----+--------------------------------------+--------------------------------------+----------------
1 | 181b6f69-ea7b-4e2f-90c7-89999168f2aa | f9b0de79-3f38-4cbb-9275-6d68b472e943 | Had fun
2 | 5770b1f1-b502-4ef2-9443-9075734a7585 | 13df1b18-5c6e-4879-9b2f-c78ea215c809 | Been better
3 | 32bb94ba-76bb-4d89-8da3-c5ef7a4957b5 | f9b0de79-3f38-4cbb-9275-6d68b472e943 | Had fun
4 | a257bb49-078f-4f03-a430-f331aee86da1 | 21f5e0ee-1e1b-4d8d-8768-d0acc276efd5 | Going to leave
5 | a1b3d545-d4b8-462b-a93b-e87ba9fce849 | 21f5e0ee-1e1b-4d8d-8768-d0acc276efd5 | Missed home
6 | f2d67010-6948-49a3-b401-3005812aaca6 | 13df1b18-5c6e-4879-9b2f-c78ea215c809 | Great place
假设 table test_a
是旅行者的旅行,test_b
是他们去过的城市列表。示例 Alice 曾两次前往芝加哥和夏洛特。一路上,他们在 test_c
中记录了他们的旅行。我想要的是将 test_b
中的 uuid 和 idx 添加到 test_c
,假设 test_b
中的顺序与 test_c
中找到的顺序相匹配。
在 table_c
上连接来自 table_b
的记录需要一个共同的连接条件。
假设 ID 正确地随着条目的增加而增加(因此较新的记录具有更高的 id
),它们可以用作排序标准。如果没有,您将需要一个,因为没有什么比插入订单更好的了。插入记录不保证任何查询顺序。
好吧,要创建通用连接条件,您可以使用 row_number()
window function,它会在有序组(= 分区)内创建行计数。在您的情况下,分区是 traveler
,顺序是 id
(这里是 table_b
):
SELECT
*,
row_number() OVER (PARTITION BY traveler ORDER BY id)
FROM table_b;
产生(注意创建的最后一列)
> id | uuid | idx | location | traveler | row_number
> -: | :----------------------------------- | --: | :--------- | :-------------------------------------------- | ---------:
> 2 | 676143d6-abe1-48d6-bf78-c72b3186ede3 | 0 | Pittsburgh | 13df1b18-5c6e-4879-9b2f-c78ea215c809 | 1
> 3 | b0cb5e4f-3070-4403-89dd-6063864233c4 | 0 | Denver | 21f5e0ee-1e1b-4d8d-8768-d0acc276efd5 | 1
> 6 | b0cb5e4f-3070-4403-89dd-6063864233c4 | 1 | New York | 21f5e0ee-1e1b-4d8d-8768-d0acc276efd5 | 2
> 5 | 676143d6-abe1-48d6-bf78-c72b3186ede3 | 1 | Las Vegas | aeae809f-13df1b18-5c6e-4879-9b2f-c78ea215c809 | 1
> 1 | b972acfc-d5b2-4e65-bf31-0a515ee1a2f1 | 0 | Chicago | f9b0de79-3f38-4cbb-9275-6d68b472e943 | 1
> 4 | b972acfc-d5b2-4e65-bf31-0a515ee1a2f1 | 1 | Charlotte | f9b0de79-3f38-4cbb-9275-6d68b472e943 | 2
同样可以用 table_c
来完成。
现在,您为每个 traveler
的记录创建了规范化行计数。因为记录数相等(您在问题中假设),这是您的加入条件:
SELECT
*
FROM (
SELECT -- 1
*,
row_number() OVER (PARTITION BY traveler ORDER BY id)
FROM table_c
) c LEFT JOIN (
SELECT
*,
row_number() OVER (PARTITION BY traveler ORDER BY id) -- 2
FROM table_b
) b ON b.traveler = c.traveler AND b.row_number = c.row_number -- 3
table_c
行数
table_b
行数
- 加入
traveler
和行数
好吧,如果您想将 table_b
的列 uuid
和 idx
添加到 table_c
,您需要新的列:
ALTER TABLE table_c
ADD COLUMN b_uuid text,
ADD COLUMN b_idx int;
然后您必须使用 UPDATE
语句来填充它们,该语句使用上面的查询:
UPDATE table_c c
SET b_uuid = s.b_uuid, b_idx = s.b_idx
FROM (
SELECT
c.id,
b.uuid as b_uuid,
b.idx as b_idx
FROM (
SELECT
*,
row_number() OVER (PARTITION BY traveler ORDER BY id)
FROM table_c
) c LEFT JOIN (
SELECT
*,
row_number() OVER (PARTITION BY traveler ORDER BY id)
FROM table_b
) b ON b.traveler = c.traveler AND b.row_number = c.row_number
) s
WHERE s.id = c.id;
所以我有一个 Table A 缺少与 Table B 的关系,因此我想添加关系信息以保留基于插入的顺序。 Table B 可以有多个部分,其中 UUID 对于一个分组是唯一的,并且顺序由索引保存。
所以我可以在 Table B:
| dfe63310-6a01-40e1-a44e-b9cc2f4ed37a | 0 |
| dfe63310-6a01-40e1-a44e-b9cc2f4ed37a | 1 |
我想要做的是将这些列添加到 Table A 中,然后按照我们可以假设 Table A 具有条目的顺序将该信息复制到 Table A匹配与 Table B.
相同的计数示例数据:
id | uuid | name
----+--------------------------------------+---------
1 | f9b0de79-3f38-4cbb-9275-6d68b472e943 | Alice
2 | 13df1b18-5c6e-4879-9b2f-c78ea215c809 | Bob
3 | 21f5e0ee-1e1b-4d8d-8768-d0acc276efd5 | Charlie
select * from test_b;
id | uuid | idx | location | traveler
----+--------------------------------------+-----+------------+--------------------------------------
1 | b972acfc-d5b2-4e65-bf31-0a515ee1a2f1 | 0 | Chicago | f9b0de79-3f38-4cbb-9275-6d68b472e943
2 | 676143d6-abe1-48d6-bf78-c72b3186ede3 | 0 | Pittsburgh | 13df1b18-5c6e-4879-9b2f-c78ea215c809
3 | b0cb5e4f-3070-4403-89dd-6063864233c4 | 0 | Denver | 21f5e0ee-1e1b-4d8d-8768-d0acc276efd5
4 | b972acfc-d5b2-4e65-bf31-0a515ee1a2f1 | 1 | Charlotte | f9b0de79-3f38-4cbb-9275-6d68b472e943
5 | 676143d6-abe1-48d6-bf78-c72b3186ede3 | 1 | Las Vegas | aeae809f-13df1b18-5c6e-4879-9b2f-c78ea215c809
6 | b0cb5e4f-3070-4403-89dd-6063864233c4 | 1 | New York | 21f5e0ee-1e1b-4d8d-8768-d0acc276efd5
select * from test_c;
id | uuid | traveler | log
----+--------------------------------------+--------------------------------------+----------------
1 | 181b6f69-ea7b-4e2f-90c7-89999168f2aa | f9b0de79-3f38-4cbb-9275-6d68b472e943 | Had fun
2 | 5770b1f1-b502-4ef2-9443-9075734a7585 | 13df1b18-5c6e-4879-9b2f-c78ea215c809 | Been better
3 | 32bb94ba-76bb-4d89-8da3-c5ef7a4957b5 | f9b0de79-3f38-4cbb-9275-6d68b472e943 | Had fun
4 | a257bb49-078f-4f03-a430-f331aee86da1 | 21f5e0ee-1e1b-4d8d-8768-d0acc276efd5 | Going to leave
5 | a1b3d545-d4b8-462b-a93b-e87ba9fce849 | 21f5e0ee-1e1b-4d8d-8768-d0acc276efd5 | Missed home
6 | f2d67010-6948-49a3-b401-3005812aaca6 | 13df1b18-5c6e-4879-9b2f-c78ea215c809 | Great place
假设 table test_a
是旅行者的旅行,test_b
是他们去过的城市列表。示例 Alice 曾两次前往芝加哥和夏洛特。一路上,他们在 test_c
中记录了他们的旅行。我想要的是将 test_b
中的 uuid 和 idx 添加到 test_c
,假设 test_b
中的顺序与 test_c
中找到的顺序相匹配。
在 table_c
上连接来自 table_b
的记录需要一个共同的连接条件。
假设 ID 正确地随着条目的增加而增加(因此较新的记录具有更高的 id
),它们可以用作排序标准。如果没有,您将需要一个,因为没有什么比插入订单更好的了。插入记录不保证任何查询顺序。
好吧,要创建通用连接条件,您可以使用 row_number()
window function,它会在有序组(= 分区)内创建行计数。在您的情况下,分区是 traveler
,顺序是 id
(这里是 table_b
):
SELECT
*,
row_number() OVER (PARTITION BY traveler ORDER BY id)
FROM table_b;
产生(注意创建的最后一列)
> id | uuid | idx | location | traveler | row_number
> -: | :----------------------------------- | --: | :--------- | :-------------------------------------------- | ---------:
> 2 | 676143d6-abe1-48d6-bf78-c72b3186ede3 | 0 | Pittsburgh | 13df1b18-5c6e-4879-9b2f-c78ea215c809 | 1
> 3 | b0cb5e4f-3070-4403-89dd-6063864233c4 | 0 | Denver | 21f5e0ee-1e1b-4d8d-8768-d0acc276efd5 | 1
> 6 | b0cb5e4f-3070-4403-89dd-6063864233c4 | 1 | New York | 21f5e0ee-1e1b-4d8d-8768-d0acc276efd5 | 2
> 5 | 676143d6-abe1-48d6-bf78-c72b3186ede3 | 1 | Las Vegas | aeae809f-13df1b18-5c6e-4879-9b2f-c78ea215c809 | 1
> 1 | b972acfc-d5b2-4e65-bf31-0a515ee1a2f1 | 0 | Chicago | f9b0de79-3f38-4cbb-9275-6d68b472e943 | 1
> 4 | b972acfc-d5b2-4e65-bf31-0a515ee1a2f1 | 1 | Charlotte | f9b0de79-3f38-4cbb-9275-6d68b472e943 | 2
同样可以用 table_c
来完成。
现在,您为每个 traveler
的记录创建了规范化行计数。因为记录数相等(您在问题中假设),这是您的加入条件:
SELECT
*
FROM (
SELECT -- 1
*,
row_number() OVER (PARTITION BY traveler ORDER BY id)
FROM table_c
) c LEFT JOIN (
SELECT
*,
row_number() OVER (PARTITION BY traveler ORDER BY id) -- 2
FROM table_b
) b ON b.traveler = c.traveler AND b.row_number = c.row_number -- 3
table_c
行数table_b
行数- 加入
traveler
和行数
好吧,如果您想将 table_b
的列 uuid
和 idx
添加到 table_c
,您需要新的列:
ALTER TABLE table_c
ADD COLUMN b_uuid text,
ADD COLUMN b_idx int;
然后您必须使用 UPDATE
语句来填充它们,该语句使用上面的查询:
UPDATE table_c c
SET b_uuid = s.b_uuid, b_idx = s.b_idx
FROM (
SELECT
c.id,
b.uuid as b_uuid,
b.idx as b_idx
FROM (
SELECT
*,
row_number() OVER (PARTITION BY traveler ORDER BY id)
FROM table_c
) c LEFT JOIN (
SELECT
*,
row_number() OVER (PARTITION BY traveler ORDER BY id)
FROM table_b
) b ON b.traveler = c.traveler AND b.row_number = c.row_number
) s
WHERE s.id = c.id;