【问题标题】:Preventing user from adding a row that has more space than the alotted space, in a self-referencing table防止用户在自引用表中添加空间大于分配空间的行
【发布时间】:2012-08-03 12:58:43
【问题描述】:

我在分层查询中遇到问题。我有一个这样的自引用表:

    id    parent_id    name    size
-----------------------------------------
    1       null       Ship1    50
    2        1         cabin1   10
    3        1         cabin2   30
    4        3         shelf1    5
    5        3         shelf2   20
    6       null       Ship2    50
    7        6         cabin1   10
    8        6         cabin2   30
    9        7         shelf1   15

我需要在数据库中添加一个触发器,以防止用户添加超过该船剩余尺寸的客舱。

例如,在表格中,对于 1 号船,我们的总尺寸为 50。有 2 个船舱占用了 40 的尺寸。所以现在我们剩下 10 个作为可用空间。我们应该不能再添加一个大小>10 的客舱。任何

表中可以有任意数量的船舶条目(即根)。

我知道分层查询,我可以遍历一棵树,但我发现很难收集我对这个问题的想法。谁能指出我正确的方向,以便我可以成功添加该触发器?

【问题讨论】:

  • 在 Oracle 中查找“connect by”语句。你需要遍历一棵树,这就是Oracle的解决方案。
  • 另外,如果您最终升级到 11gR2,oracle 现在还支持递归 CTE。顺便说一句,您认为分层表真的最适合您的需求吗?相反,我会使用“Ships”表、“Cabins”表,也许还有“Cabin Contents”表或类似的......
  • 感谢您的回复戈登。我知道连接方式和分层查询。我和他们一起工作了一点,我可以轻松地穿过一棵树。但我没有得到这个特定问题的逻辑。
  • 不幸的是,我没有根据自己的舒适度来修改任务的奢侈。由于我不是管理员,因此我必须解决给我的问题。但感谢您的意见!

标签: sql oracle oracle10g hierarchical-data self-referencing-table


【解决方案1】:

我同意@N_west 的观点,您可能应该为ShipsCabinsShelves 设置单独的表,以实现极简主义目的和便于维护(存档/清除等)。 如果您想要一个触发器来处理这个问题,那么您必须使用SHIPS 上的触发器将数据从SHIPS 捕获到日志表中,然后使用日志表上的数据来验证SHIPS 上的插入。它不是最好的解决方案,但可以实现您想要的。您可以根据错误代码 (20101) 在应用程序中使用用户定义的异常来处理 ALERTS

SQL> CREATE TABLE LOG_SHIPS AS SELECT * FROM SHIPS;

SQL> CREATE or REPLACE TRIGGER TRG_SHIP
BEFORE INSERT ON SHIPS
FOR EACH ROW

L_count   NUMBER(10);
L_total   NUMBER(10);
e_exp     EXCEPTION;

BEGIN
     SELECT sum(size) INTO L_count
       FROM LOG_SHIPS
      WHERE parent_id = :new.parent_id;

     SELECT size INTO L_total
       FROM LOG_SHIPS
      WHERE id = :new.parent_id;

     if L_count+:new.size > L_total then
        RAISE e_exp;
     else
        INSERT INTO LOG_SHIPS VALUES (:new.id,:new.parent_id,:new.name,:new.size);
     end if;

EXCEPTION
   WHEN e_exp THEN
     RAISE_APPLICATION_ERROR (-20101,'Size entered exceeds limit.');
   WHEN others THEN
      null; -- do some meaningful exception handling here
END;
/

另一种方法是仅当您使用 Oracle 11g 时才使用 COMPOUND TRIGGERS

【讨论】:

  • 我认为 DBMS_OUTPUT 不是一个好的异常处理方法
  • 我已经用RAISE_APPLICATION_ERROR 编辑了我的答案。这样,可以捕获错误代码 20101,以在应用程序中通过弹出消息或其他内容提醒用户。
  • 问题是,每当您在触发器中查询正在修改的表时,都会遇到变异表问题。
  • Annjawn,非常感谢您提供的触发代码。触发器工作正常并解决了我的问题。一个问题-您告诉我创建日志表是否有原因。如果我不创建它并直接在我的船舶表上工作怎么办?
  • 感谢大家对这个问题的宝贵见解。作为一个新手,我真的很感激他们,因为我可以从他们那里学到很多新东西!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多