【问题标题】:SQL Trigger: row to be modified was already modifiedSQL 触发器:要修改的行已被修改
【发布时间】:2019-10-23 14:00:08
【问题描述】:

我有一个表,其中包含带有订单字段的项目,我用这些字段将它们绘制在树上。

CREATE TABLE items (
    menuId INTEGER,
    itemId INTEGER,
    name VARCHAR, 
    order1 INTEGER,
    order2 INTEGER,
    order3 INTEGER,
    order4 INTEGER,
);

主键是“menuId”和“itemId”。

“menuId”与“menus”表的外键。

对于每个菜单,我都有一个唯一的检查,例如对于 menu1,我不能有两个具有相同组合顺序的项目,但 menu2 可以。

我想创建一个在我插入或更新项目时触发的触发器,所以如果添加一个订单为 2 的新项目,订单 2 的项目更新为 3,订单 3 更新为 4,依此类推。现在我不在乎订单之间是否有空格,我会在稍后尝试解决这个问题。

触发器是这样的:

CREATE TRIGGER trg_items_menu_bibu
  BEFORE INSERT OR UPDATE
  ON items
  FOR EACH ROW
  EXECUTE PROCEDURE update_menu_order();

CREATE OR REPLACE FUNCTION update_menu_order()
  RETURNS trigger AS
$BODY$
BEGIN
    IF EXISTS (SELECT name
                FROM items
                WHERE order1 = NEW.order1
                AND order2 = NEW.order2
                AND order3 = NEW.order3
                AND order4 = NEW.order4
                AND menuId = NEW.menuId
                AND itemId <> NEW.itemId) THEN
        -- If exists an item for that menu with the same orders
        IF (NEW.order4 <> 0) THEN
            -- If it's an item in the sublevel4
            UPDATE items SET order4 = order4 + 1
                WHERE order1 = NEW.order1
                AND order2 = NEW.order2
                AND order3 = NEW.order3
                AND order4 = NEW.order4
                AND menuId = NEW.menuId
                AND itemId <> NEW.itemId;
        ELSEIF (NEW.order3 <> 0) THEN
            -- If it's an item in the sublevel3
            UPDATE items SET order3 = order3 + 1
                WHERE order1 = NEW.order1
                AND order2 = NEW.order2
                AND order3 = NEW.order3
                AND order4 = 0
                AND menuId = NEW.menuId
                AND itemId <> NEW.itemId;
        ELSEIF (NEW.order2 <> 0) THEN
            -- If it's an item in the sublevel2
            UPDATE items SET order2 = order2 + 1
                WHERE order1 = NEW.order1
                AND order2 = NEW.order2
                AND order3 = 0
                AND order4 = 0
                AND menuId = NEW.menuId
                AND itemId <> NEW.itemId;
        ELSE
            -- If it's an item in the sublevel1
            UPDATE items SET order1 = order1 + 1
                WHERE order1 = NEW.order1
                AND order2 = 0
                AND order3 = 0
                AND order4 = 0
                AND menuId = NEW.menuId
                AND itemId <> NEW.itemId;
        END IF;
    END IF;

    RETURN NEW;
END;
$BODY$
  LANGUAGE plpgsql;

如果我有这些物品:

menuId  itemId  name    order1  order2  order3  order4
1       1       menu1   1       0       0       0
1       2       menu2   1       1       0       0
1       3       menu3   1       2       0       0

我尝试插入以下内容:

menuId  itemId  name    order1  order2  order3  order4
1       4       menu4   1       1       0       0       

触发器正确更新为:

menuId  itemId  name    order1  order2  order3  order4
1       1       menu1   1       0       0       0
1       4       menu4   1       1       0       0       
1       2       menu2   1       2       0       0
1       3       menu3   1       3       0       0

但如果我尝试更新:

1       3       menu3   1       1       0       0

我收到一条错误消息,指出要修改的一行已被修改。

我了解问题是触发器使menu2将order2更新为3,谁强制menu3将order2更新为4,但menu3已经被原始更新修改了。

我不知道我该如何解决这个问题,或者是否有可能。

【问题讨论】:

    标签: sql postgresql triggers


    【解决方案1】:

    订单使用double precision 而不是integer

    这样,您总是可以在两个现有项目之间插入一个新项目,只需使用它们订单的平均值。

    最大的优势是无需修改现有条目,因此您根本不需要触发器。

    ORDER BY 可以正常工作;如果出于任何原因需要显示整数订单,请使用dense_rank 窗口函数在查询中生成它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      • 2017-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多