PostgreSQL - Loop似乎已经异步了一会儿

时间:2018-04-04 03:38:37

标签: postgresql

我的table1已经过时,正在被table2取代。我的目标是将table1中的所有记录移动到table2。为了避免在移动数据时发生id冲突,我运行了这个函数,如果匹配的table2.id已经存在,它只会更新table1.ids:

DO
$do$
DECLARE
    row RECORD;
BEGIN
  FOR row IN
    SELECT t1.id, t1.name, t2.id, t2.name
    FROM sch.table1 AS t1
    JOIN sch.table2 AS t2
    ON t1.id = t2.id
  LOOP
    UPDATE sch.table1
      SET id = (select greatest(
        (select max(id) from sch.table1),
        (select max(id) from sch.table2)) + 1)
      WHERE id = row.id;
    -- more code here that updates tables with table1.id as foreign key
  END LOOP;
END
$do$;

在大多数情况下,该功能按预期工作,正确地整理了100多条记录。但奇怪的是,似乎它只是一点点地异步运行。在函数运行之前,我在table1中有这8条记录(我已经编辑了名称):

id  |name
----|-----------------------------
450 |Number Zero
451 |Number One
452 |Number Two
453 |Number Three
454 |Number Four
455 |Number Five
456 |Number Six
457 |Number Seven

在函数运行后,这8条记录是:

id  |name
----|-----------------------------
1138|Number Zero
1139|Number One
1139|Number Two
1140|Number Three
1140|Number Four
1141|Number Five
1141|Number Six
1142|Number Seven

“第一号”之前和“第六号”之后的每条记录都相应更新。奇怪的是6条记录配对了。两个记录分配了id 1139,1140和1141.我不知道这是怎么发生的,我需要知道才能找到避免这种情况的方法!

有什么想法吗?

PS。我在DataGrip上运行SQL代码,PostgreSQL DB位于AWS上。只是说明这一点,以防任何一个是重要的。

1 个答案:

答案 0 :(得分:1)

您正在从正在更新的表中获取,并且获取(连接)基于您正在更新的列,这可能是主键。 Postgres在进入循环之前不得选择所有行。

在您的代码中还有一些其他问题:

  1. row.id的价值应该是什么; t1.idt2.id?您应该为idname列使用显式别名。
  2. 在关系模型和SQL中,关系(表)没有特定的顺序。您应该使用明确的ORDER BY子句。如果线条按你想要的那样编​​号,那就巧合了。
  3. id的{​​{1}}的最大值是循环的不变量。因此,您可以将循环外部的最大值计算到变量中,并在循环内增加此变量的值。
  4. 我认为没有任何理由在循环中加入,因为您似乎没有使用t2的值。所以你可以省略加入。
  5. 总而言之,你应该尝试类似的事情:

    table2

    但总是存在更新DO $do$ DECLARE row RECORD; i INTEGER; BEGIN i := greatest( (select max(id) from sch.table1), (select max(id) from sch.table2)) + 1; FOR row IN SELECT t1.id, t1.name FROM sch.table1 AS t1 ORDER BY ... LOOP UPDATE sch.table1 SET id = i WHERE id = row.id; i := i + 1; END LOOP; END $do$; 主键的问题。如果此代码不起作用,则应将主键保存在临时列中:

    table1