postgres:插入取决于先前的插入

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

我有一个如下表:

the_table
+----+----------+-------+
| id | category | total |
+----+----------+-------+
|  1 | A        |     0 |
|  2 | B        |     5 |
|  3 | A        |     7 |
|  4 | A        |     2 |
+----+----------+-------+


我想插入一个新行,其中total列将更新为previous_total + new_total,以保持连续的总和对于每个类别

示例:INSERT INTO the_table VALUES (DEFAULT, 'A', most_recently_entered_A - 1)

[问题是,如果most_recently_entered_A - n < 0(即n是一个使总数为负的数字,我希望插入失败。

为了执行此操作,我需要确保没有其他插入具有先前的总值,因为这显然会导致总条件可能不正确的竞争状况。

我假设有某种触发器或函数可以使我在锁定特定total的最后一个category的同时执行此插入操作,但老实说,我不知道这样做的安全方法。

类似以下工作吗?

DO $$
DECLARE
  previous INTEGER;
  new_val  INTEGER;
  cat      TEXT;
BEGIN
  new_val := 2;
  cat := 'A';
  SELECT total FROM the_table WHERE category = cat ORDER BY id DESC LIMIT 1 INTO previous;
  IF previous - new_val < 0 THEN
    RAISE EXCEPTION 'The total will be negative if this insert is performed';
  ELSE
    INSERT INTO the_table VALUES (default, cat, previous - new_val);
  END IF;
END $$;

以上内容将保留不变式,并且有更高效的方法吗?


编辑:我意识到我忘记了重要的一点。我没有在total列上使用检查约束的原因是因为此约束仅适用于某些类别。例如,我可以添加另一个类别C,该类别的总和为负。

sql postgresql rdbms
1个回答
0
投票

[如果您希望在插入总数变为负数时插入失败,请使用check约束:

alter table the_table add constraint chk_the_table_total
    check (total >= 0);

请勿尝试在您的代码中执行此操作。让数据库来做保证完整性的工作。

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