Postgresql 根据值更新特定字段(触发器)

Postgresql update specific fields based on a value (trigger)

我正在 Postgresql 中编写一个触发器,根据 咨询 收入 table 中的特定列动态更新特定列的内容 table。 [编辑] 这是我的 table 的样子

SELECT * FROM psy_revenues;
id | owner_id | January | February | March | April | etc | etc
---+----------+---------+----------+-------+-------+-----+----
2  | 1        |0        | 0        | 0     | 0     |     |

SELECT * FROM psy_consultations;
id | first_name | last_name |        date                 | payed | owner_id
---+------------+-----------+-----------------------------+-------+---------
3  | Gérard     | Bouchard  |2018-12-05 04:49:26.064397+01| 80    |1
4  | Pasti      | Lami      |2018-12-05 23:23:52.454849+01| 60    |2

我正在寻找一种直接的解决方案,仅设置与 咨询 上添加的新行的时间戳对应的列(月)。根据 psql 中的时间戳获取月份名称相当容易:to_char(2018-12-05 04:42:11.66867+01, 'Month') ==> December

[问题] 但是,我不知道如何使用它来指示 psql 应该更新哪一列。这是我正在寻找的内容的总体思路。主要问题是我使用 value 来表示 field(参见 SET 行)。是否有解决方法,以便我可以直接 select 相关字段? (我尝试了好几样东西,但都不是很成功)

CREATE OR REPLACE FUNCTION update_revenues()
RETURNS trigger AS
$BODY$
BEGIN
    UPDATE psy_revenues
    SET to_char(NEW.date, 'Month') = (
        SELECT SUM(payed) 
        FROM psy_consultations
        WHERE (
            owner_id = NEW.owner_id 
            AND to_char(date, 'Month')=to_char(NEW.date, 'Month')
        )
    );

RETURN NEW;
END;
$BODY$ LANGUAGE plpgsql;

CREATE TRIGGER update_revenues
AFTER INSERT 
ON psy_consultations
FOR EACH ROW 
EXECUTE PROCEDURE update_revenues();

您需要在触发器函数中使用动态 sql:生成包含正确 SQL 代码的字符串,并使用 EXECUTE 关键字 运行 它.

下面的代码应该可以解决问题:

CREATE OR REPLACE FUNCTION update_revenues()
RETURNS trigger AS
$BODY$
    DECLARE 
        new_month text;
        new_owner_id integer;
    BEGIN
        new_month    := to_char(NEW.date, 'Month');
        new_owner_id := NEW.owner_id;
        EXECUTE 
            'UPDATE psy_revenues 
            SET ' || new_month || ' = (
                SELECT SUM(payed) FROM psy_consultations 
                WHERE (
                    owner_id = ' || new_owner_id || ' 
                    AND to_char(date, ''Month'') = ' || new_month || '
                )
            )';

    RETURN NEW;
    END;
$BODY$ LANGUAGE plpgsql;

你应该使用动态 SQL。请避免连接以避免 SQL 注入,使用 format 函数和位置参数

CREATE OR REPLACE FUNCTION update_revenues()
RETURNS trigger AS
$BODY$
    DECLARE 
    BEGIN
        EXECUTE format (
            'UPDATE psy_revenues 
              SET  %I = (
                SELECT SUM(payed) FROM psy_consultations WHERE 
                    owner_id =   AND to_char(date, ''MM-YYYY'') =  
                    )'
             ,to_char(NEW.date, 'FMMonth') )      --column name to update(%I)
 USING NEW.owner_id , to_char(NEW.date, 'MM-YYYY');--values for owner_id & month
    RETURN NEW;
    END;
$BODY$ LANGUAGE plpgsql;

编辑:似乎TO_CHAR() 为月份字符串填充空格,我添加了 FM 修饰符(如@horse 所建议的那样)以将其删除。

看到这个:

knayak=# select '|'||to_char(current_date,'Month')||'|' as mon ;
     mon
-------------
 |December |
(1 row)

Demo