PL/SQL:我的程序工作正常,但不是我的例外?

Posted

技术标签:

【中文标题】PL/SQL:我的程序工作正常,但不是我的例外?【英文标题】:PL/SQL : My procedure works fine but not my exceptions? 【发布时间】:2017-08-13 20:53:09 【问题描述】:

我正在处理的软件包有一些问题。我正在使用 sqldeveloper,我用 PL/SQL 编写。

程序"Ajouter"应该添加一个游泳者,你必须指定名字,姓氏等。当我尝试它并提供正确的信息时,它运行良好。

但是当我尝试测试我的异常时,它不起作用。我的任何例外都不起作用。例如,如果我尝试在 sexe 中写 "Z",它不会告诉我 "Sex has to be F or M"。它只告诉我"Procédure PL/SQL terminée.",类似于"PL / SQL procedure completed."

问题出在哪里?我怎样才能解决这个问题并使我的异常工作?

这是“Ajouter”(添加)代码:

PROCEDURE Ajouter(Nageur Nageurs%ROWTYPE) AS
    ExcNull EXCEPTION;
    PRAGMA EXCEPTION_INIT(ExcNull, -1400);
    ExcPK EXCEPTION;
    PRAGMA EXCEPTION_INIT(ExcPK, -00001);
    ExcFK EXCEPTION;
    PRAGMA EXCEPTION_INIT(ExcFK, -2291);
    ExcCheck EXCEPTION;
    PRAGMA EXCEPTION_INIT(ExcCheck, -2290);
BEGIN
    INSERT INTO Nageurs values (Nageur.NRLIGUE, Nageur.NOM, Nageur.PRENOM,
    Nageur.ANNEENAISS, Nageur.SEXE, Nageur.CATEGORIE, Nageur.CLUB, Nageur.ADRESSE,
    Nageur.CODEPOSTAL, Nageur.LOCALITE, Nageur.NRTELEPHONE, Nageur.EMAIL, Nageur.GSM, Nageur.COTISATION);

    COMMIT;

    DBMS_OUTPUT.PUT_LINE('Nageur ajouté');
EXCEPTION
    WHEN ExcNull THEN
    IF(INSTR(SQLERRM, 'EveNomNotNull') <> 0) THEN DBMS_OUTPUT.PUT_LINE('Le nom ne peut pas être null.');
    ELSIF (INSTR(SQLERRM, 'EvePrenomNotNull') <> 0) THEN DBMS_OUTPUT.PUT_LINE('Le prenom ne peut pas être null.');
    ELSIF (INSTR(SQLERRM, 'EveNaissanceNotNull') <> 0) THEN DBMS_OUTPUT.PUT_LINE('L''annee ne peut pas être null.');
    ELSIF (INSTR(SQLERRM, 'EveSexeNotNull') <> 0) THEN DBMS_OUTPUT.PUT_LINE('Le sexe ne peut pas être null.');
    END IF;

    WHEN ExcPK THEN 
    IF(INSTR(SQLERRM, 'EveCpNageurs') <> 0) THEN DBMS_OUTPUT.PUT_LINE('Le nageur existe deja.');
    ELSIF (INSTR(SQLERRM, 'EveUnicite') <> 0) THEN DBMS_OUTPUT.PUT_LINE('Le prénom et le nom doivent etre uniques.');
    END IF;

    WHEN ExcFK THEN
    IF(INSTR(SQLERRM, 'EveRefNageursCat') <> 0) THEN DBMS_OUTPUT.PUT_LINE('La categorie n''existe pas');
    ELSIF (INSTR(SQLERRM, 'EveRefNageursClubs') <> 0) THEN DBMS_OUTPUT.PUT_LINE('Le club n''existe pas');
    ELSIF (INSTR(SQLERRM, 'EveRefNageursCP') <> 0) THEN DBMS_OUTPUT.PUT_LINE('Le code postal n''existe pas.');
    END IF;

    WHEN ExcCheck THEN
    IF(INSTR(SQLERRM, 'EveSexe') <> 0) THEN DBMS_OUTPUT.PUT_LINE('Le sexe doit être F ou M');
    ELSIF (INSTR(SQLERRM, 'EveCotisation') <> 0) THEN DBMS_OUTPUT.PUT_LINE('La cotisation doit être O ou N');
    END IF;

    WHEN TOO_MANY_ROWS THEN DBMS_OUTPUT.PUT_LINE('Exception : Trop de données.');
    WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('Pas de données.');
    WHEN OTHERS THEN RAISE;
