【问题标题】:Postgres UPDATE..FROM query with multiple updates on the same rowPostgres UPDATE..FROM 查询在同一行上有多个更新
【发布时间】:2015-01-22 22:43:40
【问题描述】:

我正在尝试优化 Postgres 中的批量 UPDATE 语句,使用 UPDATE..FROM 语法从值列表进行更新。除非在同一查询中多次更新同一行。

例如,假设我有一个表“test”,其中包含“key”和“value”列。

update test as t set value = v.value from (values 
    ('key1', 'update1'), 
    ('key1', 'update2') ) 
    as v (key, value) 
where t.key = v.key;

我想要的行为是将键为“key1”的行更新两次,最后将值设置为“update2”。在实践中,有时值会更新为 update1,有时会更新为 update2。此外,表上的更新触发器函数只调用一次。

文档 (http://www.postgresql.org/docs/9.1/static/sql-update.html) 解释了原因:

当出现 FROM 子句时,实质上发生的情况是目标表与 from_list 中提到的表连接,连接的每个输出行代表目标表的更新操作。使用 FROM 时,应确保连接为要修改的每一行生成最多一个输出行。换句话说,目标行不应连接到来自其他表的多个行。如果是这样,那么只有一个连接行将用于更新目标行,但将使用哪一个是不容易预测的。

由于这种不确定性,仅在子选择中引用其他表更安全,但通常比使用连接更难阅读且速度较慢。

有没有办法重新制定这个查询来实现我正在寻找的行为?文档中对子选择的引用是否给出了提示?

【问题讨论】:

  • 如果你有多个源元组来更新tarfet,你至少有一个语义问题:你想使用哪个候选值?要么您需要另一个字段作为决胜局,要么您需要在作为源的子查询中使用unique on(...)

标签: sql database postgresql


【解决方案1】:

示例(假设id是目标表中的PK,{id, date_modified}是源表中的PK)

UPDATE target dst
Set a = src.a , b = src.b
FROM source src
WHERE src.id = dst.id
AND NOT EXISTS (
        SELECT *
        FROM source nx
        WHERE nx.id = src.id
        -- use an extra key field AS tie-breaker
        AND nx.date_modified > src.date_modified
        );

(其实这是对源表的去重->强制源表和目标表同一个PK)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-24
    • 1970-01-01
    • 2021-10-14
    • 2022-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-29
    相关资源
    最近更新 更多