Oracle 触发器:SELECT INTO,未找到数据
Oracle trigger: SELECT INTO, no data found
我有以下 table 描述每个行星由哪些化学元素组成的百分比。
CREATE TABLE elem_in_planet
(
id_planet INTEGER,
element_symbol CHAR(2),
percent_representation NUMBER CONSTRAINT NN_elem_in_planet NOT NULL,
CONSTRAINT PK_elem_in_planet PRIMARY KEY (id_planet, element_symbol),
CONSTRAINT FK_planet_has_elem FOREIGN KEY (id_planet) REFERENCES planet (id_planet),
CONSTRAINT FK_elem_in_planet FOREIGN KEY (element_symbol) REFERENCES chemical_element (element_symbol)
);
我正在尝试制作一个触发器,当用户向行星添加新元素并且该行星中的元素总和超过 100% 时会警告用户。我想到了这个。
CREATE OR REPLACE TRIGGER elem_in_planet_check
AFTER INSERT OR UPDATE ON elem_in_planet
FOR EACH ROW
DECLARE
sum_var NUMBER;
PRAGMA autonomous_transaction;
BEGIN
SELECT SUM(percent_representation)
INTO sum_var
FROM elem_in_planet
WHERE id_planet = :NEW.id_planet
GROUP BY id_planet;
EXCEPTION
WHEN NO_DATA_FOUND THEN
sum_var := 0;
IF sum_var > 100 THEN
DBMS_OUTPUT.put_line('WARNING: Blah blah.');
END IF;
END;
/
此代码似乎每次都会抛出 NO_DATA_FOUND 异常,即使我插入了测试数据并且当我 运行 单独 SQL 查询时,它仍按预期工作。
我是新手,不明白我做错了什么。
感谢您的任何建议。
您 未 将行插入 table,有 2 个原因。
- 触发器作为插入语句的一部分运行
完全的。所以该行不存在。
- 您指定了 "PRAGMA autonomous_transaction"(又名创建
untraceable bug here statement), 你之前有没有得到一个变异
table 异常。所以你看不到任何数据inserted/updated/deleted
由当前 transaction.Further 如果确实发生错误,该行仍将被插入,因为您没有引发错误或重新引发现有错误。我建议你熟悉一下PLSQL block structure。现在你可能想试试:
您可以使用后语句触发器或复合触发器的后语句部分进行此测试,执行 raise_application_error if sum > 100;
顺便说一句,您的 "if on sum_var > 100" 仅在发生错误时运行。该块的 "EXCEPTION" 之后和 END 之前的任何内容仅在发生错误时运行。
create or replace trigger elem_in_planet_check
after insert or update on elem_in_planet
declare
error_detected boolean := False;
begin
for planet in
(
select id_planet, sum_var
from (select id_planet, sum(percent_representation) sum_var
from elem_in_planet
group by id_planet
)
where sum_var > 100
)
loop
dbms_output.put_line('Planet ' || planet.id_planet || ' at '|| planet.sum_var || '% resources exceed 100%');
error_detected:= True;
end loop;
if error_detected then
Raise_application_error('-20001', 'Planet resources cannot exceed 100%');
end if;
end elem_in_planet_check;
我有以下 table 描述每个行星由哪些化学元素组成的百分比。
CREATE TABLE elem_in_planet
(
id_planet INTEGER,
element_symbol CHAR(2),
percent_representation NUMBER CONSTRAINT NN_elem_in_planet NOT NULL,
CONSTRAINT PK_elem_in_planet PRIMARY KEY (id_planet, element_symbol),
CONSTRAINT FK_planet_has_elem FOREIGN KEY (id_planet) REFERENCES planet (id_planet),
CONSTRAINT FK_elem_in_planet FOREIGN KEY (element_symbol) REFERENCES chemical_element (element_symbol)
);
我正在尝试制作一个触发器,当用户向行星添加新元素并且该行星中的元素总和超过 100% 时会警告用户。我想到了这个。
CREATE OR REPLACE TRIGGER elem_in_planet_check
AFTER INSERT OR UPDATE ON elem_in_planet
FOR EACH ROW
DECLARE
sum_var NUMBER;
PRAGMA autonomous_transaction;
BEGIN
SELECT SUM(percent_representation)
INTO sum_var
FROM elem_in_planet
WHERE id_planet = :NEW.id_planet
GROUP BY id_planet;
EXCEPTION
WHEN NO_DATA_FOUND THEN
sum_var := 0;
IF sum_var > 100 THEN
DBMS_OUTPUT.put_line('WARNING: Blah blah.');
END IF;
END;
/
此代码似乎每次都会抛出 NO_DATA_FOUND 异常,即使我插入了测试数据并且当我 运行 单独 SQL 查询时,它仍按预期工作。
我是新手,不明白我做错了什么。
感谢您的任何建议。
您 未 将行插入 table,有 2 个原因。
- 触发器作为插入语句的一部分运行 完全的。所以该行不存在。
- 您指定了 "PRAGMA autonomous_transaction"(又名创建 untraceable bug here statement), 你之前有没有得到一个变异 table 异常。所以你看不到任何数据inserted/updated/deleted 由当前 transaction.Further 如果确实发生错误,该行仍将被插入,因为您没有引发错误或重新引发现有错误。我建议你熟悉一下PLSQL block structure。现在你可能想试试:
您可以使用后语句触发器或复合触发器的后语句部分进行此测试,执行 raise_application_error if sum > 100;
顺便说一句,您的 "if on sum_var > 100" 仅在发生错误时运行。该块的 "EXCEPTION" 之后和 END 之前的任何内容仅在发生错误时运行。
create or replace trigger elem_in_planet_check
after insert or update on elem_in_planet
declare
error_detected boolean := False;
begin
for planet in
(
select id_planet, sum_var
from (select id_planet, sum(percent_representation) sum_var
from elem_in_planet
group by id_planet
)
where sum_var > 100
)
loop
dbms_output.put_line('Planet ' || planet.id_planet || ' at '|| planet.sum_var || '% resources exceed 100%');
error_detected:= True;
end loop;
if error_detected then
Raise_application_error('-20001', 'Planet resources cannot exceed 100%');
end if;
end elem_in_planet_check;