Oracle 返回错误的原因是您不能从外部查询中引用列超过相关子查询内部的一层。
(StackOverflow 上的其他问题也回答了同样的问题。)
更新
我之前说明的方法(如下)只有在我们能够获得一个内联视图(其中 t1 是保留键)时才有效。 (完全是我的错。这种方法在 MySQL 中确实有效。我使用 MySQL 的时间已经够长了,我希望 Oracle 会接受相同的语法。)
未指定t1 中的(fi,fo) 元组是唯一键。因此,相关子查询是可行的方法。
如果不需要保留 NULL 值,那么您可以用零替换 NULL 值...
UPDATE TABLE1 t1
SET t1.fum = NVL( SELECT SUM(t2.fum)
FROM TABLE1 t2
WHERE t2.fi = t1.fi
AND t2.fo = t1.fo
,0)
+ NVL( SELECT SUM(t3.fum)
FROM TABLE2 t3
WHERE t3.fi = t1.fi
AND t3.fo = t1.fo
,0)
注意: 这将返回一个零来代替 NULL;它不保留 NULL 值。 (如果 t1.fum 被定义为 NOT NULL,那么这不会是一个问题。但在更一般的情况下这是一个问题,其中 t1.fum 在所有行中都包含 NULL,并且 TABLE2 是空的......这将替换NULL 为零。
另外,如果 t1.fum 不是 NULL,并且元组 (fi,fo) 是 TABLE1 中的唯一键,那么我们可以避免执行 SELECT 来获取存储在 t1.fum 中的值的 SUM,我们已经有了,所以我们可以...
... SET t1.fum = t1.fum + NVL(( correlated subquery ),0)
但在更一般的情况下,我们想在 t1.fum 中保留 NULL,我还没有一个好方法可以在不重复子查询的情况下在相关子查询中引用 t1 (ugghh)...我没有不知道像 SUM 聚合一样保留 NULL 的内置运算符或函数,因此我们可以在添加两个 SUM 子查询的数字结果时保留 NULL。
原始答案:
(此要求的用例似乎有点奇怪;请注意,UNION 将消除重复行,而 UNION ALL 则不会。)
原始答案指定了在 Oracle 中不起作用的多表语法。这种方法适用于 SELECT 语句,但不适用于 UPDATE 语句。
就个人而言,我不会使用相关子查询来执行这样的操作;我更喜欢使用 JOIN 操作来获得等效的结果。例如:
UPDATE TABLE1 t1
JOIN ( SELECT SUM(DISTINCT r.fum) AS sum_fum, r.fi, r.fo
FROM ( SELECT t2.fum
, t2.fi
, t2.fo
FROM TABLE1 t2
UNION
SELECT t3.fum
, t3.fi
, t3.fo
FROM TABLE2 t3
) r
GROUP BY r.fi, r.fo
) s
ON s.fi = t1.fi
AND s.fo = t1.fo
SET t1.fum = s.sum_fum
(如果打算只更新 t1 中的一部分行,而不是 t1 中的所有行,我会省略 LEFT 关键字以使其成为内连接。)
但在我运行这样的更新之前,我会先使用SELECT 语句进行验证,例如:
SELECT t1.fi
, t1.fo
, t1.fum AS old_fum
, s.sum_fum AS new_fum
FROM TABLE1 t1
LEFT
JOIN ( SELECT SUM(DISTINCT r.fum) AS sum_fum, r.fi, r.fo
FROM ( SELECT t2.fum
, t2.fi
, t2.fo
FROM TABLE1 t2
UNION
SELECT t3.fum
, t3.fi
, t3.fo
FROM TABLE2 t3
) r
GROUP BY r.fi, r.fo
) s
ON s.fi = t1.fi
AND s.fo = t1.fo
一旦我确认 SELECT 以我想要的方式工作,new_fum 列中返回的值就是我想要分配给 t1 中的 fum 列的值(替换现有的old_fum 值),然后我才会将其转换为 UPDATE 语句。
要使其成为 UPDATE 语句,我只需将“SELECT ”替换为“UPDATE”关键字,并在语句末尾添加一个“SET t1.fum = s.sum_fum”赋值(如果查询有 WHERE 子句,则在 WHERE 子句之前)。
注意:我做了以下替换以提高可读性:
FIELD1 => fi
FIELD2 => fo
FIELD4 => fum
原始查询中的内联视图使用UNION 运算符而不是UNION ALL 有点奇怪。因为UNION 运算符会在将值相加之前删除FIELD4 的所有重复值...为了获得等效结果,我将DISTINCT 关键字包含在SUM 聚合中。
(显然,如果原始查询有 UNION ALL 运算符,那么我们将在 SUM 聚合中省略 DISTINCT 关键字。)
我看不到原始查询在 Oracle 9 中是如何“工作”的;它引用了t4.FIELD1,但内联视图t4 不返回名为FIELD1 的列。