Oracle - Fetch返回超过请求的行数 - 使用触发器

时间:2017-11-20 22:27:10

标签: oracle plsql

所以我试图使用触发器基本上设置一些规则..如果任何人的身份证号码低于3,他将只需支付100美元,但如果某人的身份证号码高于此值,他将不得不支付更多。我做了一些研究,并被告知使用触发器,并且在获取多行时触发器非常有用。所以我尝试过这样做,但它没有奏效。基本上触发器被创建但是当我尝试添加值时,我收到以下错误: -

ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "S.PRICTICKET", line 6
ORA-04088: error during execution of trigger 'S.PRICTICKET'

这是我做触发器所做的: -

CREATE OR REPLACE TRIGGER PRICTICKET BEFORE INSERT OR UPDATE OR DELETE ON PAYS FOR EACH ROW ENABLE
DECLARE 
V_PRICE PAYS.PRICE%TYPE;
V_ID PAYS.ID%TYPE;
V_NAME PAYS.NAME%TYPE;
BEGIN
SELECT ID,NAME INTO V_ID,V_NAME FROM PAYS;
IF INSERTING AND V_ID<3 THEN
V_PRICE:=100;
INSERT INTO PAYS(ID,NAME,PRICE) VALUES (V_ID,V_NAME,V_PRICE);
ELSIF INSERTING AND V_ID>=3 THEN
V_PRICE:=130;
INSERT INTO PAYS(ID,NAME,PRICE) VALUES (V_ID,V_NAME,V_PRICE);
END IF;
END;

事情是,当我执行这段代码时,我确实得到一条消息说已经编译了触发器。但是当我尝试使用以下代码将值插入表中时,我收到上面提到的错误消息。

INSERT INTO PAYS(ID,NAME) VALUES (19,'SS');

2 个答案:

答案 0 :(得分:1)

您收到了指定的错误ORA-01422,因为您使用以下SELECT返回了多行:

SELECT ID,NAME INTO V_ID,V_NAME FROM PAYS;

您需要限制结果集。例如,我将使用:NEW psuedorecord来获取行的新ID值,如果唯一,则会将SELECT限制为一行:

SELECT ID,NAME INTO V_ID,V_NAME FROM PAYS WHERE ID = :NEW.ID;

以下是有关使用触发器的Oracle文档:https://docs.oracle.com/database/121/TDDDG/tdddg_triggers.htm#TDDDG99934

但是,我认为您的触发器还有其他问题,请参阅我的评论,我们可以讨论。

编辑:根据我们的讨论。

  

ORA-04088:执行触发器时出错

在同一个表的INSERT触发器中使用BEFORE INSERT将创建一个无限循环。请考虑使用AFTER INSERT并将INSERTS更改为UPDATESINSTEAD OF INSERT

此外,从触发器定义中删除DELETE。在这种情况下,这没有任何意义。

答案 1 :(得分:1)

让我们开始清理一些事情。你被告知&#34;触发器在获取多行时非常有用&#34;这是一般规则,没有额外的背景,是错误的。有4种类型的DML触发器: 语句之前 - 无论处理的行数是多少,都会为语句触发1次。 行前 - 在语句中处理的每一行触发一次,然后将旧值和新值合并为一组值。此时,您可以更改列中的值。 行后 - 在将旧值和新值合并为一组值后,在语句中处理的行触发一次。此时,您无法更改列值。 语句后 - 无论处理的行数是多少,都会为语句触发一次。

请记住,触发器实际上是声明的一部分。

可以为插入,更新或删除触发触发器。但是,没有必要对每个人开火。在这种情况下,建议删除删除。但是更新作为你的触发器没有做任何事情。 (注意:有复合触发器,但它们包含上述每一个的段)。

通常,触发器无法引用触发它的表。请参阅错误ORA-04091。

如果您在插入时触发了触发器无法在同一个表中插入(也请参阅ORA-04091),即使您绕过该插入会触发触发器,创建一个递归的,也许是一个永无止境的循环 - 这将在这里发生。

使用:新建。 column_name 和:旧。 column_name 以适当引用列值。不要试图选择它们。

由于您试图确定列的值,因此必须使用Before触发器。

因此将此应用于您的触发器,结果将变为:

CREATE OR REPLACE TRIGGER PRICTICKET 
    BEFORE INSERT ON PAYS 
    FOR EACH ROW ENABLE
BEGIN

    if :new.id is not null
       if :new.ID<3 then
          :new.Price :=100;
       else 
          :new.Price := 130;
       end if ;
    else
       null; -- what should happen here? 
    end if ; 
END PRICTICKET ;