【问题标题】:Add/Update stored procedure in Oracle, inserting a null or empty field在 Oracle 中添加/更新存储过程,插入 null 或空字段
【发布时间】:2012-06-03 05:30:27
【问题描述】:

我是使用 Oracle 的新手,我正在尝试为表创建添加/插入存储过程。我的表中的 PROD_CD 和 PLAN_CD 字段可以没有值(空或 null) 你能检查我的代码并告诉我我做错了什么吗?

表定义:

CREATE TABLE DCWEB.USER_PLAN_PREFERENCE
(
  USERID        VARCHAR2(40) NOT NULL,
  PROD_CD       VARCHAR2(9)  NULL,
  PLAN_CD       VARCHAR2(9)  NULL,
  STATE_LST     VARCHAR2(2)  NOT NULL,
  STATE_NM      VARCHAR2(40) NOT NULL,
  LST_UPDATE_TS TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP NOT NULL
);

ALTER TABLE DCWEB.USER_PLAN_PREFERENCE
  ADD CONSTRAINT USER_PLAN_PREFERENCE_XPK PRIMARY KEY (USERID, PROD_CD, PLAN_CD);

-- Grant/Revoke object privileges 
grant select, insert, update, delete on DCWEB.USER_PLAN_PREFERENCE to HIGGIB1;

存储过程定义:

  procedure setUserPlanPref (
    userid in varchar2,
    prod_cd in varchar2,
    plan_cd in varchar2,
    state_lst in varchar2,
    state_nm in varchar2
  )
  is
    currentTimestamp timestamp := current_timestamp;
  begin
       insert into user_plan_preference (userid, prod_cd, plan_cd, state_lst, state_nm, lst_update_ts)
       values (upper(userid), upper(prod_cd), upper(plan_cd), upper(state_lst), upper(state_nm), currentTimestamp);
       commit;
       exception
       when dup_val_on_index then
         begin
          update user_plan_preference up set
            up.userid = upper(userid),
            up.prod_cd = upper(prod_cd),
            up.plan_cd = upper(plan_cd),
            up.state_lst = upper(state_lst),
            up.state_nm = upper(state_nm),
            up.lst_update_ts = currentTimestamp
          where up.userid = upper(userid)
                and up.prod_cd = upper(prod_cd)
                and up.plan_cd = upper(plan_cd);
          commit;
          exception 
          when others then
            rollback;
        end;
      when others then
        rollback;
    end;
  end;

输入数据

我无法插入一条记录调用存储过程的值: DCWEB4578, , 2P, CA, 加利福尼亚 但是当我更改为字符串“NULL”时,插入成功。 当我尝试调用存储过程来更新插入的记录时 价值观: DCWEB4578,“NULL”,2P,科罗拉多州,科罗拉多州 更新没有发生,因为我仍然在表中看到原始记录。

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    您的直接问题是,如果您在主键中包含PROD_CDPLAN_CD,主键约束将要求两列都是NOT NULL。您可以在这些列中允许 NULL 值,也可以将它们包含在主键中,但不能同时包含两者。

    如果您的异常处理程序没有被编写为吞下异常,您会更清楚这一点。当你编写这样的代码时,几乎总是一个等待发生的错误

    when others then
      rollback;
    end;
    

    如果您要使用when others 异常处理程序,您几乎总是希望至少重新引发异常。

    when others then
      rollback;
      raise;
    end;
    

    否则,调用者不知道发生了错误,也不知道错误是什么。如果你重新提出异常,你会看到类似

    ORA-01400: cannot insert NULL into ("DCWEB"."USER_PLAN_PREFERENCE"."PROD_CD")
    

    这至少会为您指明正确的方向,并且会给您一些可以在此处发布的内容。

    此外,声明与表中的列同名的参数是另一个等待发生的错误。您真的想采用某种约定来区分参数名称和列名称。就个人而言,我在参数名称前加上p_,即p_userid in varchar2,。否则,您的代码几乎肯定不会达到您的预期。

    由于在执行 SQL 语句时列名优先于局部变量,因此您的 UPDATE 语句将 upper(userid)upper(prod_cd) 等解析为 USER_PLAN_PREFERENCE 表中的列而不是已解析的参数传入。假设您的数据始终为大写,此UPDATE 语句将更新USER_PLAN_PREFERENCE 的每一行,而不仅仅是您希望更新的一行,它会将每一行的LST_UPDATE_TS 设置为currentTimestamp

     update user_plan_preference up 
        set up.userid = upper(userid),
            up.prod_cd = upper(prod_cd),
            up.plan_cd = upper(plan_cd),
            up.state_lst = upper(state_lst),
            up.state_nm = upper(state_nm),
            up.lst_update_ts = currentTimestamp
      where up.userid = upper(userid)
        and up.prod_cd = upper(prod_cd)
        and up.plan_cd = upper(plan_cd);
    

    如果您的命名约定区分列名和参数名,那么当您打算使用参数或局部变量名时,无意中使用列名会困难得多。

    【讨论】:

    • 贾斯汀。感谢您的信息 - 非常有帮助。该表现在允许在 PROD_CD 和 PLAN_CD 中为空,并且我从主键中删除了这些字段。我还遵循了您在参数名称前加上 p_ 的建议。剩下的唯一问题是插入成功,值为: DCWEB4578, , 1P, CO, COLORODO 当我第二次使用参数调用 setUserPlanPref 时: DCWEB4578, , 1P, CA, CALIFORNIA 表没有更新。有什么进一步的建议吗?再次感谢。
    • 在我的表定义中:PROD_CD VARCHAR2(9),PLAN_CD VARCHAR2(9),我也试过:PROD_CD VARCHAR2(9) NULL,PLAN_CD VARCHAR2(9) NULL,我唯一的方法能够进行行更新是当我使用字符串“NULL”作为 PROD_CD 的输入值而不是将其留空/空时。
    • @user1433167 - 假设USERID 现在是表的主键,问题是如果up.prod_cdp_prod_cd 是@,则谓词up.prod_cd = upper(p_prod_cd) 不会为真987654344@。 NULL 值永远不会彼此相等(它们也永远不会彼此不相等)。您需要使用NVL 或明确检查NULL,即(up.prod_cd = upper(p_prod_cd) or (up.prod_cd is null and p_prod_cd is null)NVL(up.prod_cd, 'NULL') = nvl(upper(p_prod_cd),'NULL')
    【解决方案2】:

    问题来了

    如果您希望 col 不接受 null 值,请将其定义为 NOT NULL 反之亦然

    CREATE TABLE DCWEB.USER_PLAN_PREFERENCE
    (
      USERID        VARCHAR2(40) NOT NULL,
      PROD_CD       VARCHAR2(9)  NULL,--**this should be NOT NULL** 
      PLAN_CD       VARCHAR2(9)  NULL,--**this should be NOT NULL** 
      STATE_LST     VARCHAR2(2)  NOT NULL,
      STATE_NM      VARCHAR2(40) NOT NULL,
      LST_UPDATE_TS TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP NOT NULL
    );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-04
      • 2021-09-07
      • 2010-12-22
      • 1970-01-01
      • 2021-07-30
      • 2017-12-02
      相关资源
      最近更新 更多