Access SQL 中使用聚合函数执行 UPDATE SET
支付小周
结论
Access SQL 对 UPDATE ... SET 中的相关聚合子查询支持有限。如果直接在 SET 后写 SELECT AVG(...),通常会出现语法错误,或提示“查询必须是可更新的查询”。
比较稳妥的办法是先将各城市的平均值写入临时表,再用可更新的连接查询更新 Agent。
解决方法
先计算每个城市的平均 Payment,并将结果保存到临时表:
SELECT
City,
AVG(Payment) AS AvgPayment
INTO AgentCityAverage
FROM Agent
GROUP BY City;
再把平均值更新到 Agent:
UPDATE Agent
INNER JOIN AgentCityAverage
ON Agent.City = AgentCityAverage.City
SET Agent.Payment = AgentCityAverage.AvgPayment;
执行后,数据如下:
| ID_Agent | City | Payment |
|---|---|---|
| 1 | London | 1300 |
| 2 | York | 1750 |
| 3 | London | 1300 |
| 4 | York | 1750 |
确认更新结果正确后,可以删除临时表:
DROP TABLE AgentCityAverage;
为什么原来的 SQL 不能运行
下面的写法在部分数据库中有效:
UPDATE Agent AS a1
SET a1.Payment =
(
SELECT AVG(a2.Payment)
FROM Agent AS a2
WHERE a2.City = a1.City
);
但 Access 的更新查询无法可靠地将这种相关聚合子查询用作 SET 的值。即使把聚合查询直接连接到更新查询,Access 也可能因为聚合结果集不可更新而拒绝执行。先将聚合结果写入普通表,可以避开这个限制。
临时表已经存在时
SELECT ... INTO 要求目标表尚不存在。如果需要重复执行,可以保留 AgentCityAverage,每次先清空表中的数据:
DELETE FROM AgentCityAverage;
然后重新写入各城市的平均值:
INSERT INTO AgentCityAverage (City, AvgPayment)
SELECT City, AVG(Payment)
FROM Agent
GROUP BY City;
最后再次执行更新:
UPDATE Agent
INNER JOIN AgentCityAverage
ON Agent.City = AgentCityAverage.City
SET Agent.Payment = AgentCityAverage.AvgPayment;
注意事项
AVG()会忽略Null。如果某个城市的Payment全部为Null,计算结果也会是Null。City为Null的记录无法通过普通等值连接匹配,需要另行处理。- 如果
Payment是整数类型,而平均值可能带有小数,应将该字段改为合适的数值类型或 Currency 类型,否则 Access 可能会进行舍入。 - 此更新会覆盖原始 Payment。如果需要保留原始金额,应先备份表,或将平均值写入新字段。
备注:内容仅供参考。
