我将触发器从SQL转换为Oracle 10时结合了JOIN,ORDER BY和ROWNUM。 需要从脚本中删除ORDER BY才能正确创建触发器,但我需要它。
CREATE OR REPLACE TRIGGER Update_Quantity
AFTER INSERT
ON MediaUsed
FOR EACH ROW
Begin
UPDATE Inventory
SET Quantity = Quantity - 1
WHERE ID = ( SELECT IV1.ID FROM Inventory IV1
INNER JOIN (
SELECT Distinct ItemNo, Item, :NEW.Plant AS Plant FROM Inventory
WHERE (Not :NEW.IsChanged = 0) AND Inventory.ID = :NEW.ID_Inventory
) IV2 ON IV1.Item = IV2.Item AND IV1.ItemNo = IV2.ItemNo AND IV1.Plant = IV2.Plant
WHERE IV1.Quarantined = 0 AND IV1.Quantity > 0 AND IV1.ExpiryDate > SYS_EXTRACT_UTC(SYSTIMESTAMP) AND ROWNUM = 1
ORDER BY IV1.ID
);
End;
Warning: TRIGGER created with compilation errors.
我试图包装查询并将ORDER By放在外面,但是没有用。我发现ROWNUM不是最好的方法。 我在搜索中发现RANK()OVER是更好的解决方案,并编写了以下内容,但触发器仍然存在一些问题:
CREATE OR REPLACE TRIGGER Update_Quantity
AFTER INSERT
ON MediaUsed
FOR EACH ROW
Begin
UPDATE Inventory
SET Quantity = Quantity - 1
WHERE ID = ( SELECT IV1.ID, RANK() OVER (ORDER BY IV1.ID) sal_rank FROM Inventory IV1
INNER JOIN (
SELECT Distinct ItemNo, Item, :NEW.Plant AS Plant FROM Inventory
WHERE (Not :NEW.IsChanged = 0) AND Inventory.ID = :NEW.ID_Inventory
) IV2 ON IV1.Item = IV2.Item AND IV1.ItemNo = IV2.ItemNo AND IV1.Plant = IV2.Plant
WHERE IV1.Quarantined = 0 AND IV1.Quantity > 0 AND IV1.ExpiryDate > SYS_EXTRACT_UTC(SYSTIMESTAMP) AND sal_rank <= 1 --ROWNUM = 1
);
End;
Warning: TRIGGER created with compilation errors.
删除ORDER BY可以修复触发器,但是我需要它!
CREATE OR REPLACE TRIGGER Update_Quantity
AFTER INSERT
ON MediaUsed
FOR EACH ROW
Begin
UPDATE Inventory
SET Quantity = Quantity - 1
WHERE ID = ( SELECT IV1.ID FROM Inventory IV1
INNER JOIN (
SELECT Distinct ItemNo, Item, :NEW.Plant AS Plant FROM Inventory
WHERE (Not :NEW.IsChanged = 0) AND Inventory.ID = :NEW.ID_Inventory
) IV2 ON IV1.Item = IV2.Item AND IV1.ItemNo = IV2.ItemNo AND IV1.Plant = IV2.Plant
WHERE IV1.Quarantined = 0 AND IV1.Quantity > 0 AND IV1.ExpiryDate > SYS_EXTRACT_UTC(SYSTIMESTAMP) AND ROWNUM = 1
--ORDER BY IV1.ID
);
End;
Trigger created.
所以我需要ORDER BY,并且需要使用该JOIN获取第一行。如果有什么办法可以使我对TOAD中的问题有更多的描述,那也是完美的。
答案 0 :(得分:1)
您的第二个触发器看起来应该可以工作,但是您的查询将两个值返回到=子句:
WHERE ID = ( SELECT IV1.ID, RANK() OVER (ORDER BY IV1.ID) sal_rank
将其推入子查询以仅获得排名靠前的ID怎么样?像这样:
CREATE OR REPLACE TRIGGER OR1_EM.Update_Quantity
AFTER INSERT
ON MediaUsed
FOR EACH ROW
Begin
UPDATE Inventory
SET Quantity = Quantity - 1
WHERE ID = (SELECT ID
FROM
( SELECT IV1.ID, RANK() OVER (ORDER BY IV1.ID) sal_rank FROM Inventory IV1
INNER JOIN (
SELECT Distinct ItemNo, Item, :NEW.Plant AS Plant FROM Inventory
WHERE (Not :NEW.IsChanged = 0) AND Inventory.ID = :NEW.ID_Inventory
) IV2 ON IV1.Item = IV2.Item AND IV1.ItemNo = IV2.ItemNo AND IV1.Plant = IV2.Plant
WHERE IV1.Quarantined = 0 AND IV1.Quantity > 0 AND IV1.ExpiryDate > SYS_EXTRACT_UTC(SYSTIMESTAMP) AND sal_rank <= 1 --ROWNUM = 1
)
WHERE sal_rank = 1 );
End;
此外,请注意,如果该子查询多次返回该ID,则RANK可以为给定值返回多行。如果可能的话,您需要将其减少到仅返回=子句的一行,最简单的方法是使用MAX():
CREATE OR REPLACE TRIGGER OR1_EM.Update_Quantity
AFTER INSERT
ON MediaUsed
FOR EACH ROW
Begin
UPDATE Inventory
SET Quantity = Quantity - 1
WHERE ID = (SELECT MAX(ID)
FROM
( SELECT IV1.ID, RANK() OVER (ORDER BY IV1.ID) sal_rank FROM Inventory IV1
INNER JOIN (
SELECT Distinct ItemNo, Item, :NEW.Plant AS Plant FROM Inventory
WHERE (Not :NEW.IsChanged = 0) AND Inventory.ID = :NEW.ID_Inventory
) IV2 ON IV1.Item = IV2.Item AND IV1.ItemNo = IV2.ItemNo AND IV1.Plant = IV2.Plant
WHERE IV1.Quarantined = 0 AND IV1.Quantity > 0 AND IV1.ExpiryDate > SYS_EXTRACT_UTC(SYSTIMESTAMP) AND sal_rank <= 1 --ROWNUM = 1
)
WHERE sal_rank = 1 );
End;
答案 1 :(得分:0)
最后,我通过包装脚本并将ROWNUM放在外面来解决了这个问题:
CREATE OR REPLACE TRIGGER OR1_FG.Update_Quantity
AFTER INSERT
ON OR1_FG.MediaUsed
FOR EACH ROW
Begin
UPDATE OR1_FG.Inventory
SET Quantity = Quantity - 1
WHERE ID =
(
select ID from
(
SELECT IV1.ID FROM OR1_FG.Inventory IV1
INNER JOIN (
SELECT Distinct LotNumber, Item, :NEW.Plant AS Plant
FROM OR1_FG.Inventory WHERE (Not :NEW.IsChanged = 0
)
AND OR1_FG.Inventory.ID = :NEW.ID_Inventory
) IV2 ON IV1.Item = IV2.Item AND IV1.LotNumber = IV2.LotNumber AND IV1.Plant = IV2.Plant
WHERE IV1.Quarantined = 0 AND IV1.Quantity > 0 AND IV1.ExpiryDate > SYS_EXTRACT_UTC(SYSTIMESTAMP) ORDER BY IV1.ID) WHERE ROWNUM = 1);
End;
感谢您的所有贡献。