2014-09-23 59 views
0
CREATE OR REPLACE PROCEDURE test_max_rows (
    max_rows IN NUMBER DEFAULT 1000 
) 
IS 
    CURSOR cur_test (max_rows IN number) IS 
     SELECT id FROM test_table 
     WHERE user_id = 'ABC' 
     AND ROWNUM <= max_rows; 
    id test_table.id%TYPE; 
BEGIN 
    OPEN cur_test(max_rows) ; 
    LOOP 
    FETCH cur_test INTO id; 
    EXIT WHEN cur_test%NOTFOUND; 
    DBMS_OUTPUT.PUT_LINE('ID:' || id); 
    END LOOP; 
END; 

我的要求是修改上面的代码,以便当我为max_rows传递-1时,proc应该返回查询返回的所有行。否则,它应该按照max_rows限制行数。显示基于输入参数的行数

例如:

EXECUTE test_max_rows(-1); 

这个命令应该返回由上面的SELECT语句返回的所有行。

EXECUTE test_max_rows(10); 

该命令应该只返回10行。

+0

我建议删除DEFAULT 1000。之后你不需要这个-1破解。告诉你的应用程序使用这个过程来说它需要1000个。因为任何其他带有当前select的解决方案都会引发一个IF语句和另一个子查询来确定表中有多少行,例如。 IF max_rows == -1 THEN max_rows = SELECT count(1)FROM table .. – tvm 2014-09-23 09:30:03

回答

2

你可以用OR条款来做到这一点;改变:

AND ROWNUM <= max_rows; 

到:

AND (max_rows < 1 OR ROWNUM <= max_rows); 

然后通过零,-1或任何负数将获取所有行,任何正数将返回的限制列表。你也可以用default null更换default 1000条款,然后测试空相反,这可能是比较明显的一点:

AND (max_rows is null OR ROWNUM <= max_rows); 

注意,因为你不知道你有传递价值得到哪些行是不确定目前有一个order by条款。

在一个过程中做这件事似乎有点奇怪,你假设谁调用它将能够看到输出 - 即将完成set serveroutput on或他们的客户端的等价物 - 这不是一个非常安全的假设。另一种方法是,如果您不能在简单的查询中指定行限制,则可以使用流水线功能 - 至少可以从普通SQL中调用该功能。

CREATE OR REPLACE FUNCTION test_max_rows (max_rows IN NUMBER DEFAULT NULL) 
RETURN sys.odcinumberlist PIPELINED 
AS 
BEGIN 
    FOR r IN (
     SELECT id FROM test_table 
     WHERE user_id = 'ABC' 
     AND (max_rows IS NULL OR ROWNUM <= max_rows) 
    ) LOOP 
     PIPE ROW (r.id); 
    END LOOP; 
END; 
/

然后调用它为:

SELECT * FROM TABLE(test_max_rows); 

SELECT * FROM TABLE(test_max_rows(10)); 

Here's a quick SQL Fiddle demo。但是你仍然应该考虑是否可以在普通的SQL和PL/SQL中完成整个事情。

+0

非常感谢。尽管我没有得到@TVM的建议。请原谅我的无知。 SQL新手。 – 2014-09-23 10:12:30

+0

@WamglindCarmasaic - 我认为tvm意味着删除默认子句并使客户端*始终*指定多行;即它必须传递非常高的值以确保包含所有行。这意味着您的客户端足够了解要安全执行的数据,或者首先运行查询来决定要使用的数字。 – 2014-09-23 10:16:11