PostgreSQL CTE UPDATE-FROM查询跳过行

PostgreSQL CTE UPDATE-FROM查询跳过行,sql,postgresql,common-table-expression,Sql,Postgresql,Common Table Expression,2张桌子 表1行:注意:id 2有两行 ----------------------- | id | counts | track | ----------------------- | 1 | 10 | 1 | | 2 | 10 | 2 | | 2 | 10 | 3 | ----------------------- 表2行 --------------- | id | counts | --------------- | 1 | 0

2张桌子

表1行:注意:id 2有两行

-----------------------
| id | counts | track |
-----------------------
| 1  | 10     | 1     |
| 2  | 10     | 2     |
| 2  | 10     | 3     |
-----------------------
表2行

---------------
| id | counts |
---------------
| 1  | 0      |
| 2  | 0      |
---------------
查询:

with t1_rows as (
    select id, sum(counts) as counts, track 
    from table_1
    group by id, track
)
update table_2 set counts = (coalesce(table_2.counts, 0) + t1.counts)::float 
from t1_rows t1
where table_2.id = t1.id;

select * from table_2;
当我运行上面的查询时,我得到了表2的输出

---------------
| id | counts |
---------------
| 1  | 10     |
| 2  | 10     | (expected counts as 20 but got 10)
---------------
我注意到上面的更新查询只考虑了第一个匹配,并跳过了其余的匹配

我可以通过如下更改查询使其工作。现在,由于表_1中没有重复的行,因此表_2将按预期更新

但是我想知道为什么我之前的查询不起作用。有什么不对劲吗

with t1_rows as (
    select id, sum(counts) as counts, array_agg(track) as track 
    from table_1
    group by id
)
update table_2 set counts = (coalesce(table_2.counts, 0) + t1.counts)::float 
from t1_rows t1
where table_2.id = t1.id;
模式

CREATE TABLE IF NOT EXISTS table_1(
  id varchar not null,
  counts integer not null,
  track integer not null
);

CREATE TABLE IF NOT EXISTS table_2(
  id varchar not null,
  counts integer not null
);

insert into table_1(id, counts, track) values(1, 10, 1), (2, 10, 2), (2, 10, 3);
insert into table_2(id, counts) values(1, 0), (2, 0);

所以,如果我读对了您的问题,您希望表_1中的第2行和第3行相加吗?如果是这样,您的第一种方法不起作用的原因是它按id、track分组。 因为第2行和第3行在track列中的编号不同,所以它们没有通过GROUPBY子句相加


第二种方法有效,因为它只按id分组。问题是PostgreSQL中的更新创建了行的新版本,而不是就地更改行,但新行版本在当前查询的快照中不可见。因此,从查询的角度来看,行在第一次更新时“消失”

说:

当存在
FROM
子句时,实际上发生的是将目标表连接到
FROM\u列表中提到的表,并且连接的每个输出行表示目标表的更新操作。使用
中的
时,应确保联接为要修改的每一行最多生成一个输出行。换句话说,目标行不应连接到其他表中的多个行。如果这样做,那么只有一个连接行将用于更新目标行,但使用哪一个连接行并不容易预测


那么,在这种情况下使用CTE UPDATE-FROM是否是个坏主意呢?我试图回答您的问题:但我想知道为什么我之前的查询不起作用。使用CTE没有问题,但是请确保使用
FROM
子句的联接只返回每个目标行一次。实际上,第一行确实有效,只是没有如您预期的那样,因为CTE为#2生成了两行,使用相同的值执行了两次更新。