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.

如何解决

解决方法

错误的直接原因是您尝试引用输入列名称,但在 UPSERT 的 UPDATE 部分中只有目标列名称可见。并且您必须使用 virtual table name 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_yeardate_monthdate_day。更干净、更高效。

进一步阅读:

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...