首页 > 解决方案 > 使用 PSQL 中的函数仅更新最后更新的行

问题描述

我正在开发一个功能,该功能将根据到达和离开时间计算工作时间。

我的功能如下所示:

CREATE FUNCTION Sati_rada() 
  RETURNS TRIGGER 
as $Update$ 
BEGIN
    update radni_sati 
        set sati_rada=(select (current_date + (odlazak-dolazak)) 
                       from radni_sati 
                       where datum=current_date 
                       and dolazak IS NOT NULL 
                       LIMIT 1)
  WHERE datum=current_date 
    AND odlazak IS NOT NULL 
    AND DOLAZAK IS NOT NULL; 
  RETURN NULL; 
END $Update$ 
language plpgsql;

我的触发器如下所示:

CREATE TRIGGER Sati_rada_trigger
AFTER UPDATE OF odlazak ON radni_sati 
FOR EACH ROW EXECUTE PROCEDURE Sati_rada();

当我想在我手动更新的最后一行上使用函数时,问题就从这里开始了。

例如(我从我的母语翻译了列的名称):

SELECT id_radni_sati as id,ime as name,dolazak as arrival, 
odlazak as departure, sati_rada as "hours of work" FROM radni_sati
WHERE datum='31/08/2018';

  id   |  name   |       arrival       |      departure      |    hours of work
-------+---------+---------------------+---------------------+---------------------
 22282 | Nevenko | 2018-08-31 07:00:00 |                     |
 22284 | Marko   | 2018-08-31 11:41:52 | 2018-08-31 12:01:45 | 2018-08-31 00:19:53

如果我手动尝试更改一排的离开:

UPDATE radni_sati SET odlazak='31/08/2018 07:05:00' where id_radni_sati=22282;

这发生了:

postgres=# select id_radni_sati as id,ime as name,dolazak as arrival,
odlazak as departure, sati_rada as "hours of work" from radni_sati 
where datum='31/08/2018';
  id   |  name   |       arrival       |      departure      |    hours of work
-------+---------+---------------------+---------------------+---------------------
 22282 | Nevenko | 2018-08-31 07:00:00 | 2018-08-31 07:05:00 | 2018-08-31 00:05:00
 22284 | Marko   | 2018-08-31 11:41:52 | 2018-08-31 12:01:45 | 2018-08-31 00:05:00
(2 rows)

我的问题是:每次更新 odlazak 列时,如何计算数据库中单行(需要更新的行)的工作时间?

标签: postgresqlfunctiontimestampdatabase-trigger

解决方案


问题在于触发器函数中的更新语句。它应该使用更新的行的 id 来确保它只更新正确的记录。

这是设置:

CREATE TABLE t (id INTEGER, arrival TIMESTAMP, departure TIMESTAMP, hours_of_work TIME);

CREATE OR REPLACE FUNCTION public.trig()
        RETURNS TRIGGER AS $$
BEGIN
        UPDATE t
        SET hours_of_work = NEW.departure - NEW.arrival
        WHERE id = NEW.id;

        RETURN NULL;
END
        $$ LANGUAGE plpgsql;


CREATE TRIGGER t_trig
AFTER UPDATE OF departure ON public.t 
FOR EACH ROW EXECUTE PROCEDURE public.trig();

INSERT INTO t VALUES (1, NOW(), NOW() + INTERVAL '1 hour', (NOW() + INTERVAL '1 hour') - NOW());
INSERT INTO t VALUES (2, NOW(), NOW() + INTERVAL '1 hour');

表如下所示:

在此处输入图像描述

现在更新:

UPDATE t SET departure = NOW() + INTERVAL '2 hours' WHERE id = 2;

现在的表格是:

在此处输入图像描述


所以在你的情况下你应该改变

update radni_sati 
    set sati_rada=(select (current_date + (odlazak-dolazak)) 
                   from radni_sati 
                   where datum=current_date 
                   and dolazak IS NOT NULL 
                   LIMIT 1)   WHERE datum=current_date 
AND odlazak IS NOT NULL 
AND DOLAZAK IS NOT NULL;

UPDATE radni_sati
SET sati_rada = current_date + (NEW.odlazak - NEW.dolazak)
WHERE id_radni_sati = NEW.id_radni_sati;

推荐阅读