3

我在 Oracle 中创建了一个存储过程。该过程编译成功,没有错误。该过程有 3 个更新查询,更新 3 个表“TBLHOTEL”、“TBLHOTELDETAIL”和“TBLHOTELFARE”。

在每个 Update 语句之后,变量successCnt1 递增以获取成功插入查询的数量。最后将successCnt1赋值给successCnt来存储最终结果。如果在任何查询中发生异常,则将其设置为 0 ,表示没有发生插入。

问题是没有异常发生,数据库也没有发生更新。

这是我的代码:

架构:

TBLHOTEL 架构: {DATE1 (DATE) , ACROOMS (NUMBER) , NACROOMS (NUMBER), HOTELID (VARCHAR2(10)) }

TBLHOTELFARE 模式: {HOTELID (VARCHAR2(10)), CLASS (VARCHAR2(5)), FARE (NUMBER)}

TBLHOTELDETAIL 模式: {HOTELID (VARCHAR2(10)) , PLACE (VARCHAR2(15)) , HOTELNAME (VARCHAR2(15)) }

程序:

CREATE OR REPLACE PROCEDURE TableUpdateByParameter (acrooms   in number,
                                           nacrooms  in number,
                                           date1      in date,
                                           hotelid   in varchar2,
                                           fare in number,
                                           place in varchar2,
                                           hotelname in varchar2,
                                           class in varchar2,
                                           successCnt  out number) IS

successCnt1 number(6) NOT NULL := 0;
rowUpdated1 number(6) NOT NULL := 0;
rowUpdated2 number(6) NOT NULL := 0;
rowUpdated3 number(6) NOT NULL := 0;

BEGIN
  SAVEPOINT before;

  UPDATE tblhotel
     SET acrooms = acrooms, nacrooms = nacrooms
   WHERE date1 = (to_date(date1, 'mm/dd/yyyy'))
     AND hotelid = 'hotelid' ;

rowUpdated1 := SQL%RowCount;
successCnt1 := successCnt1 + 1;

   dbms_output.put_line('Successful Insertion tblhotel. count ='||successCnt1);
   dbms_output.put_line('Successful Insertion tblhotel. Row Updated ='||rowUpdated1);

  UPDATE tblhoteldetail
 SET place = 'place', hotelname = 'hotelname'
   WHERE hotelid = 'hotelid' ;

rowUpdated2 := SQL%RowCount;
successCnt1 := successCnt1 + 1;

dbms_output.put_line('Successful Insertion tblhoteldetail. count ='||successCnt1);
dbms_output.put_line('Successful Insertion tblhoteldetail. Row Updated= '||rowUpdated2);

  UPDATE tblhotelfare
     SET fare = fare
   WHERE hotelid = 'hotelid' 
     AND class = 'class';

rowUpdated3 := SQL%RowCount;
successCnt1 := successCnt1 + 1;
successCnt := successCnt1;

 COMMIT;

 dbms_output.put_line('Successful Insertion tblhotelfare. count ='||successCnt);
dbms_output.put_line('Successful Insertion tblhotelfare. Row Updated= '||rowUpdated3);

EXCEPTION
  WHEN Others THEN
    successCnt1 := 0;
    successCnt := successCnt1;
    dbms_output.put_line('An error has occured. count ='||successCnt);

    ROLLBACK TO before;

END;

来电声明

DECLARE 
 C  number;

BEGIN

   TableUpdateByParameter (140,200,TO_DATE('03/24/2013','MM/DD/YYYY'),'H1',3000,'GANGTOK','TRIPTI','AC',C);
END;

数据库管理系统输出:

Successful Insertion tblhotel. count =1
Successful Insertion tblhotel. Row Updated =0
Successful Insertion tblhoteldetail. count =2
Successful Insertion tblhotel. Row Updated =0
Successful Insertion tblhotelfare. count =3
Successful Insertion tblhotel. Row Updated =0

请帮我找出问题所在。如果需要额外的信息,请告诉我。

4

3 回答 3

7

UPDATE语句正在运行,但更新了 0 行,如您的日志 ( Row Updated =0) 所示。这不是错误,您的更新评估 where 子句,找到 0 行匹配,并执行 0 修改。在 Oracle 中,与 where 子句中的任何行都不匹配的更新仍然是成功的。

现在为什么会这样。让我们进行第一次更新:

UPDATE tblhotel
   SET acrooms = acrooms, nacrooms = nacrooms
 WHERE date1 = (to_date(date1, 'mm/dd/yyyy'))
   AND hotelid = 'hotelid' ;

我认为您想更新具有hotelid作为参数传递的值的列的行。这样做有几个问题:

  • 首先,您不是在比较列和参数,而是比较具有常数的列。参数不使用引号。常量(VARCHAR2)可以。
  • 其次,您不应该调用与您的列同名的参数,这会导致混淆,甚至可能导致变量 shadowing。我建议使用在您的架构中没有任何列使用的前缀。参数的一个常见前缀是p_.
  • 最后,如果你的参数是好的类型,你就不需要转换函数(因为你的参数p_date1是日期类型,你不需要这个to_date函数)。

因此,如果您重命名参数p_hotelidp_date1,您的语句应为:

UPDATE tblhotel
   SET acrooms = acrooms, nacrooms = nacrooms
 WHERE date1 = p_date1
   AND hotelid = p_hotelid;

在这种情况下,不会出现混淆或转换错误。


在一个不相关的注释上:

  • 您的过程名称与其生成的日志之间似乎不匹配:更新语句永远不会进行插入。
  • 不要抓住when others,让错误传播。如果错误传播,PL/SQL将回滚过程更改。PL/SQL 语句(DML 和块)本质上是原子的,它们要么完全失败,要么完全成功
于 2013-03-28T13:36:32.543 回答
1

如果hotelid是数据库中的列,您几乎肯定不想重载名称以将其用作过程参数的名称。这样做会使在 SQL 语句中使用参数变得相当复杂。大多数人制定某种约定来区分两者。我更喜欢在参数名称前加上 a 前缀,p_这是一种相对常见的约定。

CREATE OR REPLACE PROCEDURE TableUpdateByParameter (p_acrooms   in number,
                                           p_nacrooms  in number,
                                           p_date1      in date,
                                           p_hotelid   in varchar2,
                                           p_fare in number,
                                           p_place in varchar2,
                                           p_hotelname in varchar2,
                                           p_class in varchar2,
                                           p_successCnt  out number) 
IS

您的 SQL 语句将变为

 WHERE tblhoteldetail.hotelid = p_hotelid

如果您真的想重载参数名称,则必须在参数名称前加上过程名称。但这通常会给你带来无尽的悲伤,因为你无意中编写了类似的代码

 WHERE tblhoteldetail.hotelid = hotelid

并无意中更新了表中的每一行。

于 2013-03-28T13:39:34.370 回答
0

您的每个where陈述都与此类似:

AND hotelid = 'hotelid'

这将每次将表上的hotelid 列与该字符串文字“hotelid”进行匹配,而不是传递给proc 的值。

要让他们引用您需要使用的参数,例如:

AND tblhotel.hotelid = TableUpdateByParameter.hotelid

其中左侧是表格上的列,右侧是您的 proc 参数。

另一种方法是有一个命名约定,所有参数都以“p”为前缀,以便您可以使用:

AND tblhotel.hotelid = photelid
于 2013-03-28T13:30:21.170 回答