Sql 在Oracle中添加/更新存储过程,插入null或空字段

Sql 在Oracle中添加/更新存储过程,插入null或空字段,sql,oracle,Sql,Oracle,我不熟悉使用Oracle,我正在尝试为表创建一个添加/插入存储过程。我的表中的PROD_CD和PLAN_CD字段不能有值(空或null) 你能检查一下我的代码,让我知道我做错了什么吗 表定义: 存储过程定义: 输入数据 我无法插入调用存储过程的记录,其值为: DCWEB4578,加利福尼亚州2P 但当我更改为字符串“NULL”时,插入成功。 当我尝试调用存储过程以更新插入的记录时 价值观: DCWEB4578,“空”,2P,CO,COLORODO 更新没有发生,因为我仍然在表中看到原始记录。问题

我不熟悉使用Oracle,我正在尝试为表创建一个添加/插入存储过程。我的表中的PROD_CD和PLAN_CD字段不能有值(空或null) 你能检查一下我的代码,让我知道我做错了什么吗

表定义: 存储过程定义: 输入数据 我无法插入调用存储过程的记录,其值为: DCWEB4578,加利福尼亚州2P 但当我更改为字符串“NULL”时,插入成功。 当我尝试调用存储过程以更新插入的记录时 价值观: DCWEB4578,“空”,2P,CO,COLORODO 更新没有发生,因为我仍然在表中看到原始记录。

问题就在这里

如果希望列不接受空值,则将其定义为非空 反之亦然

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
);

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

如果您的异常处理程序不是为吞咽异常而编写的,那么这对您来说会更清楚。当您编写类似这样的代码时,它几乎总是一个等待发生的bug

when others then
  rollback;
end;
如果您打算在其他人异常处理程序时使用一个,那么您几乎总是希望至少重新引发该异常

when others then
  rollback;
  raise;
end;
否则,调用方不知道发生了错误,也不知道错误是什么。如果你重新提出这个异常,你会看到

ORA-01400: cannot insert NULL into ("DCWEB"."USER_PLAN_PREFERENCE"."PROD_CD")
这至少为你指明了正确的方向,也会给你一些东西在这里发布

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

由于在执行SQL语句时列名优先于局部变量,因此
UPDATE
语句将
upper(userid)
upper(prod\u cd)
等解析为
用户计划首选项
表中的列,而不是已传入的参数。假设您的数据总是大写,此
UPDATE
语句将更新
USER\u PLAN\u PREFERENCE
的每一行,而不仅仅是您希望更新的一行,并且它将每一行的
LST\u 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);

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

Justin。谢谢你的信息-非常有用。该表现在允许PROD_CD和PLAN_CD中使用null,我从主键中删除了这些字段。我还遵循了您的建议,在我的参数名前面加了一个p_u。剩下的唯一问题是,当我第二次使用参数DCWEB4578,1P,CA,CALIFORNIA调用setUserPlanPref时,插入成功,值为:DCWEB4578,1P,CO,COLORODO。表不会更新。还有什么建议吗?再次感谢。在表定义中,我输入了:PROD_CD VARCHAR2(9),PLAN_CD VARCHAR2(9),我还尝试了:PROD_CD VARCHAR2(9)NULL,PLAN_CD VARCHAR2(9)NULL,我能够进行行更新的唯一方法是使用字符串“NULL”作为PROD_CD的输入值,而不是将其保留为空/null。@user143367-假设
USERID
现在是表的主键,问题是谓词
up.PROD_CD=upper(p_PROD_CD)
如果
up.PROD_CD
p_PROD_CD
null,则谓词
NULL
值永远不会彼此相等(它们也永远不会彼此不相等)。您需要使用
NVL
或显式检查
NULL
,即
(up.prod\u cd=upper(p\u prod\u cd)或(up.prod\u cd为NULL,p\u cd为NULL)
NVL(up.prod\u cd,'NULL')=NVL(upper(p\u prod\u cd),'NULL')
ORA-01400: cannot insert NULL into ("DCWEB"."USER_PLAN_PREFERENCE"."PROD_CD")
 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);