动态 SQL 在 PL/SQL 中具有动态绑定

Dynamic SQL with dynamic bindings in PL/SQL

我正在 ORDS 中编写 REST 处理程序。 URL 端点应允许使用多个可选参数进行查询。编写 PL/SQL 代码的一种方法可能是:

DECLARE
  cur SYS_REFCURSOR
BEGIN
  OPEN cur FOR
    SELECT * FROM MYTABLE WHERE
    (:param1 IS NULL OR column1 = :param1) AND
    (:param2 IS NULL OR column2 = :param2);
  :resultSetOut := cur;
END;

另一种我认为性能稍高的方法是构建 SQL 字符串

DECLARE
  cur SYS_REFCURSOR
  sqlString VARCHAR2(200)
BEGIN
  sqlString := 'SELCT * FROM MYTABLE WHERE 1=1';
  IF (:param1 IS NOT NULL) THEN sqlString := sqlString || ' AND COLUMN1=:param1'; END IF;
  IF (:param2 IS NOT NULL) THEN sqlString := sqlString || ' AND COLUMN1=:param2'; END IF;
  OPEN cur FOR sqlString USING :param1, :param2;
  :resultSetOut := cur;
END;

但是,最后的这个字符串构造需要静态绑定到变量,这实际上使得所有变量在 URL 查询中都是必需的,而不是可选的。

对于允许动态 WHERE 子句的 PL/SQL 块,使用此处显示的第一种方法的唯一方法是什么?有没有一种方法可以构造一个字符串并绑定类似于此处显示的第二种方法?

你走在正确的轨道上:

IF (:param1 IS NOT NULL) THEN sqlString := sqlString || ' AND COLUMN1=:param1'; 
Else sqlString := sqlString || ' and (1=1 or :param1 is null) ';
END IF;

现在无论如何您都需要相同数量的绑定变量,并且 Oracle 优化器将知道 1 始终为 1,因此不需要考虑其他谓词。

你可以在没有动态的情况下以等效的方式做到这一点 SQL:

BEGIN
  IF :param1 IS NOT NULL AND :param1 IS NOT NULL THEN
    OPEN :resultSetOut FOR
      SELECT *
      FROM   MYTABLE
      WHERE  COLUMN1=:param1
      AND    COLUMN2=:param2;
  ELSIF :param1 IS NOT NULL THEN
    OPEN :resultSetOut FOR
      SELECT *
      FROM   MYTABLE
      WHERE  COLUMN1=:param1;
  ELSIF :param2 IS NOT NULL THEN
    OPEN :resultSetOut FOR
      SELECT *
      FROM   MYTABLE
      WHERE  COLUMN2=:param2;
  ELSE
    OPEN :resultSetOut FOR
      SELECT *
      FROM   MYTABLE;
  END IF;
END;