如何在Oracle中显示过程之外的过程结果

时间:2018-11-26 20:59:57

标签: oracle stored-procedures

我正在处理一个应用程序,并决定所有查询都是过程。我希望通过这样做可以提高性能并简化维护。我们的DBA也表示有兴趣这样做。

我有一个HR表,每晚对其进行操作,任何更改都记录在辅助表中。我们不进行审核,这些更改记录将保留到下一次运行,并向用户显示已发生的更改。

为使问题简短,我减少了HR中的列数。

HR表ID,GROUP_NAME和GROUP_LEVEL。钻取表具有ID和TYPEVALUE。

CREATE OR REPLACE PROCEDURE DOCSADM.DRILL_RECORD_POSITION (
    RECORD_TYPE IN VARCHAR2,
    OUT_ID OUT VARCHAR2,
    OUT_GROUP_NAME OUT VARCHAR2,
    OUT_GROUP_LEVEL OUT VARCHAR2
) AS
BEGIN
    SELECT  HR.ID,  HR.GROUP_NAME,  HR.GROUP_LEVEL
    INTO    OUT_ID, OUT_GROUP_NAME, OUT_GROUP_LEVEL
    FROM HR_POSITION HR JOIN DRILL_POSITION DP ON (HR.ID = DP.ID) WHERE DP.TYPEVALUE = RECORD_TYPE;
END DRILL_RECORD_POSITION;

该过程编译没有问题。在完成应用程序中的所有工作以链接到该过程并提取值(在这种情况下,这些值最终将显示在视图或网页中)之前,我想要一个快速的小脚本来调用该过程,然后显示结果,以便我可以在Oracle中验证。

循环

BEGIN
for t in (DRILL_RECORD_POSITION('D', V1,V5,V6))
loop
    --dbms_output.put_line(t.V1 || t.V5 || t.V6);
    dbms_output.put_line(t.OUT_ID);

end loop;
END;
/

光标

DECLARE
V1 HR_POSITION.ID%TYPE;
V5 HR_POSITION.GROUP_NAME%TYPE;
V6 HR_POSITION.GROUP_LEVEL%TYPE;
CURSOR T_CUR IS DRILL_RECORD_POSITION('D', V1,V5,V6);
BEGIN
OPEN T_CUR;
    DBMS_OUTPUT.PUTLINE('START');
    LOOP
        FETCH T_CUR INTO V1,V5,V6;
        EXIT WHEN T_CUR%NOTFOUND;
        DBMS_OUTPUT.PUTLINE(V1||V5||V6);
    END LOOP;
CLOSE T_CUR;
END;

对于循环

DECLARE
V1 HR_POSITION.POSITION_ID%TYPE;
V5 HR_POSITION.GROUP_NAME%TYPE;
V6 HR_POSITION.GROUP_LEVEL%TYPE;
BEGIN
    DBMS_OUTPUT.PUTLINE('START');
    FOR INDEX IN (DRILL_RECORD_POSITION('D', V1,V5,V6))
LOOP
        --DBMS_OUTPUT.PUTLINE(INDEX.ID);
        DBMS_OUTPUT.PUTLINE(INDEX.V1||INDEX.V5||INDEX.V6);
    END LOOP;

END;

注意:我将列名进行了编辑,并在转移到此处时使其短了一些,所以我可能会犯一些错误。

我在网上看到的所有文章都向我展示了如何从原始过程显示或如何使用视图,光标,记录显示。除非我错了,否则Eclipse使用当前形式的信息不会有任何问题,这就是我以这种方式传递信息的原因。因此,我对更改该程序不感兴趣,并且希望按原样使用它,因为这就是应用程序将如何执行它。

因为这是我为应用程序执行的第一个存储过程,所以我没有使用任何现有示例来代替应用程序中的即席查询,这就是为什么我认为结果可以正常工作的原因,因为应该与即席使用的格式相同。

更新

