Oracle 插入触发器ORA-01422后:fetch返回的行数超过请求的行数

Oracle 插入触发器ORA-01422后:fetch返回的行数超过请求的行数,oracle,plsql,sqlplus,database-trigger,Oracle,Plsql,Sqlplus,Database Trigger,有人能帮我写下面的代码吗。共有3个表:客户表、预订表和发票表。我正在编写一个触发器,它将在每次进行新预订时执行 触发器将预加载发票表中的发票id(库存id)、预订id(库存id)、客户姓名(客户名称)、客户姓氏(客户名称)和预订开始日期信息 我的代码如下。创建触发器时没有编译错误。然而,当我向Reservation表插入一个新行以执行触发器时,它会通知我触发器有一个错误 ORA-01422:fetch返回的行数超过请求的行数 注意:我已经在互联网上找到了解决方案,但没有雪茄。人们说问题主要来自返

有人能帮我写下面的代码吗。共有3个表:客户表、预订表和发票表。我正在编写一个触发器,它将在每次进行新预订时执行

触发器将预加载发票表中的发票id(库存id)、预订id(库存id)、客户姓名(客户名称)、客户姓氏(客户名称)和预订开始日期信息

我的代码如下。创建触发器时没有编译错误。然而,当我向Reservation表插入一个新行以执行触发器时,它会通知我触发器有一个错误

ORA-01422:fetch返回的行数超过请求的行数


注意:我已经在互联网上找到了解决方案,但没有雪茄。人们说问题主要来自返回多行的Select语句。但是,上面代码中的Select查询只返回一行。我还检查了表的数据,3个表Customer_A1、Reservation_A1和Invoice_A1中没有违反实体和引用完整性。我甚至将代码复制到一个单独的测试过程中,以便在读取输入后打印出所有变量。测试程序运行良好。我现在投降。请帮我解决这个问题。我是新来的。谢谢

问题在声明中

Select CUSTOMER_A1.cust_fname,CUSTOMER_A1.cust_lname INTO 
cust_fname,cust_lname 
FROM CUSTOMER_A1 
WHERE CUSTOMER_A1.cust_id=cust_id;
您的意思可能是“从CUSTOMER_A1查找数据,其中CUSTOMER_A1.cust_id=变量'cust_id'的值”。不幸的是,这不是它的解释。数据库将其读取为“Find data from CUSTOMER_A1 where CUSTOMER_A1.cust_id=CUSTOMER_A1.cust_id”-换句话说,它将每行的
cust_id
字段与自身进行比较,发现它们相等(空值除外),并从该行返回数据

编写PL/SQL时要记住的一条好规则是“永远不要给变量指定与要操作的列相同的名称”。考虑到这一点,你可能会考虑将你的触发器重写为:

CREATE OR REPLACE TRIGGER invoice_after_reservation_made
  AFTER INSERT
  ON RESERVATION_A1
  FOR EACH ROW
DECLARE
  vInv_id INVOICE_A1.INV_ID%type;
  vRes_id INVOICE_A1.res_id%type;
  vRoom_id INVOICE_A1.room_id%type;
  vCust_fname INVOICE_A1.cust_fname%type;
  vCust_lname INVOICE_A1.cust_lname%type;
  vReservation_start_date INVOICE_A1.reservation_start_date%type;
  vCust_id RESERVATION_A1.cust_id%type;
BEGIN
  --read reservation_id
  vRes_id:= :new.res_id;

  --read room_id
  vRoom_id:= :new.room_id;

  --read reservation_start_date
  vReservation_start_date:= :new.reservation_start_date;

  --read customer_id
  vCust_id:= :new.cust_id;

  --create new invoice_id
  SELECT MAX(INVOICE_A1.inv_id)+1 INTO vInv_id FROM INVOICE_A1;

  -- import value from CUSTOMER_A1 table to variable cust_fname, cust_lname
  Select CUSTOMER_A1.cust_fname,CUSTOMER_A1.cust_lname
    INTO vCust_fname, vCust_lname 
    FROM CUSTOMER_A1 
    WHERE CUSTOMER_A1.cust_id=cust_id;

  -- Insert record into invoice table
  INSERT INTO INVOICE_A1
  VALUES (vInv_id, vRes_id, vRoom_id, vCust_fname, vCust_lname, null, 
          TO_DATE(TO_CHAR(reservation_start_date),'DD/MM/YYYY'), null);
END invoice_after_reservation_made;

非常感谢。那是个愚蠢的错误。我把它修好了。一点也不傻-你只是没看到它和电脑一样。:-)顺便说一下,不需要将
:新的
值复制到局部变量中。您可以直接使用
:new.res\u id
等并保存十几行代码。(或者,如果您确实需要局部变量,您可以将它们的值作为声明的一部分进行赋值,并且仍然可以保存六行代码。)此外,
从发票中选择MAX(INVOICE_A1.inv_id)+1到inv_id
将为同时运行它的两个会话提供相同的结果。
CREATE OR REPLACE TRIGGER invoice_after_reservation_made
  AFTER INSERT
  ON RESERVATION_A1
  FOR EACH ROW
DECLARE
  vInv_id INVOICE_A1.INV_ID%type;
  vRes_id INVOICE_A1.res_id%type;
  vRoom_id INVOICE_A1.room_id%type;
  vCust_fname INVOICE_A1.cust_fname%type;
  vCust_lname INVOICE_A1.cust_lname%type;
  vReservation_start_date INVOICE_A1.reservation_start_date%type;
  vCust_id RESERVATION_A1.cust_id%type;
BEGIN
  --read reservation_id
  vRes_id:= :new.res_id;

  --read room_id
  vRoom_id:= :new.room_id;

  --read reservation_start_date
  vReservation_start_date:= :new.reservation_start_date;

  --read customer_id
  vCust_id:= :new.cust_id;

  --create new invoice_id
  SELECT MAX(INVOICE_A1.inv_id)+1 INTO vInv_id FROM INVOICE_A1;

  -- import value from CUSTOMER_A1 table to variable cust_fname, cust_lname
  Select CUSTOMER_A1.cust_fname,CUSTOMER_A1.cust_lname
    INTO vCust_fname, vCust_lname 
    FROM CUSTOMER_A1 
    WHERE CUSTOMER_A1.cust_id=cust_id;

  -- Insert record into invoice table
  INSERT INTO INVOICE_A1
  VALUES (vInv_id, vRes_id, vRoom_id, vCust_fname, vCust_lname, null, 
          TO_DATE(TO_CHAR(reservation_start_date),'DD/MM/YYYY'), null);
END invoice_after_reservation_made;