【问题标题】:Dynamic PL/SQL query, how to ignore null parameters?动态 PL/SQL 查询,如何忽略空参数?
【发布时间】:2011-02-08 22:35:14
【问题描述】:

我有一个带有多个参数的 PL/SQL 过程。 webapp调用过程时,如果不使用某个参数,则传递为null,即

procedure test (param1 in varchar2, param2 in varchar2, param3 in varchar2, cursor out sys_refcursor)
...
end procedure test;

我想进行一个 SQL 查询,其中只有当参数不为空时,我才会在 WHERE 子句中包含给定的参数。除了在字符串中构建 SQL 查询然后打开该字符串的游标之外,有没有办法以一种优雅的方式实现这一点,就像这样

vSQL := 'SELECT * from TABLE WHERE something = something_else';
if param1 IS NOT NULL
    vSQL := vSQL || 'AND some_param = ' || param1;

【问题讨论】:

  • 我想指出,如果参数曾经暴露给用户,这是一个典型的代码示例,具有很高的 SQL*Injection 风险。所以你应该使用 DBMS_ASSERT 来检查你的最终 SQL 是否有良好的行为。

标签: sql oracle dynamic plsql


【解决方案1】:

我已经回答了类似的问题on dba.stackexchange.com

【讨论】:

  • 谢谢,这很有帮助。
【解决方案2】:

您可以将其全部编码到一个选择中

SELECT * from TABLE WHERE something = something_else
AND ((param1 IS NOT NULL AND some_param = param1) OR 1)

【讨论】:

  • 当从代码中调用命名查询时,这个答案是一个很好的简单解决方案,而 PL 通常不是一个选项。当构建标准查询或拼凑 where 子句时,我喜欢这样。
【解决方案3】:

创建测试表:

create table testtab
(
name_first varchar2(50),
name_last varchar2(50),
name_middle varchar2(50)
);

insert into testtab values ('Joe', 'Jones', 'A');
insert into testtab values ('Joe', 'Smith', 'A');
insert into testtab values ('Steve', 'Jones', 'B');
insert into testtab values ('Axl', 'Rose', 'C');
insert into testtab values ('Phil', 'McCracken', 'D');
commit;

创建您的程序:

CREATE OR REPLACE procedure ECDATA.get_testtab_rows
(i_name_first in varchar2 default null,
i_name_last in varchar2 default null,
i_name_middle in varchar2 default null,
o_cursor out sys_refcursor
) as

    v_result_cur    sys_refcursor;

begin

    open v_result_cur for
        select * from testtab
        where name_first like nvl(i_name_first, '%')
        and name_last like nvl(i_name_last, '%')
        and name_middle like nvl(i_name_middle, '%')
    ;

    o_cursor := v_result_cur;

end;
/

然后这样称呼它:

declare

    v_cur sys_refcursor;
    testtab_rec testtab%rowtype;

begin

    get_testtab_rows(i_name_last=>'Jones', o_cursor=>v_cur);
    loop

        fetch v_cur into testtab_rec;
        exit when v_cur%notfound;
        dbms_output.put_line(testtab_rec.name_first || ' ' || testtab_rec.name_middle || ' ' || testtab_rec.name_last);

    end loop;

exception
    when others then raise;
end;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-24
    • 2015-05-13
    • 2020-05-31
    • 2022-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多