如何在不与 postgresql 11.2 冲突的情况下解决重复键错误

How to resolve duplicate key error without conflict with postgresql 11.2

插入代码

INSERT INTO employee (pid, pname, desig, dept, lts_i, lts_O, p_status) VALUES %s \
                    ON CONFLICT (pid) DO UPDATE SET \
                    (pname, desig, dept, lts_i, lts_O, p_status) = \
                    (EXCLUDED.pname, EXCLUDED.desig, EXCLUDED.dept, EXCLUDED.lts_i, EXCLUDED.lts_O, EXCLUDED.p_status) \
                    RETURNING *

如果我像上面那样插入,那么它工作正常。我没有使用 CONFLICT,而是使用了以下函数

CREATE FUNCTION employee_db(
  pid1 integer,
  pname1 text,
  desig1 text,
  dept1 text,
  lts_i1 time,
  lts_o1 time,
  p_status1 text
) RETURNS VOID AS
$$
BEGIN
LOOP
-- first try to update the key
-- note that "a" must be unique
UPDATE employee SET (lts_i, lts_o, p_status) = (lts_i1, lts_o1, p_status1) WHERE pid = pid1;
IF found THEN
RETURN;
END IF;
-- not there, so try to insert the key
-- if someone else inserts the same key concurrently,
-- we could get a unique-key failure
BEGIN
INSERT INTO employee(pid, pname, desig, dept, lts_i, lts_o, p_status) VALUES (pid1, pname1, desig1, dept1, lts_i1, lts_o1, p_status1);
RETURN;
EXCEPTION WHEN unique_violation THEN
-- do nothing, and loop to try the UPDATE again
END;
END LOOP;
END;
$$
LANGUAGE plpgsql;

需要一些论据

SELECT merge_db(12, 'Newton', 'director', 'd1', '10:00:26', '00:00:00', 'P-Status')"

但是当我在同一 id(12)

中更新 lts_i、lts_O 和 p_status 时
SELECT merge_db(12, 'Newton', 'director', 'd1', '12:10:22', '02:30:02', 'active')"

然后它也显示重复键错误。 我不想在这里使用 CONFLICT,因为我在同一个 Table 上有一个更新规则并且 postgresql 已经说 "The event is one of SELECT, INSERT, UPDATE, or DELETE. Note that an INSERT containing an ON CONFLICT clause cannot be used on tables that have either INSERT or UPDATE rules. Consider using an updatable view instead."

更新规则

CREATE RULE log_employee AS ON UPDATE TO employee
    WHERE NEW.lts_i <> OLD.lts_i or NEW.lts_O <> OLD.lts_O
    DO UPDATE employee set today = current_date where id = new.id;

如果 lts_i、lts_o 或 p_status 更新,则将 current_date 插入同一员工 "today" 字段中 table .

但我确实需要规则,在这种情况下我该怎么办?

如有任何帮助,我们将不胜感激。 谢谢。

你应该为此使用触发器。

触发函数:

create function emp_trigger_func()
  returns trigger
as
$$
begin
   new.today := current_date;
   return new;
end;
$$
language plpgsql;

关于何时应该更新列的条件最好在触发器定义中完成,以避免触发不必要的触发器

create trigger update_today
  before update on employee
  for each row
  when (NEW.lts_i <> OLD.lts_i or NEW.lts_O <> OLD.lts_O)
  execute procedure emp_trigger_func();

请注意,<> 没有正确处理 NULL 值。如果lts_ilts_o可以包含空值,那么触发条件最好写成:

  when (   NEW.lts_i is distinct from OLD.lts_i 
        or NEW.lts_O is distinct from OLD.lts_O)

这也会捕捉到 null 值的变化。