SQL约束,以防止基于其先前值更新列

时间:2013-01-16 20:34:57

标签: sql postgresql check-constraints

可以使用Check Constraint(或其他一些技术)来防止在更新记录时设置的值与其先前值相矛盾。

一个例子是一个NULL时间戳,表示发生了一些事情,例如" file_exported"。一旦文件被导出并具有非NULL值,就不应再将其设置为NULL。

另一个例子是命中计数器,其中只允许整数增加,但永远不会减少。

如果它有助于我使用postgresql,但我希望看到适合任何SQL实现的解决方案

4 个答案:

答案 0 :(得分:7)

使用触发器。这对于简单的PL / PgSQL ON UPDATE ... FOR EACH ROW触发器来说是一个完美的工作,它可以同时看到NEWOLD值。

请参阅trigger procedures

答案 1 :(得分:3)

lfLoop是解决问题的最佳方法。但是继续使用触发器Craig Ringer的方法,这是一个例子。实质上,您在更新之前将列的值设置回原始(旧)值。

CREATE OR REPLACE FUNCTION example_trigger()
  RETURNS trigger AS
$BODY$
BEGIN
     new.valuenottochange := old.valuenottochange;
     new.valuenottochange2 := old.valuenottochange2;
     RETURN new;
END
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;



DROP TRIGGER IF EXISTS trigger_name ON tablename;
  CREATE TRIGGER trigger_name BEFORE UPDATE ON tablename
    FOR EACH ROW EXECUTE PROCEDURE example_trigger();

答案 2 :(得分:2)

  

一个例子是NULL时间戳,表明发生了什么,   比如“file_exported”。一旦文件被导出并且具有非NULL   值,它永远不应该再次设置为NULL。

     

另一个例子是命中计数器,其中只有整数   允许增加,但永远不会减少。

在这两种情况下,我都不会将这些更改作为属性记录在带注释的表中; “导出”或“命中计数”是一个独特的想法,表示与它们相关的对象的相关但正交的真实世界概念:

所以他们只会是不同的关系。因为我们只想要“file_exported”发生一次:

CREATE TABLE thing_file_exported(
    thing_id INTEGER PRIMARY KEY REFERENCES(thing.id),
    file_name VARCHAR NOT NULL
)

点击计数器同样是一个不同的表:

CREATE TABLE thing_hits(
    thing_id INTEGER NOT NULL REFERENCES(thing.id),
    hit_date TIMESTAMP NOT NULL,
    PRIMARY KEY (thing_id, hit_date)
)

你可以用

查询
SELECT thing.col1, thing.col2, tfe.file_name, count(th.thing_id)
FROM thing 
LEFT OUTER JOIN thing_file_exported tfe
    ON (thing.id = tfe.thing_id)
LEFT OUTER JOIN thing_hits th
    ON (thing.id = th.thing_id)
GROUP BY thing.col1, thing.col2, tfe.file_name

答案 3 :(得分:1)

PostgreSQL中的存储过程和函数可以访问旧值和新值,并且该代码可以访问任意表和列。在存储过程中构建简单(粗略?)有限状态机并不难。您甚至可以通过这种方式构建表驱动的状态机。