0

我有一种情况,如果当前 modified_at 列比更新中指定的列更新,我想拒绝对表的更新。我试图用 CHECK 约束来做到这一点,但它没有效果。

这是一个例子:

CREATE TABLE test (
    id SERIAL PRIMARY KEY,
    value INTEGER NOT NULL DEFAULT 0,
    modified_at timestamptz DEFAULT NOW()
);                  

ALTER TABLE test ADD CHECK (modified_at >= modified_at);

INSERT INTO test (id, value) VALUES (1, 1);
INSERT 0 1
SELECT * FROM test;
 id | value |          modified_at          
----+-------+-------------------------------
  1 |     1 | 2013-05-30 14:34:37.234456-07

UPDATE test
    SET value = 2, modified_at = NOW() - INTERVAL '1 day'                                                                              
WHERE id = 1;
UPDATE 1
SELECT * FROM test;
 id | value |          modified_at          
----+-------+-------------------------------
  1 |     2 | 2013-05-29 14:35:41.337543-07

这似乎没有按预期工作。直觉上我可以看到这是一个问题。规划者如何知道左侧应该是新值而右侧应该是旧值?

知道这行不通,应该如何执行这个约束?

4

2 回答 2

3

您必须根据更新行的新 modified_date 检查旧的 modified_date,您可以使用触发器来执行此操作。将触发器设置为在更新之前在每一行上运行并创建一个处理它的函数,选择是要保留旧的 modified_date 还是根本不想执行任何更新。

触发器可以这样完成:

CREATE TRIGGER trigger_test
  BEFORE INSERT OR UPDATE
  ON test
  FOR EACH ROW
  EXECUTE PROCEDURE fn_trigger_test();

和这样的功能:

CREATE OR REPLACE FUNCTION fn_trigger_test()
  RETURNS trigger AS
$BODY$
  DECLARE
BEGIN
IF (TG_OP = 'UPDATE') THEN
    IF NEW.modified_at<OLD.modified_at THEN

        RAISE EXCEPTION 'Date_modified older than previous';
        /* or to keep the old modified date:
             NEW.modifed_at=OLD.modified_at;
         RETURN NEW; */
    ELSE
        RETURN NEW;
    END IF;
END IF; 

END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
于 2013-05-31T01:42:56.493 回答
2

就 CHECK 约束而言,没有新值和旧值之类的东西。

PostgreSQL 触发器可以访问新数据。另一种相当常见的方法是撤销对表的权限,并要求所有访问都通过存储过程进行。存储过程可以访问新数据,通过参数传递,并且存储过程可以检查表中的值,更新其他表以进行审计等。请参阅CREATE FUNCTIONplpgsql

于 2013-05-30T22:08:41.750 回答