昨天我发现了一些关于 SQL 的奇怪现象,或者至少是 PostreSQL。请看下面并解释为什么第一个查询不执行任何操作而第二个查询却正常工作:
-- this silently does nothing
update bodycontent
set body = replace(body, '~' || u.oldusername, '~' || u.newusername)
from usermigration u;
-- this works as expected
update bodycontent
set body = replace(body, '~' || oldusername, '~' || newusername)
from usermigration u;
更新:我认为每个人都没有抓住这个问题的重点,笛卡尔积是一个初衷:将会有 N x M 更新,这是设计使然。
我需要替换
bodycontent
中每一行中存在于迁移表中的所有用户名对。
而且,我再说一遍,第二个版本按预期工作,但第一个版本没有更新。我只想知道为什么。
| usermigration table |
--------------------------
oldusername | newusersname
--------------------------
johndoe | johnd
john.smith | johnsmith
这是 PostgreSQL 中的错误吗?
您缺少
WHERE
子句(不能写为直接 JOIN
条件)。附加表 usermigration
必须连接到表 bodycontent
才能以某种方式更新,或者 bodycontent
的每一行都具有与 usermigration
中的行一样多的更新候选数 - 两者之间的笛卡尔积桌子。
没有办法知道哪一个将被应用和坚持。这两种说法在这方面都是错误的。由于
usermigration
中有 1000 行,bodycontent
中有 1000 行,因此在挑选 1000 行之前,我们有 1 000 000 更新候选项。
FROM
子句中的附加表几乎没有任何意义,如果没有 WHERE
子句将它们连接到主表。
手册:
当存在
子句时,本质上发生的是 目标表连接到中提到的表FROM
列表,连接的每个输出行代表对目标表的一次更新操作。使用from_item
时,您应该 确保连接最多为每一行生成一个输出行 被修改。换句话说,目标行不应连接超过 其他表中的一行。如果是,则只有其中一个连接 rows 将用于更新目标行,但是将使用哪一行 不容易预测。FROM
FROM
语句中的UPDATE
子句是 SQL 标准的 PostgreSQL 扩展。其他 DBMS 使用不同的语法,例如与要更新的表(在 tSQL 中)的显式联接不适用于 PostgreSQL。
此查询有效,大部分1:
UPDATE bodycontent b
SET body = replace(b.body, u.oldusername, u.newusername)
FROM usermigration u
WHERE b.body LIKE ('%' || u.oldusername || '%');
1 结果仍然不明确。可以找到多个匹配项。尚不确定将应用哪一个。问题在于您的需求本质上是不明确的。可以有多个(重叠的)用户名匹配,并且应用更新的order是相关的(但未定义)。
UPDATE
陈述完美地反映了您有缺陷的要求。