sql - WHILE 循环中的 UPSERT 因列引用无效而失败
问题描述
我想在WHILE
循环中运行 UPSERT。这是我的查询:
do $$ declare start_date date := '2021-01-16';
begin
while start_date::date < '2021-03-01' loop
insert
into
A ( id,
"year",
"month",
movement,
status)
(
select
id,
date_year,
date_month,
s_movement,
move_status
from
B
where
date_year = extract(year
from
start_date::date)
and date_month = (extract(month
from
start_date::date)+ 1)
and date_day = extract(day
from
start_date::date))
on conflict (id) do
update set status = move_status, movement = s_movement;
start_date:=start_date+interval '1 day';
end loop;
end $$
但是当我运行这个查询时,它给出了错误:
SQL Error [42703]: ERROR: column "move_status" does not exist Hint: There is a column named "move_status" in table "*SELECT*", but it cannot be referenced from this part of the query.
如何解决?
解决方案
错误的直接原因是您试图引用输入列名,但UPDATE
在 UPSERT 部分中只有目标列名可见。而且您必须使用虚拟表名EXCLUDED
对那些进行表限定。
但还有更多。使用基于集合的解决方案,generate_series()
而不是命令中的循环DO
。效率更高:
INSERT INTO A
(id, year , month , movement , status)
SELECT id, date_year, date_month, s_movement, move_status
FROM generate_series(timestamp '2021-01-16'
, timestamp '2021-02-28'
, interval '1 day') start_date
JOIN B ON date_year = extract(year FROM start_date)
AND date_month = extract(month FROM start_date) + 1
AND date_day = extract(day FROM start_date)
ON CONFLICT (id) DO UPDATE
SET status = EXCLUDED.status -- here!
, movement = EXCLUDED.movement; -- and here!
旁白:考虑一个类型的单列date
来替换三列date_year
, date_month
, date_day
。更清洁,更高效。
进一步阅读:
推荐阅读
- xcode - 谷歌演员。反应本机应用程序。Xcode:ld:未找到框架 GoogleCast
- json - 替换 BASH 脚本中的 JSON 变量
- android - 如何为 Glide V4 设置默认的淡入淡出动画
- angular - Angular - 创建从服务器检索数据并将它们发送到使用它的组件的服务的正确方法是什么?
- c# - 将数据插入drisview并在同一个gridview中显示
- leaflet - 执行 fitBounds() 后地图上的 getbounds() 错误
- symfony - 当实体关系的属性包含 null 时,symfony elastica bundle 异常
- javascript - 如何修复 tsr-detect-possible-timing-attacks 潜在的定时攻击
- postgresql - 用于数据分析的特定 postgresql 服务器配置
- highcharts - 使用 Highcharts / Highmaps 从自定义 GeoJson 创建气泡图