【问题标题】:Handling ORA-01403: no data found with exception in trigger处理 ORA-01403: 在触发器中找不到异常数据
【发布时间】:2021-06-19 06:06:48
【问题描述】:

我有两张桌子:

CREATE TABLE Patient
(
    p_Name  VARCHAR2(20) NOT NULL,
    p_Surname VARCHAR2(20) NOT NULL,
    idP     INTEGER,
    b_Date  DATE NOT NULL,
    d_Date  DATE DEFAULT NULL,
 
    CONSTRAINT PK_idP PRIMARY KEY(idP)
);

CREATE TABLE Visit 
(
    idV   INTEGER,
    date_V  DATE NOT NULL,
    v_Hospital INTEGER NOT NULL,
    id_PV   INTEGER,

    CONSTRAINT PK_idV PRIMARY KEY(idV),
    CONSTRAINT FK_idPV FOREIGN KEY(id_PV) REFERENCES Patient(idp)
        ON DELETE CASCADE,
    CONSTRAINT FK_idHV FOREIGN KEY(v_Hospital) REFERENCES Hospital(idH)
        ON DELETE CASCADE
);

我创建了一个触发器,以便当我在表中插入一行时,如果患者已故(当然),它不应该允许我这样做,这就是它背后的逻辑。

CREATE OR REPLACE TRIGGER visitDeceased
BEFORE INSERT ON Visit
FOR EACH ROW
DECLARE
    pd Patient.d_date%TYPE;
BEGIN
    SELECT P.d_date INTO pd
    FROM Patient P JOIN Visit V ON P.idP=:NEW.id_PV;
EXCEPTION 
    WHEN NO_DATA_FOUND THEN  
        INSERT INTO Visit(date_V,v_Hospital,id_PV) VALUES(:NEW.date_V,:NEW.v_Hospital,:NEW.id_PV);
    WHEN OTHERS THEN
        RAISE_APPLICATION_ERROR(-20111,'Error. Patient deceased.'); 
END;
/

问题是当 d_date 为 NULL 时,代码会产生 ORA-01403: no data found 错误。我正在尝试处理该异常但不起作用。有人知道如何使它工作吗?非常感谢。

【问题讨论】:

  • 您识别已故患者的标准是什么?
  • 我更新了 Patient 表,在 d_date 属性中插入了一个日期(d 代表死亡)。

标签: sql oracle exception oracle11g triggers


【解决方案1】:

如果您希望一行匹配并且可以使用 NULL 值来处理不匹配,那么我发现聚合很方便:

SELECT MAX(P.d_date) INTO pd
FROM Patient P JOIN
     Visit V
     ON P.idP = :NEW.id_PV;

但是,在您的代码中,我只会使用 INSERT . . . SELECT:

INSERT INTO Visit (date_V, v_Hospital, id_PV) V. 
    SELECT :NEW.date_V, :NEW.v_Hospital, :NEW.id_PV
    FROM dual
    WHERE NOT EXISTS (SELECT 1
                      FROM Patient p
                      WHERE p.idP = :NEW.id_PV
                     );

出于法律原因,您可能必须从Patient 中删除已故患者。但是,如果这不是必需的,我建议使用标志或deceased_date

另外,这个问题可以通过外键约束来避免。这将验证关系完整性,而无需依赖触发器。

【讨论】:

    【解决方案2】:

    希望,我正确理解了您的问题。

    NO_DATA_FOUNDSELECT P.d_date INTO pd FROM Patient P JOIN Visit V ON P.idP=:NEW.id_PV; 不返回任何行时处理异常。当此查询存在行时,它不处理,但是,d_date 为空。根据您的表结构d_Date DATE DEFAULT NULL,这是可能的。您可以通过以下方式处理:

    *检查pd 是否在您的select 查询后为空。 例如:

    IF pd IS NULL THEN    
    -- do your work 
    END IF;
    

    OR

    *在下面的查询中添加支票where P.d_date is not null

    SELECT P.d_date INTO pd FROM Patient P JOIN Visit V ON P.idP=:NEW.id_PV where P.d_date is not null;

    【讨论】:

      【解决方案3】:

      当您在 VISIT 表上的 insert 语句上运行触发器时,为什么要在其中使用 Insert 语句?只需删除您的 Insert 语句,然后它应该可以工作 -

      CREATE OR REPLACE TRIGGER visitDeceased
      BEFORE INSERT ON Visit
      FOR EACH ROW
      DECLARE
          pd Patient.d_date%TYPE;
      BEGIN
          SELECT P.d_date INTO pd
          FROM Patient P JOIN Visit V ON P.idP=:NEW.id_PV;
      EXCEPTION
          WHEN OTHERS THEN
              RAISE_APPLICATION_ERROR(-20111,'Error. Patient deceased.'); 
      END;
      /
      

      Link.

      【讨论】:

      • 如果我这样做,无论患者是否活着,它都会显示 RAISE_APPLICATION_ERROR。
      猜你喜欢
      • 2017-06-16
      • 2015-01-23
      • 2021-04-08
      • 1970-01-01
      • 2011-11-06
      • 2019-10-22
      • 1970-01-01
      • 1970-01-01
      • 2022-01-19
      相关资源
      最近更新 更多