触发查找下一个可用广告资源位置

时间:2015-06-15 22:12:49

标签: oracle triggers inventory

我正在尝试实施库存跟踪并遇到问题。由于这是我第一次涉足数据库触发器(& 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在触发器中不喜欢这个,因为我正在读取与我正在编辑的表相同的表(抛出变异表错误)。

我已经完成了关于变异表错误的一些阅读,并提出了一些变通方法(自治事务等)。但是,我读到的关键信息是“你的方式错误”。所以我的问题是,“解决这个问题的另一种方法是什么,以便我可以实现一个干净简单的解决方案,而不必破解我的方式来改变表格?”

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

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;

1 个答案:

答案 0 :(得分:1)

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

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

第三个选项 - 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;

我测试了你的例子中的数据,插入(使用select)看起来没问题。你可以尝试一下,检查它是否有效,也许这适合你。

最后的笔记 - 在您的选择中,您不需要明确,MINUS makes values distinct。 另外考虑订购数据,现在您的select(和我的)可能会从ALL_LOCATIONS中随机排列。