如何解决重复键错误而不与postgresql 11.2冲突

问题描述 投票:0回答:1

insertion code

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;

that takes some argument

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

but when i update lts_i, lts_O and p_status within same id(12)

SELECT merge_db(12, 'Newton', 'director', 'd1', '12:10:22', '02:30:02', 'active')"

然后它也显示重复的键错误。我不想在这里使用CONFLICT,因为我在同一个表上有一个UPDATE RULE,并且已经postgresql说“该事件是SELECT,INSERT,UPDATE或DELETE之一。请注意,包含ON CONFLICT子句的INSERT不能在具有INSERT或UPDATE规则的表上使用。请考虑使用可更新视图。“

Update Rule

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插入到同一employee表中的“today”字段中。

但我肯定需要RULE,在这种情况下我该怎么办?

任何帮助,将不胜感激。谢谢。

sql sql-insert upsert stored-functions postgresql-11
1个回答
1
投票

您应该使用触发器。

触发功能:

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值的变化。

© www.soinside.com 2019 - 2024. All rights reserved.