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

时间:2018-12-17 00:30:57

标签: sql postgresql plpgsql database-trigger

我正在Postgresql中编写触发器,以基于咨询表上的插入内容动态更新收入表中特定列的内容。 [编辑]这是我的表格的样子

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

我正在寻找一种简单的解决方案,以仅设置与 consults 上添加的NEW行的时间戳相对应的列(月)。根据psql中的时间戳获取月份名称非常容易:to_char(2018-12-05 04:42:11.66867 + 01,'Month')==>十二月

[问题]但是,我不知道如何使用它来指示psql应该更新哪一列。这是我正在寻找的一般想法。主要问题是我正在使用来表示字段(请参阅SET行)。有没有解决方法,所以我可以直接选择相关字段? (我尝试了几件事,但不是很成功)

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();

2 个答案:

答案 0 :(得分:1)

您需要在触发函数中使用动态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;

答案 1 :(得分:1)

您应该使用动态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 =  $1 AND to_char(date, ''MM-YYYY'') = $2 
                    )'
             ,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