【发布时间】: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,我认为这可能可行,但当前配置无法选择。