动态Oracle查询,不带动态

问题描述 投票:0回答:1

标题确实很奇怪,但我会尽力解释一下。

我多年来一直在 11G 版本中对 Oracle (PL-SQL) 进行编程。 我最近搬到了一个新的工作场所,在第一个任务中,我被要求编写一个接受 5 个变量作为输入的函数,并且可能不会发送所有变量 - 也许只有一个。

作为该过程的一部分,在很多非常大的表之间存在非常大的查询,因此输入中的值越多,表之间的 JOINS 实现得越多,索引的使用效率也越高。 喜欢

create function get_customer(p_ssn number, p_phone number, p_email varchar2, p_address varchar2, p_unique_id number number) return <type>
is
begin
select...
from A, B, C, D, E, F, G
JOIN ..
where ssn = p_ssn
and phone = p_phone ...
end;

我想到解决该任务的第一种方法是使用动态 SQL,以便我们检查某个输入是否不为 NULL,如果是,我们可以将其 AND 链接到查询,最后对整个查询执行立即执行询问 喜欢

v_sql varchar2(4000);
v_sql := 'select...
    from A, B, C, D, E, F, G
    JOIN ..
    WHERE 1=1'

if p_phone is not null then
v_sql := v_sql || ' AND phone = p_phone'
end if;

等等..

但是,我的新团队领导决定不使用动态 SQL,因为它很复杂并且可能会崩溃等原因。 例如,他建议对每个输入使用 NVL

select...
from A, B, C, D, E, F, G
JOIN ..
where ssn = nvl (p_ssn, a.ssn)
and phone = nvl(p_phone, b.phone) etc..

我惊呆了。我认为 DBA 团队领导应该对效率和运行时了解一两件事。 当我向他展示执行计划非常糟糕,特别是他花了很多时间才能完成运行后,他告诉我找到另一种有效的方法,而不是使用动态 SQL。

那么,其他建议 任务如何解决?

oracle dynamic-sql
1个回答
0
投票

在您的示例中,您不会根据参数是否设置来改变连接哪些表;相反,您总是从相同的表中选择相同的列,并根据参数是否设置或未设置来应用不同的过滤器。

在这种情况下,传递

NULL
作为可选参数的默认值,然后使用静态查询并检查可选参数是否未使用
IS NULL
设置,以便您不应用该过滤器:

CREATE FUNCTION get_customer(
  p_ssn       A.SSN%TYPE       DEFAULT NULL,
  p_phone     B.PHONE%TYPE     DEFAULT NULL,
  p_email     C.EMAIL%TYPE     DEFAULT NULL,
  p_address   D.ADDRESS%TYPE   DEFAULT NULL,
  p_unique_id E.UNIQUE_ID%TYPE DEFAULT NULL
) RETURN <type>
IS
BEGIN
  SELECT A.column1,
         B.column2,
         C.column3,
         D.column4,
         E.column5,
         F.column6,
         G.column7
  INTO   ...
  FROM   A
         INNER JOIN B ON (...)
         INNER JOIN C ON (...)
         INNER JOIN D ON (...)
         INNER JOIN E ON (...)
         INNER JOIN F ON (...)
         INNER JOIN G ON (...)
  WHERE  (p_ssn   IS NULL OR a.ssn = p_ssn)
  AND    (p_phone IS NULL OR b.phone = p_phone)
  ...;
END;

如果您想使用动态 SQL,则不要将值连接到查询中(因为这会在代码中引入 SQL 注入漏洞)。相反,使用绑定变量将值传递到查询中:

v_sql varchar2(4000);
v_sql := 'SELECT A.column1,
         B.column2,
         C.column3,
         D.column4,
         E.column5,
         F.column6,
         G.column7
  FROM   A
         INNER JOIN B ON (...)
         INNER JOIN C ON (...)
         INNER JOIN D ON (...)
         INNER JOIN E ON (...)
         INNER JOIN F ON (...)
         INNER JOIN G ON (...)
  WHERE  1=1'

IF p_ssn IS NOT NULL THEN
  v_sql := v_sql || ' AND ssn = :1';
ELSE
  v_sql := v_sql || ' AND :1 IS NULL';
END IF;

IF p_phone IS NOT NULL THEN
  v_sql := v_sql || ' AND phone = :2';
ELSE
  v_sql := v_sql || ' AND :2 IS NULL';
END IF;

EXECUTE IMMEDIATE v_sql
  INTO ...
  USING p_ssn, p_phone;
© www.soinside.com 2019 - 2024. All rights reserved.