在其中一项评论中,我指出应该是solution。位于其下的另一个solution证实了这一点。

我不断收到错误消息

  

ORA-01422:精确提取返回的行数超过了请求的行数

因此,我返回了多行,但这是我的期望以及正在发生的事情。我似乎无法弄清楚如何显示结果。

1 个答案:

答案 0 :(得分:0)

要测试显示的过程,您可以执行以下操作:

declare
  l_id hr_position.id%type;
  l_group_name hr_position.group_name%type;
  l_group_level hr_position.group_level%type;
begin
  drill_record_position('D', l_id, l_group_name, l_group_level);
  dbms_output.put_line(l_id ||':'|| l_group_name ||':'|| l_group_level);
end;
/

但是-或更确切地说,您的过程-仅在查询的结果集中存在传入值类型的一行时才起作用。看来您期望返回多行(这将导致太多行),但也可能会有非行(这将导致找不到数据)。

实际上,您的问题似乎应该是关于如何编写过程的,以便它与您尝试过的一种检索/测试方法一起工作。

如果您的过程需要返回多行,则可以使用ref游标,例如:

create or replace procedure drill_record_position (
  p_record_type in varchar2,
  p_ref_cursor out sys_refcursor
)
as
begin
  open p_ref_cursor for
    select hr.id, hr.group_name, hr.group_level
    from hr_position hr
    join drill_position dp
    on hr.id = dp.id
    where dp.typevalue = p_record_type;
end drill_record_position;
/

然后您可以使用以下内容进行测试:

declare
  l_ref_cursor sys_refcursor;
  l_id hr_position.id%type;
  l_group_name hr_position.group_name%type;
  l_group_level hr_position.group_level%type;
begin
  drill_record_position('D', l_ref_cursor);
  loop
    fetch l_ref_cursor into l_id, l_group_name, l_group_level;
    exit when l_ref_cursor%notfound;
    dbms_output.put_line(l_id ||':'|| l_group_name ||':'|| l_group_level);
  end loop;
  close l_ref_cursor;
end;
/

您也可以将其作为一个函数来完成,这可能更容易在您的应用程序中使用:

-- drop procedure drill_record_position;

create or replace function drill_record_position (p_record_type in varchar2)
return sys_refcursor as
  l_ref_cursor sys_refcursor;
begin
  open l_ref_cursor for
    select hr.id, hr.group_name, hr.group_level
    from hr_position hr
    join drill_position dp
    on hr.id = dp.id
    where dp.typevalue = p_record_type;
  return l_ref_cursor;
end drill_record_position;
/

declare
  l_ref_cursor sys_refcursor;
  l_id hr_position.id%type;
  l_group_name hr_position.group_name%type;
  l_group_level hr_position.group_level%type;
begin
  l_ref_cursor := drill_record_position('D');
  loop
    fetch l_ref_cursor into l_id, l_group_name, l_group_level;
    exit when l_ref_cursor%notfound;
    dbms_output.put_line(l_id ||':'|| l_group_name ||':'|| l_group_level);
  end loop;
  close l_ref_cursor;
end;
/

您也可以使用集合和流水线函数来做到这一点,这需要进行更多的工作:

create type t_drill_obj as object (
   -- use your real data types...
  id number,
  group_name varchar2(10),
  group_level number
)
/

create type t_drill_tab as table of t_drill_obj
/

create or replace function drill_record_position (p_record_type in varchar2)
return t_drill_tab pipelined as
begin
  for l_row in (
    select t_drill_obj(hr.id, hr.group_name, hr.group_level) as obj
    from hr_position hr
    join drill_position dp
    on hr.id = dp.id
    where dp.typevalue = p_record_type
  )
  loop
    pipe row (l_row.obj);
  end loop;
  return;
end drill_record_position;
/

但是您可以将其作为另一个查询的一部分来调用,甚至可以在需要时加入他的结果

select * from table(drill_record_position('D'));