PL/SQL 过程中的参数偏移量

offset with parameter in PL/SQL procedure

我有一个 PL/SQL 程序。它执行 SQL 语句和 returns 一个 json 响应。

我想使用 offset 子句限制返回的行。例如:

select *    
from wherever
where something = parameter
offset 0 rows 
fetch next 25 rows only;

但是我似乎无法使用变量来替换上面示例中的 0 和 25。

当然有办法解决这个问题。我可以像在 11g 中出现偏移子句之前那样编写代码。但它看起来很丑,而且可能不会表现得那么好……我是不是错过了什么。 proc 或 cursor 中 SQL 的偏移量子句中可以使用参数吗?

例如,以下过程确实可以编译,但返回的游标始终为空(当我在值中进行硬编码时不是):

procedure test (pPageSize in pls_integer:=25, pPageno in pls_integer:=1, RecipeList out sys_refcursor) is
      vNextRows pls_integer;
      vOffset pls_integer; 
    begin
        vOffset:= pPageSize*(pPageno-1);
        vNextRows:= pPageSize;          

        open RecipeList 
            for
            select *      
            from recipes       
            order by recipeno
            offset vOffset rows 
            fetch next vNextRows rows only; 
       
end test;  

像这样:

declare
  start_row integer := 0;
  fetch_rows integer := 5;
begin
  
  dbms_output.put_line ( 'First ' || fetch_rows );
  for t in ( 
    select * from all_tables 
    offset start_row rows 
    fetch first fetch_rows rows only 
  ) loop
    dbms_output.put_line ( t.table_name );
  end loop;
  
  start_row := 5;
  dbms_output.put_line ( 'Next ' || fetch_rows );
  for t in ( 
    select * from all_tables 
    offset start_row rows 
    fetch first fetch_rows rows only 
  ) loop
    dbms_output.put_line ( t.table_name );
  end loop;
end;
/

我试过了

如果将值传递给过程,它工作正常。它不适用于默认值。

-- 创建过程

SQL> CREATE OR replace PROCEDURE TEST1 (
  2  PPAGESIZE    IN    PLS_INTEGER:= 5, -- or default 5
  3  PPAGENO      IN    PLS_INTEGER:= 1, -- or default 1
  4  RECIPELIST   OUT   SYS_REFCURSOR
  5  ) IS
  6  VNEXTROWS   PLS_INTEGER;
  7  VOFFSET     PLS_INTEGER;
  8  BEGIN
  9  VOFFSET     := PPAGESIZE * ( PPAGENO - 1 );
 10  VNEXTROWS   := PPAGESIZE;
 11  OPEN RECIPELIST FOR SELECT *
 12                        FROM T
 13                       ORDER BY A OFFSET VOFFSET ROWS
 14   FETCH NEXT
 15  VNEXTROWS ROWS ONLY;
 16  END TEST1;
 17  /

Procedure created.

-- 不使用默认值

SQL> var res refcursor;
SQL> exec TEST1(null,null,:res);

PL/SQL procedure successfully completed.

SQL> print :res;

no rows selected

-- 使用非默认值

SQL> exec TEST1(5,1,:res);

PL/SQL procedure successfully completed.

SQL> print :res;

         A          B          C
---------- ---------- ----------
         1          1          2
         3                     2
         4          3          4
         8          9          6
        12         12         12

SQL>

当您调用过程时

test (null, null, :bind_rc)

您正在覆盖默认值;如果您想使用默认值,则不要提供前两个参数:

test (RecipeList => :bind_rc)

或者如果您不想使用默认值,请提供参数:

test (10, 11, :bind_rc)
test (pPageSize >= 10, pPageno => 2, RecipeList => :bind_rc)

或保留默认大小但获取特定页面:

test (pPageno => 3, RecipeList => :bind_rc)

db<>fiddle


From the documentation:

Default value of the formal parameter that you are declaring. The data type of expression must be compatible with datatype.

If a subprogram invocation does not specify an actual parameter for the formal parameter, then that invocation evaluates expression and assigns its value to the formal parameter.

If a subprogram invocation does specify an actual parameter for the formal parameter, then that invocation assigns the value of the actual parameter to the formal parameter and does not evaluate expression.

指定的实际参数。您传递的是 null,但这意味着您将形式参数指定为 null - 而 not 表示您根本没有指定它们。一个微妙但重要的区别。


I guess I coudl set up default manually in the proc if I were keen.

是的,很简单:

vOffset:= nvl(pPageSize, 25) * (nvl(pPageno, 1) -1);
vNextRows:= nvl(pPageSize, 25);

db<>fiddle