如何应用“高级”基于查询的约束?

时间:2011-06-08 09:40:33

标签: postgresql

我找不到应用'高级'基于查询的约束的方法。

例如,使用以下虚构架构,我如何强制执行Bob日常活动的总百分比不超过100%?

我已经调查了trigger constraints但我不认为他们会按照我的意愿行事(如果符合某些条件,则中止INSERT / UPDATE)。

感谢您阅读我的问题以及您可以提供的任何帮助。

create table employee (
    id serial PRIMARY KEY,
    name varchar(100) NOT NULL
);

create table work_day (
    employee_id integer references employee(id) NOT NULL,
    percentage integer NOT NULL CHECK (percentage > 0 and percentage <= 100),
    activity varchar(100) NOT NULL
);

INSERT INTO employee (name) VALUES ('bob');

-- Bob spends 50% of the day slacking, 20% eating and 30% working (total = 100%)
INSERT INTO work_day (employee_id, percentage, activity) VALUES (1, 50, 'slacking'); 
INSERT INTO work_day (employee_id, percentage, activity) VALUES (1, 20, 'eating');
INSERT INTO work_day (employee_id, percentage, activity) VALUES (1, 30, 'working');

-- This should be invalid!!! 100% of Bob's time has already been allocated
INSERT INTO work_day (employee_id, percentage, activity) VALUES (1, 10, 'invalid');

2 个答案:

答案 0 :(得分:4)

我已经测试了这段代码,但它确实有效:

CREATE OR REPLACE FUNCTION check_work_day_percentage() RETURNS trigger AS $$
    BEGIN
        IF coalesce((select sum(percentage) 
                    from work_day
                    where employee_id = NEW.employee_id
                    and activity != NEW.activity), 0) 
                + coalesce(NEW.percentage, 0) > 100 THEN
            RAISE EXCEPTION 'Employee % exceeds 100 percent', NEW.employee_id;
        END IF;
        RETURN NEW;
    END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER work_day_trigger 
BEFORE INSERT OR UPDATE ON work_day
FOR EACH ROW EXECUTE PROCEDURE check_work_day_percentage();

仅供参考,表格约束不会这样做:根据docs

  

目前,CHECK表达式不能   包含子查询或参考   除了列之外的变量   当前行。

答案 1 :(得分:0)

基于pl / pgsql的constraint trigger是你想要的。 sum()事物,并检查它是否在定义的范围内。如果没有,raise an exception和声明将被取消。

或者,使用普通触发器存储/更新employee表中的总活动,并对后者设置约束。