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 中找到的顺序相匹配。

step-by-step demo:db<>fiddle

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
  1. table_c 行数
  2. table_b 行数
  3. 加入 traveler 和行数

好吧,如果您想将 table_b 的列 uuididx 添加到 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;