END;

这是 Nageur(游泳运动员)的桌子:

CREATE TABLE Nageurs
(NrLigue CHAR(14)
     CONSTRAINT EveCpNageurs PRIMARY KEY,
Nom VARCHAR2(20) 
     CONSTRAINT EveNomNotNull NOT NULL,
Prenom VARCHAR2(20) 
   CONSTRAINT EvePrenomNotNull NOT NULL,
AnneeNaiss NUMBER(4) 
    CONSTRAINT EveNaissanceNotNull NOT NULL,
Sexe CHAR(1) 
  CONSTRAINT EveSexeNotNull NOT NULL
  CONSTRAINT EveSexe CHECK (Sexe in ('F','M')),
Categorie CHAR(2)
  CONSTRAINT EveRefNageursCat  REFERENCES Categories(Categorie),Club CHAR(5)
  CONSTRAINT EveRefNageursClubs  REFERENCES Clubs (Club),
 Adresse VARCHAR2(50),
 CodePostal CHAR(5)
        CONSTRAINT EveRefNageursCP REFERENCES CodePostaux (CodePostal),
 Localite VARCHAR2(20),
 NrTelephone CHAR(15),
 EMAIL VARCHAR2(50),
 GSM CHAR(15),
 Cotisation CHAR(1)
    CONSTRAINT EveCotisation CHECK (Cotisation in ('O','N')),
CONSTRAINT EveUnicite UNIQUE (Nom, Prenom)
);

这是一个不起作用的测试示例:

DECLARE
  nag nageurs%rowtype;
BEGIN
  nag.nrligue := '01/000325/CCM';
  nag.nom := 'DISNEY';
  nag.prenom := 'WALTER';
  nag.anneenaiss := '1901';
  nag.sexe := 'Z';
  nag.club := 'CCM';
  EveGestionNageursMasters.Ajouter(nag);
END ;

【问题讨论】:

看看raise_application_error。另外,don't use char. 很可能,您没有打开输出 - 例如“set serveroutput on”(或者,如果您使用的是像 Toad 或 PL/SQL Developer 这样的 GUI,那么您没有找到正确的位置)。然而,这是一种处理异常的*可怕*方式——不要将消息输出到不会被看到的东西;而是使用 raise 或 raise_application_error 来专门停止过程的执行并将错误消息传递回调用过程。更安全。 感谢您的 cmets,我已经设置了“SET serveroutput ON size unlimited;”在我的包裹的开头,对不起,我应该提到它。我要看看 raise_application_error。 :) 【参考方案1】:

当您在 Oracle 中这样命名对象时,不带分隔符:

CONSTRAINT EveNomNotNull NOT NULL

实际的约束名不区分大小写,所以错误信息中的约束名会报为:

EVENOMNOTNULL

您可以通过运行如下查询来检查:

select constraint_name from all_constraints where table_name = 'NAGEURS';

这就是为什么使用INSTR 的以下条件不会检测到约束名称:

IF(INSTR(SQLERRM, 'EveNomNotNull') <> 0) THEN

由于 INSTR 进行区分大小写的搜索,您必须确保它与数据库中创建的约束名称匹配,例如:

IF(INSTR(SQLERRM, 'EVENOMNOTNULL') <> 0) THEN

【讨论】:

非常感谢!我从没想过我的问题来自那里。现在效果好多了!【参考方案2】:

我建议在每个异常处理程序中在 IF 语句之前添加 dbms_output.put_line 语句,以准确查看 SQLERRM 的文本。

您的异常处理程序打印消息但不传播异常。也许您想在每个异常处理程序的末尾添加一个RAISE; 以将异常传播回调用者,如下所示。

