简体   繁体   English

如何获得sysref游标选择的记录总数?

[英]How can I get the total number of records selected by a sysref cursor?

BACKGROUND 背景

I am working on a web application that calls PLSQL stored procedures to retrieve and manipulate information. 我正在使用一个Web应用程序,该应用程序调用PLSQL存储过程来检索和处理信息。 In one such case, the database has two stored procedures; 在这种情况下,数据库有两个存储过程。 one that selects the total number of records for a given set of parameters and one that returns the actual records with the same parameters, plus pagination parameters (min and max rownum). 一个选择一组给定参数的记录总数,另一个返回具有相同参数以及分页参数(最小和最大行数)的实际记录。

EX (not the actual code): EX(不是实际代码):

PROCEDURE get_records_count(
    p_first_name IN record_table.first_name%TYPE,
    p_last_name IN record_table.last_name%TYPE,
    p_resultCursor OUT sys_refcursor
)
IS BEGIN 
    OPEN p_resultCursor FOR 
    SELECT count(*) from record_table 
        WHERE first_name LIKE (p_first_name || '%') 
        OR last_name LIKE (p_last_name || '%');
END;


PROCEDURE get_records(
    p_first_name IN record_table.first_name%TYPE,
    p_last_name IN record_table.last_name%TYPE,
    p_min IN NUMBER,
    p_max IN NUMBER,
    p_resultCursor OUT sys_refcursor
)
IS BEGIN 
    OPEN p_resultCursor FOR 
    SELECT * from record_table 
        WHERE first_name LIKE (p_first_name || '%') 
        OR last_name LIKE (p_last_name || '%')
        AND rownum >= p_min AND rownum <= p_max;
END;

Whether or not one thinks that this is a good idea is beyond the scope of my position. 是否认为这是一个好主意超出了我的职务范围。 The problem is that whenever either stored procedure is changed, the results don't match up. 问题在于,无论何时更改任一存储过程,结果都不匹配。 The short term fix is to look through both stored procedures, determine which selection criteria from which stored procedure is appropriate and then edit the other stored procedure so that they both match up. 短期解决方法是浏览两个存储过程,确定从哪个存储过程中选择哪个选择标准,然后编辑另一个存储过程,使它们都匹配。

As a long term fix, I would like to change the get_records_count procedure to call the get_records procedure and then return the total number of records that would be returned from the resulting sys_refcursor. 作为一项长期解决方案,我想将get_records_count过程更改为调用get_records过程,然后返回从结果sys_refcursor返回的记录总数。

EX: 例如:

PROCEDURE get_records_count(
    p_first_name IN record_table.first_name%TYPE,
    p_last_name IN record_table.last_name%TYPE,
    p_resultCursor OUT sys_refcursor
)
AS
v_recordsSelectedCursor sys_refcursor; 
BEGIN 
    /*I understand that I will need to change some logic in get_records to
      handle the case in which p_max is set to zero. 
      It should take this case to not apply an upper limit.*/ 
    get_records(p_first_name,p_last_name,0,0,v_recordsSelectedCursor);
    /*This is where I really have NO idea what I'm doing.
      Hopefully, you can infer what I'm trying to do. */ 
    OPEN p_resultCursor FOR
        SELECT count(*) FROM v_recordsSelectedCursor;  
END;

ACTUAL QUESTION 实际问题

How can I select the number of records that would be returned for a sys_refcursor? 如何选择要为sys_refcursor返回的记录数? The resulting number needs to be returned inside a sys_refcursor 结果数需要在sys_refcursor内部返回

A cursor is just a spec for fetching rows - it doesn't know how many rows are going to be returned until it has fetched them all. 游标只是用于获取行的规范-在获取所有行之前,它不知道将返回多少行。

Any method involving calling it twice risks getting inconsistent results unless you use dbms_flashback.enable_at_time at the start of the procedure (and disable it at the end). 除非两次在过程开始时使用dbms_flashback.enable_at_time (并在过程结束时将其禁用),否则任何涉及两次调用它的方法dbms_flashback.enable_at_time可能导致结果不一致。 There is also the performance overhead, of course. 当然,还有性能开销。

The only way to get a cursor to include its total rowcount is to include an analytic count(*) over () expression in the select list. 使游标包括其总行数的唯一方法是在select列表中的count(*) over ()表达式上包含一个解析count(*) over ()

How can I select the number of records that would be returned for a sys_refcursor? 如何选择要为sys_refcursor返回的记录数? The resulting number needs to be returned inside a sys_refcursor. 结果数需要在sys_refcursor内部返回。

You can modify your procedure as below: 您可以如下修改程序:

PROCEDURE get_records_count(
    p_first_name IN record_table.first_name%TYPE,
    p_last_name IN record_table.last_name%TYPE,
    p_resultCursor OUT sys_refcursor
)
AS
v_recordsSelectedCursor sys_refcursor; 
type y is table of record_table%rowtype;
z y; 
num number:=0;
BEGIN 

    get_records(p_first_name,p_last_name,0,0,v_recordsSelectedCursor);

    fetch  v_recordsSelectedCursor bulk collect into z;

    ---taking the count of refcursor
    num:=z.count;

    OPEN p_resultCursor FOR
    select num from dual;         
    dbms_output.put_line(num);

END;

See demo: 观看演示:

 SQL> SELECT count(*)
     FROM emp;

     COUNT(*)
     ----------
      14

SQL> CREATE OR REPLACE PROCEDURE sys_ref_rec_cnt (var OUT sys_refcursor)
  2  AS
  3  BEGIN
  4  OPEN var FOR
  5  SELECT *
  6    FROM emp;
  7  END;
  8  /

Procedure created.    

 SQL> DECLARE
  2  x     sys_refcursor;
  3  k     sys_refcursor;
  4  TYPE y IS TABLE OF emp%ROWTYPE;
  5  z      y;
  6  num   NUMBER        := 0;
  7  BEGIN
  8  sys_ref_rec_cnt (x);
  9  
 10  FETCH x
 11  BULK COLLECT INTO z;
 12  
 13  num :=z.count;
 14  
 15  open k for
 16   select num from dual;
 17   
 18  DBMS_OUTPUT.put_line ('No. Of records-->'||num);
 19  END;
 20  /

No. Of records-->14

PL/SQL procedure successfully completed.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM