我有一些麻烦创造一个触发器,它将获得一个人拥有的当前点,检查他将获得什么奖励,然后更新他的奖励头衔。所以这就是场景:
PersonTable
| Person (PK) | RewardTitle (FK) | Score|
| A | Beginner | 0 |
| B | MidRange | 17 |
| C | Professional | 32 |
RewardTable
| RewardTitle (PK) | BottomScore | UpperScore| Reward |
| Beginner | 0 | 9 | Free food |
| MidRange | 10 | 19 | Free games |
| Professional | 20 | 100 | Unlimited time|
情况是,我想更新人A,以便他得到11分,然后找出他的新点属于哪个RewardTitle,并相应地改变他的奖励标题,所以因为他有11分,他的奖励标题现在将是中等范围。
我试图创建一个触发器,试图找到他所属的RewardTitle,然后相应地更新这个值,但我一直收到错误说:
Person is mutating, trigger/function may not see it
我明白了这个问题,但我想不出任何其他方法来实现这个结果。我尝试过使用
pragma autonomous_transaction;
但它仍然无效,以下是我的尝试:
UPDATE PersonTable
SET Score = 11
WHERE Person = 'A';
DELIMITER //
CREATE OR REPLACE TRIGGER person_upd_trigger
AFTER UPDATE ON PersonTable
FOR EACH ROW
DECLARE
temp_variable VARCHAR(120);
BEGIN
SELECT r.RewardTitle INTO temp_variable
FROM PersonTable p, RewardTable r
WHERE :NEW.Person = p.Person
AND p.Score BETWEEN r.BottomScore AND r.UpperScore;
UPDATE PersonTable
SET RewardTitle = temp_variable
WHERE :NEW.Person = Person;
END;
我将非常感谢能得到的所有帮助,我对Oracle SQL很陌生。三江源
答案 0 :(得分:2)
您无法在BEFORE TRIGGER中更新已经更新的同一个表(如果认为允许会导致无限循环)。相反,您需要将触发器重新编写为:
为了实现这一点,您应该将触发器定义更改为BEFORE
CREATE OR REPLACE TRIGGER person_upd_trigger
BEFORE UPDATE ON PersonTable -- declare it as BEFORE
FOR EACH ROW
DECLARE
temp_variable VARCHAR(120);
BEGIN
SELECT r.RewardTitle INTO temp_variable
FROM RewardTable r
WHERE :NEW.Score BETWEEN r.BottomScore AND r.UpperScore;
-- here you are setting the new value, no need for an update.
:NEW.RewardTitle := temp_variable;
END;