我正在阅读很多文章如何创建触发器,但我真的不知道如何根据日期创建触发器。
我想添加一个触发器: 1.如果在特定日期的分钟总和高于50,则在添加或更新之前进行检查。
所以在示例实体中:
CREATE TABLE employees(
id int serial primary key,
minutes int NOT NULL,
date date NOT NULL
);
这是db中的典型数据:
(1, 40, '2018-01-1')
(2, 30, '2018-01-2')
(3, 20, '2018-01-3')
(4, 10, '2018-01-4')
现在如果我添加:
(6, 20, '2018-01-1')
(7, 40, '2018-01-2')
(8, 20, '2018-01-3')
(9, 20, '2018-01-4')
最终结果将是:
(1, 40, '2018-01-1')
(2, 30, '2018-01-2')
(3, 20, '2018-01-3')
(4, 10, '2018-01-4')
(8, 20, '2018-01-3')
(9, 20, '2018-01-4')
id为6和7被省略(未添加,因为它们高于50)
我真的很感激帮助:)
更新:在@Laurenz Albe的帮助下,我创建了函数和触发器,如下所示:
CREATE FUNCTION func_check_minutes() RETURNS trigger AS
$$
BEGIN
IF (SELECT sum(minutes) + NEW.minutes FROM employees WHERE date = NEW.date) > 50
THEN RETURN NULL;
END IF;
END;
$$
LANGUAGE 'plpgsql';
CREATE TRIGGER tr_check_minutes
BEFORE INSERT ON employees
FOR EACH ROW
EXECUTE PROCEDURE func_check_minutes();
但是这个解决方案没有明确的原因就失败了。
答案 0 :(得分:1)
这种触发器的核心部分是:
IF (SELECT sum(minutes) + NEW.minutes
FROM employees
WHERE date = NEW.date) > 50
THEN
<throw an error or return NULL>
END IF;
但是你应该知道存在可能导致违反条件的竞争条件:
如果来自两个插入的触发器同时运行,则每个插件都不会看到另一个事务的影响,并且两者都可以报告成功,而两个事务提交后的最终结果可能超出限制。
解决这个问题的唯一方法就是使用SERIALIZABLE
次交易。
答案 1 :(得分:1)
由于你没有提到失败的原因,我假设没有任何东西被写入表格。您必须在RETURN NEW
END IF
我更新了触发器
CREATE FUNCTION func_check_minutes() RETURNS trigger AS
$$
BEGIN
IF (SELECT sum(minutes) + NEW.minutes FROM employees WHERE date = NEW.date) > 50
THEN RETURN NULL;
END IF;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';
CREATE TRIGGER tr_check_minutes
BEFORE INSERT ON employees
FOR EACH ROW
EXECUTE PROCEDURE func_check_minutes();