Postgresql обновляет определенные поля на основе значения (триггера) - PullRequest
0 голосов
/ 17 декабря 2018

Я пишу Триггер в Postgresql для динамического обновления содержимого определенных столбцов таблицы выручки на основе вставок в таблице консультаций .[ edit ] Вот как выглядят мои таблицы

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

Я ищу простое решение для SET только столбца (месяца), соответствующего метке времени строки 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 голосов
/ 17 декабря 2018

Вы должны использовать динамический 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;

EDIT : Кажется, TO_CHAR() пробелы для строк месяца, я добавил модификатор FM (как предложено @horse), чтобы удалить его.

См. это:

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

Демо

0 голосов
/ 17 декабря 2018

Вам необходимо использовать динамический 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;
...