仅当连接明确时才更新行
Posted
技术标签:
【中文标题】仅当连接明确时才更新行【英文标题】:Update rows only when a join is unambiguous 【发布时间】:2018-10-11 17:10:44 【问题描述】:我有两个表,a
和 b
,都带有 product_name
和 value
。 a
中的 value 列为 null。
我想用b
表中的值更新a
表。由于数据中的一个怪癖,product_name
在任一表中都不是唯一的。
我只想在两者之间在product_name
上存在一个明确匹配时设置该值。当a
中的多行具有相同的产品名称,或者b
中的多行匹配时,我想将该值保留为空。在 Postgres 中有没有一种有效的方法来做到这一点?
一个更简单的版本是在a
中首先使用identify unique product names。然后,更新 b
中只有一行匹配的行——但我也不确定如何编写该约束。
【问题讨论】:
【参考方案1】:简单的方法:
update a
set value = (select min(b.value) from b where b.product_name = a.product_name)
where product_name in (select product_name from a group by product_name having count(*) = 1)
and product_name in (select product_name from b group by product_name having count(*) = 1)
;
【讨论】:
(explain.depesz.com/s/SLZx) 与 (explain.depesz.com/s/NBon)【参考方案2】:你可以使用聚合:
update a
set value = b.value
from (select b.product_name, max(b.value) as value
from b
group by b.product_name
having min(b.value) = max(b.value) -- there is only one value
) b
where b.product_name = a.product_name;
请注意,这假定b.value
不是null
。如果需要,很容易包含 null
值的逻辑。
【讨论】:
【参考方案3】:把 [How to Select Every Row Where Column Value is NOT Distinct 和 @Gordon Linoff 的回答放在一起:
create table a (
id serial primary key
,product_name text
,value int
);
create table b (
id serial primary key
,product_name text
,value int not null
);
insert into a (product_name) values
('A')
,('B')
,('C')
,('D')
,('E')
,('E');
insert into b (product_name,value) values
('A',1)
,('A',1)
,('B',42)
,('C',1)
,('C',2)
,('E',1)
;
update a
set value = b.value
from (select product_name, min(value) as value
from b
group by b.product_name
having 1 = count(*)
) b
where b.product_name = a.product_name
and a.product_name not in
(select product_name
from a
group by product_name
having 1 < count(*));
@Gordon Lindof 如果 product_name 和 value 在 b 中都重复(例如 product_name=A)并且错过了要求 product_name not 在 a 中重复,则您的答案将失败。
【讨论】:
以上是关于仅当连接明确时才更新行的主要内容,如果未能解决你的问题,请参考以下文章