【问题标题】:Trigger to find next available inventory location触发以查找下一个可用库存位置
【发布时间】:2015-06-15 22:12:48
【问题描述】:

我正在尝试实施库存跟踪,但遇到了问题。由于这是我第一次涉足数据库触发器(以及一般的 PL/SQL),我认为我需要调整我对如何解决这个问题的想法/理解。 我的情况如下:每次将新商品添加到我的库存时,我都需要为其自动分配第一个可用的物理存储位置。当物品被消耗时,它们会从库存中移除,从而腾出一个物理位置(即我们正在回收这些物理位置)。我有两张表:一张库存表和一张包含所有合法位置名称/ID 的表。

Table: ALL_LOCATIONS
Location_ID
SP.1.1.1.a
SP.1.1.1.b
SP.1.1.1.c
SP.1.1.2.a
SP.1.1.2.b
SP.1.1.2.c
SP.1.1.3.a
SP.1.1.3.b
SP.1.1.3.c
...
SP.25.5.6.c

Table: ITEM_INVENTORY    
Item_ID | Location_ID
    1         SP.1.1.1.a
    2         SP.1.1.1.b
    4         SP.1.1.2.a
    5         SP.1.1.2.b
    6         SP.1.1.2.c
    21        SP.1.1.4.a
    …         …

注意:第一个可用的 location_ID 应该是 SP.1.1.1.c

我需要创建一个触发器,它将下一个可用的 Location_ID 分配给插入的行。搜索这个站点,我看到了几个类似的问题,但是它们是针对确定下一个可用位置的逻辑。就我而言,我想我已经把它弄下来了,但我不知道如何将它作为触发器来实现。让我们只关注插入触发器。 “MINUS”策略(如下所示)在选择下一个可用位置时效果很好,但 Oracle 不喜欢在触发器中这样做,因为我正在从我正在编辑的同一张表中读取(引发变异表错误)。

我已经阅读了一些关于 mutating table 错误的内容,并建议了一些解决方法(自主事务等)。但是,我阅读的关键信息是,“你的做法是错误的。”所以我的问题是,“解决这个问题的另一种方法是什么,这样我就可以实现一个干净简单的解决方案,而不必在变异表周围破解我的方式?”

注意:我确信您可以使用我的触发代码找到各种不太正确的东西,如果您指出它们,我肯定会学到一些东西 - 但是我的目标是学习新的方法来处理/思考关于我的设计的根本问题。

create or replace TRIGGER Assign_Plate_Location
  BEFORE INSERT ON ITEM_INVENTORY
  FOR EACH ROW

  DECLARE
  loc VARCHAR(100) := NULL;
  
  BEGIN
  IF(:new.LOCATION_ID IS NULL) THEN
      BEGIN 
        SELECT LOCATION_ID INTO loc FROM
          (SELECT DISTINCT LOCATION_ID FROM ALL_LOCATIONS
          MINUS
          SELECT DISTINCT LOCATION_ID FROM ITEM_INVENTORY)
        WHERE ROWNUM = 1;
      EXCEPTION
      WHEN NO_DATA_FOUND THEN
        loc := NULL;
      END;
      
      IF(loc IS NOT NULL) THEN
        :new.LOCATION_ID := loc;
      END IF;
    END IF;
  END;

【问题讨论】:

  • 除了使用触发器之外,您能否仅将插入内容包装到存储过程中并在插入具有正确位置 ID 的记录之前检查过程中的下一个可用位置?
  • 感谢 Ollie,我认为这可能可行,但当前配置无法选择。

标签: oracle triggers inventory


【解决方案1】:

有几种方法可以做到这一点。您可以将列 AVAILABLEOCCUPIED 添加到第一个表 并使用where available = 'Y' 仅从此表中选择数据。在这种情况下,您还需要触发器 用于删除和更新第二张表上的 location_id。

第二个选项 - 在插入数据时使用 merge 或在 item_inventory.location_id 为空时从 all_locations 检索数据的某些过程。

第三个选项 - Oracle 11g 引入compound triggers 这允许更好地处理变异表。在这种情况下,触发器看起来像这样:

create or replace trigger assign_plate_location
for insert on item_inventory compound trigger

  loc varchar2(15) := null;
  type t_locs is table of item_inventory.location_id%type;
  v_locs t_locs;
  i number := 1;

  before statement is 
  begin
    select location_id 
      bulk collect into v_locs from all_locations al
      where not exists (
        select location_id from item_inventory ii 
          where ii.location_id = al.location_id );
  end before statement;

  before each row is
  begin
    if :new.location_id is null then
      if i <= v_locs.count() then 
        :new.location_id := v_locs(i);
        i := i + 1;
      end if;
    end if;
  end before each row;
end assign_plate_location;

我在您示例中的数据上对其进行了测试,插入(带选择)看起来不错。你可以试一试,看看它是否有效,也许这会适合你。

最后一点 - 在您的选择中,您不需要区分,减去 makes values distinct。 还要考虑订购数据,现在您的 select(和我的)可能会从 ALL_LOCATIONS 中随机抽取一行。

【讨论】:

  • 谢谢!建议的复合触发器按照宣传的方式工作,以解决变异表问题。我已经修改了代码(包括 order by 子句)并放入了测试系统。到目前为止,它似乎表现得很好。谢谢思考!
  • 不客气。我希望触发器能正常工作。我注意到在我的代码中不需要变量 loc(第 4 行) - 您可以删除它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多