EXCEPTION
  WHEN ExcNull THEN
    dbms_output.put_line(SQLERRM);
    IF(INSTR(SQLERRM, 'EveNomNotNull') <> 0) THEN 
      DBMS_OUTPUT.PUT_LINE('Le nom ne peut pas être null.');
    ELSIF (INSTR(SQLERRM, 'EvePrenomNotNull') <> 0) THEN
      DBMS_OUTPUT.PUT_LINE('Le prenom ne peut pas être null.');
    ELSIF (INSTR(SQLERRM, 'EveNaissanceNotNull') <> 0) THEN 
      DBMS_OUTPUT.PUT_LINE('L''annee ne peut pas être null.');
    ELSIF (INSTR(SQLERRM, 'EveSexeNotNull') <> 0) THEN 
      DBMS_OUTPUT.PUT_LINE('Le sexe ne peut pas être null.');
    END IF;
    RAISE;
  WHEN ExcPK THEN 
    dbms_output.put_line(SQLERRM);
    IF(INSTR(SQLERRM, 'EveCpNageurs') <> 0) THEN 
      DBMS_OUTPUT.PUT_LINE('Le nageur existe deja.');
    ELSIF (INSTR(SQLERRM, 'EveUnicite') <> 0) THEN 
      DBMS_OUTPUT.PUT_LINE('Le prénom et le nom doivent etre uniques.');
    END IF;
    RAISE;
  WHEN ExcFK THEN
    dbms_output.put_line(SQLERRM);
    IF(INSTR(SQLERRM, 'EveRefNageursCat') <> 0) THEN 
      DBMS_OUTPUT.PUT_LINE('La categorie n''existe pas');
    ELSIF (INSTR(SQLERRM, 'EveRefNageursClubs') <> 0) THEN 
      DBMS_OUTPUT.PUT_LINE('Le club n''existe pas');
    ELSIF (INSTR(SQLERRM, 'EveRefNageursCP') <> 0) THEN 
      DBMS_OUTPUT.PUT_LINE('Le code postal n''existe pas.');
    END IF;
    RAISE;
  WHEN ExcCheck THEN
    dbms_output.put_line(SQLERRM);
    IF(INSTR(SQLERRM, 'EveSexe') <> 0) THEN 
      DBMS_OUTPUT.PUT_LINE('Le sexe doit être F ou M');
    ELSIF (INSTR(SQLERRM, 'EveCotisation') <> 0) THEN 
      DBMS_OUTPUT.PUT_LINE('La cotisation doit être O ou N');
    END IF;
    RAISE;
  WHEN TOO_MANY_ROWS THEN 
    DBMS_OUTPUT.PUT_LINE('Exception : Trop de données.');
    RAISE;
  WHEN NO_DATA_FOUND THEN 
    DBMS_OUTPUT.PUT_LINE('Pas de données.');
    RAISE;
  WHEN OTHERS THEN 
    RAISE;
END;

【讨论】:

感谢您的评论柯比! 我尝试了您的第一个提议,这就是我得到的结果:“ORA-02290:违反检查约束 (EVEPACKAGES.EVESEXE)” 似乎我的例外情况有效,但文本未显示。我不知道应该把我的 RAISE 放在哪里;确切地说,你能给我举个例子吗? (我尝试将它放在 ENDIF 之前,但它似乎不是正确的位置。)我还是初学者,感谢您的耐心等待。 :) 初学者不丢脸;我们曾经都是初学者。 :-) 我建议提出 RAISE;每个 IF 语句之后的语句。我会用代码更新我的答案。 为确保您看到文本,在 SQLDeveloper 中转到视图菜单并选择 DBMS 输出。这将为您提供一个窗口,然后您需要单击绿色 + 按钮并选择您将运行它的连接。 @Kirby:感谢您的帮助!我把 RAISE;在正确的位置,这就是我得到的: Rapport d'erreur - ORA-02290:检查约束 (EVEPACKAGES.EVESEXE) 违反 ORA-06512:在“EVEPACKAGES.EVEGESTIONNAGEURSMASTERS”,第 61 行 ORA-06512:在第 10 行 02290.00000 - “违反检查约束 (%s.%s)” *原因:插入的值不满足命名检查 *操作:不要插入违反约束的值。它运作良好,但文本仍然没有显示,我仍然不明白为什么...... T_T Shaun Peterson:感谢您的建议。 :)

以上是关于PL/SQL:我的程序工作正常,但不是我的例外?的主要内容,如果未能解决你的问题,请参考以下文章

我的 PL/SQL 过程异常似乎不起作用

如何从替换过程(PL/SQL)中获取旧代码?

我的 VB.Net 代码中出现 PL SQL 错误,但无法在 SQL Developer 中重现

为啥这个 PL/SQL 过程不起作用?

关于pl/sql打开后database为空的问题解决办法

Oracle PL SQL 从 SQL Dev 工作。但不是来自代码