1

昨天我发现了一些关于 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.xml 替换迁移表中每一行中存在的所有用户名对。

而且,我再说一遍,第二个版本按预期工作,但第一个版本没有更新。我只想知道为什么。

| usermigration table    |
--------------------------
oldusername | newusersname
--------------------------
johndoe     | johnd
john.smith  | johnsmith

这是 PostgreSQL 中的错误吗?

4

1 回答 1

2

您缺少WHERE子句(不能写为直接JOIN条件)。附加表usermigration必须以某种方式绑定到bodycontent要更新的表,或者每一行bodycontent都有与其中行一样多的更新候选usermigration- 两个表之间的笛卡尔积。

没有办法知道哪个会被应用并坚持下去。在这方面,两种说法都是错误的。例如,如果其中有 1000 行,usermigration其中 1000 行将bodycontent导致1 000 000个更新候选者,然后可以选择 1000 个。

如果你在一个语句中加入一个或多个表,那么如果没有一个子句将子句的结果连接到更新的表,UPDATE几乎没有任何意义。WHEREFROM

考虑手册中有关 UPDATE 语句的这些注释

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

请注意,语句FROM中的子句UPDATE是对 SQL 标准的PostgreSQL 扩展。其他 DBMS 使用不同的语法,例如JOIN要更新的表的显式 s(在 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结果还是模棱两可。可以找到多个匹配项。不确定,将应用哪一个。问题是您的要求本质上是模棱两可的。可以有多个(重叠)匹配的用户名,并且应用更新的顺序是相关的(但未定义)。该UPDATE声明完美地反映了您有缺陷的要求。

'~' ||部分是怎么回事?

于 2012-04-12T15:06:26.097 回答