存储过程未返回预期的自定义异常消息
Posted
技术标签:
【中文标题】存储过程未返回预期的自定义异常消息【英文标题】:Stored procedure is not returning expected custom exception message 【发布时间】:2019-01-05 11:21:53 【问题描述】:我正在使用这个存储过程,我在其中检查游标是否包含任何数据,如果它有 0 条记录,则引发异常,否则将数据返回到输出中。
CREATE OR replace PROCEDURE user_details(v_ownerid IN NUMBER,
v_branchcode IN NVARCHAR2,
v_login IN NVARCHAR2,
cv_1 OUT SYS_REFCURSOR)
IS
result_out1 SYS_REFCURSOR;
v_territoryid NUMBER(10);
v_user NUMBER(10);
CURSOR cc IS
SELECT Z.username AS USERNAME,
Z.loginid AS LOGINID,
Z.userid AS CRMUSERID
FROM userterritory U
inner join teammembers T
ON U.ownerid = T.ownerid
AND U.userid = T.memberid
inner join az_user Z
ON Z.appownerid = T.ownerid
AND Z.userid = T.memberid;
TYPE tbl_join
IS TABLE OF cc%ROWTYPE;
l_table TBL_JOIN;
BEGIN
SELECT regionid
INTO v_territoryid
FROM regions
WHERE ownerid = v_ownerid
AND categorytype = 3
AND code = v_branchcode;
SELECT userid
INTO v_user
FROM az_user
WHERE appownerid = v_ownerid
AND loginid = v_login;
OPEN result_out1 FOR
SELECT Z.username AS USERNAME,
Z.loginid AS LOGINID,
Z.userid AS CRMUSERID
FROM userterritory U
inner join teammembers T
ON U.ownerid = T.ownerid
AND U.userid = T.memberid
inner join az_user Z
ON Z.appownerid = T.ownerid
AND Z.userid = T.memberid
WHERE Z.appownerid = v_ownerid
AND T.reportsto = v_user
AND U.territoryid = v_territoryid; --using whereClause;
FETCH result_out1 bulk collect INTO l_table;
-- FETCH result_out1 bulk collect INTO l_table;
dbms_output.Put_line('Count '
|| l_table.count);
IF l_table.count > 0 THEN
OPEN cv_1 FOR
SELECT Z.username AS USERNAME,
Z.loginid AS LOGINID,
Z.userid AS CRMUSERID
FROM userterritory U
inner join teammembers T
ON U.ownerid = T.ownerid
AND U.userid = T.memberid
inner join az_user Z
ON Z.appownerid = T.ownerid
AND Z.userid = T.memberid
WHERE Z.appownerid = v_ownerid
AND T.reportsto = v_user
AND U.territoryid = v_territoryid;
ELSE
Raise_application_error(-20001, 'Data Not Found.');
END IF;
END;
如果数据不存在,此存储过程将引发异常。但不是返回自定义异常消息,而是返回系统异常:
ORA-01403:未找到数据
我在这里做错了吗?是否需要进行任何更改才能返回自定义异常消息,即“未找到数据”?我将修改此消息。早些时候我在 SP 下使用,但在记录为 0 的情况下它没有返回任何错误消息,因为我已经完成了存储过程中提到的更改:
CREATE OR replace PROCEDURE user_details(v_ownerid IN NUMBER,
v_branchcode IN NVARCHAR2,
v_login IN NVARCHAR2,
cv_1 OUT SYS_REFCURSOR)
AS
v_territoryid NUMBER(10);
v_user NUMBER(10);
BEGIN
SELECT regionid
INTO v_territoryid
FROM regions
WHERE ownerid = v_ownerid
AND categorytype = 3
AND code = v_branchcode;
SELECT userid
INTO v_user
FROM az_user
WHERE appownerid = v_ownerid
AND loginid = v_login;
OPEN cv_1 FOR
SELECT Z.username AS USERNAME,
Z.loginid AS LOGINID,
Z.userid AS CRMUSERID
FROM userterritory U
inner join teammembers T
ON U.ownerid = T.ownerid
AND U.userid = T.memberid
inner join az_user Z
ON Z.appownerid = T.ownerid
AND Z.userid = T.memberid
WHERE Z.appownerid = v_ownerid
AND T.reportsto = v_user
AND U.territoryid = v_territoryid;
END;
【问题讨论】:
我怀疑其中一个 pure 选择(select userid
或 select regionid
)返回 ORA-01403,而不是光标。
错误可能来自SELECT regionid INTO v_territoryid FROM regions
或SELECT userid INTO v_user
@KaushikNayak 和 Littlefoot 谢谢。我错过了检查那部分是我的错误。是的,该行发生了异常。我已经评论了那部分以供检查。它正在返回预期的错误消息。
【参考方案1】:
ORA-01403: no data found
是从 BULK COLLECT
之前的两个 select 语句中的任何一个引发的,来自 CURSOR
。
除此之外,您的代码似乎包含几个冗余结构,使其变得不必要地复杂。例如,CURSOR cc
的唯一目的是定义该类型的表变量,如果您的意图只是在打开游标之前检查记录是否存在,则不需要使用 BULK COLLECT
。
你可以这样重写。
CREATE OR replace PROCEDURE user_details (v_ownerid IN NUMBER,
v_branchcode IN NVARCHAR2,
v_login IN NVARCHAR2,
cv_1 OUT SYS_REFCURSOR)
IS
v_territoryid NUMBER(10);
v_user NUMBER(10);
l_count INT;
BEGIN
SELECT regionid
INTO v_territoryid
FROM regions
WHERE ownerid = v_ownerid
AND categorytype = 3
AND code = v_branchcode;
SELECT userid
INTO v_user
FROM az_user
WHERE appownerid = v_ownerid
AND loginid = v_login;
SELECT CASE
WHEN EXISTS (SELECT 1 --check if a row exists.
FROM userterritory u
INNER JOIN teammembers t
ON u.ownerid = t.ownerid
AND u.userid = t.memberid
INNER JOIN az_user z
ON z.appownerid = t.ownerid
AND z.userid = t.memberid
WHERE z.appownerid = v_ownerid
AND t.reportsto = v_user
AND u.territoryid = v_territoryid) THEN 1
ELSE 0
END
INTO l_count
FROM dual;
IF l_count = 1 THEN
OPEN cv_1 FOR
SELECT z.username AS username,
z.loginid AS loginid,
z.userid AS crmuserid
FROM userterritory u
INNER JOIN teammembers t
ON u.ownerid = t.ownerid
AND u.userid = t.memberid
INNER JOIN az_user z
ON z.appownerid = t.ownerid
AND z.userid = t.memberid
WHERE z.appownerid = v_ownerid
AND t.reportsto = v_user
AND u.territoryid = v_territoryid;
ELSE
raise_application_error(-20001, 'Data Not Found.');
END IF;
EXCEPTION
WHEN no_data_found THEN
raise_application_error(-20001, 'regionid or userid not Found.');
-- Handling the exception
--for errors from first 2 selects
END;
/
【讨论】:
以上是关于存储过程未返回预期的自定义异常消息的主要内容,如果未能解决你的问题,请参考以下文章
用于检索自定义消息而不是异常详细信息的 PLSQL 异常处理
Spring Security:来自 UserDetailsService 的自定义异常消息