从 Oracle 存储过程返回 XML
不幸的是,我的大部分数据库经验都是使用 MSSQL,它比 Oracle 更容易掌握。我想做的事情在 tSQL 中相当简单,但是 pl/sql 让我头疼。
我有以下过程:
CREATE OR REPLACE PROCEDURE USPX_GetUserbyID (USERID USERS.USERID%TYPE, USERRECORD OUT XMLTYPE) AS
BEGIN
SELECT XMLELEMENT("user"
, XMLATTRIBUTES(u.USERID AS "userid", u.companyid as "companyid", u.usertype as "usertype", u.status as "status", u.personid as "personid")
, XMLFOREST( p.FIRSTNAME AS "firstname"
, p.LASTNAME AS "lastname"
, p.EMAIL AS "email"
, p.PHONE AS "phone"
, p.PHONEEXTENSION AS "extension")
, XMLELEMENT("roles",
(SELECT XMLAGG(XMLELEMENT("role", r.ROLETYPE))
FROM USER_ROLES r
WHERE r.USERID = USERID
AND r.ISACTIVE = 1
)
)
, XMLELEMENT("watches",
(SELECT XMLAGG(
XMLELEMENT("watch",
XMLATTRIBUTES(w.WATCHID AS "id", w.TICKETID AS "ticket")
)
)
FROM USER_WATCHES w
WHERE w.USERID = USERID
AND w.ISACTIVE = 1
)
)
) AS "RESULT"
INTO USERRECORD
FROM USERS u
LEFT JOIN PEOPLE p ON p.PERSONID = u.PERSONID
WHERE u.USERID = USERID;
END USPX_GetUserbyID;
执行时,它应该返回具有以下结构的 XML 文档:
<user userid="" companyid="" usertype="" status="" personid="">
<firstname />
<lastname />
<email />
<phone />
<extension />
<roles>
<role />
</roles>
<watches>
<watch id="" ticket="" />
</watches>
</user>
当我执行查询本身时,用字符串替换 USERID 参数并删除“into”子句,查询运行良好并返回预期的结果结构。
但是,当该过程尝试执行查询,将 XMLELEMENT 函数的结果传递到 USERRECORD 输出参数时,我得到以下异常:
Error report: ORA-01422: exact fetch returns more than requested number of rows ORA-06512: at "USPX_GETUSERBYID", line 4 ORA-06512: at line 3
01422. 00000 - "exact fetch returns more than requested number of rows"
*Cause: The number specified in exact fetch is less than the rows returned.
*Action: Rewrite the query or change number of rows requested
I'm baffled attempts to pin this down, andfortunately my google-fu has not help 。我发现了大量 Oracle SQL|XML 示例,但没有一个处理从过程返回的 XML。
注意: 我知道存在使用 DBMS 方法检索 XML 的替代方法,但是,据我所知,该功能已被弃用,取而代之的是 SQL|XML。
Unfortunately most of my DB experience has been with MSSQL which tends to hold your hand a lot more than Oracle. What I'm trying to do is fairly trivial in tSQL, however, pl/sql is giving me a headache.
I have the following procedure:
CREATE OR REPLACE PROCEDURE USPX_GetUserbyID (USERID USERS.USERID%TYPE, USERRECORD OUT XMLTYPE) AS
BEGIN
SELECT XMLELEMENT("user"
, XMLATTRIBUTES(u.USERID AS "userid", u.companyid as "companyid", u.usertype as "usertype", u.status as "status", u.personid as "personid")
, XMLFOREST( p.FIRSTNAME AS "firstname"
, p.LASTNAME AS "lastname"
, p.EMAIL AS "email"
, p.PHONE AS "phone"
, p.PHONEEXTENSION AS "extension")
, XMLELEMENT("roles",
(SELECT XMLAGG(XMLELEMENT("role", r.ROLETYPE))
FROM USER_ROLES r
WHERE r.USERID = USERID
AND r.ISACTIVE = 1
)
)
, XMLELEMENT("watches",
(SELECT XMLAGG(
XMLELEMENT("watch",
XMLATTRIBUTES(w.WATCHID AS "id", w.TICKETID AS "ticket")
)
)
FROM USER_WATCHES w
WHERE w.USERID = USERID
AND w.ISACTIVE = 1
)
)
) AS "RESULT"
INTO USERRECORD
FROM USERS u
LEFT JOIN PEOPLE p ON p.PERSONID = u.PERSONID
WHERE u.USERID = USERID;
END USPX_GetUserbyID;
When executed, it should return an XML document with the following structure:
<user userid="" companyid="" usertype="" status="" personid="">
<firstname />
<lastname />
<email />
<phone />
<extension />
<roles>
<role />
</roles>
<watches>
<watch id="" ticket="" />
</watches>
</user>
When I execute the query itself, replacing the USERID parameter with a string and removing the "into" clause, the query runs fine and returns the expected structure.
However, when the procedure attempts to execute the query, passing the results of the XMLELEMENT function into the USERRECORD output parameter, I get the following exception:
Error report: ORA-01422: exact fetch returns more than requested number of rows ORA-06512: at "USPX_GETUSERBYID", line 4 ORA-06512: at line 3
01422. 00000 - "exact fetch returns more than requested number of rows"
*Cause: The number specified in exact fetch is less than the rows returned.
*Action: Rewrite the query or change number of rows requested
I'm baffled trying to nail this down, and unfortunately my google-fu hasn't helped. I've found plenty of Oracle SQL|XML examples, but none that deal with XML returns from a procedure.
Note: I know that an alternate method of retrieving XML using DBMS methods exists, however, it's my understanding that that functionality is deprecated in favor of SQL|XML.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您的代码包括以下内容:
虽然您希望将裸 USERID 作为过程的参数,但 Oracle 实际上优先考虑作为表中列的 USERID。实际上,它将其解释为“
您可以使用”
,但最好为 PL/SQL 变量使用前缀以避免混淆。我倾向于使用 v_ 表示变量,使用 i_、o_、io_ 表示输入、输出和输入/输出参数。
Your code includes the following :
While you intend the bare USERID to be the procedure's parameter, Oracle actually gives preference to the USERID that is the column in the table. In effect it interprets it as
You can use
but it is good practice to use a prefix for PL/SQL variables to avoid confusion. I tend towards v_ for variables and i_, o_, io_ for input, output and input/output parameters.
您的错误与 XML 无关。在 PL/SQL 中,如果您有一个返回多行的查询,则必须使用游标循环遍历这些行。您使用了 INTO 关键字,它只能处理单行(或您的情况下的 XML)结果。
Your error has nothing to do with XML. In PL/SQL if you have a query which returns multiple rows, you must loop through the rows with a cursor. You have used the INTO keyword which can handle only a single row (or XML in your case) result.
您的查询显然返回了不止一行。根据构建过程的方式,您需要以返回包含所有 XML 的单行的方式编写查询。那么您不应该收到该错误。
You query is apparently returning more than one row. With the way you have structured your procedure, you need to write your query in a way that it returns a single row containing all of the XML. Then you should not receive the error.