【问题标题】:oracle dynamic sql evaluate expression in where clauseoracle动态sql评估where子句中的表达式
【发布时间】:2021-10-27 19:56:20
【问题描述】:

我正在尝试使用动态 SQL 将表达式传递到我的查询的 WHERE 子句中。表达式可以包含多个过滤器/列。

与 SO 上的其他帖子类似,以下(示例 1)有效:


DECLARE
    where_expression VARCHAR2(40) := q'[filter_column = 'some_value')]';
    plsql_block VARCHAR2(500);

BEGIN
    plsql_block := 'SELECT column FROM mytable';

    EXECUTE IMMEDIATE plsql_block || ' WHERE ' || where_expression;

END;
/

而且这种使用占位符的方法(示例 2)不起作用:


DECLARE
    where_expression VARCHAR2(40) := q'[filter_column = 'some_value')]';
    plsql_block VARCHAR2(500);

BEGIN
    plsql_block := 'SELECT column FROM mytable WHERE :a';

    EXECUTE IMMEDIATE plsql_block USING where_expression;

END;
/

Oracle 在第 8 行返回错误:ORA-00920: invalid relational operator(EXEC 语句)。

我在示例 2 中做错了什么以及使用占位符的正确方法是什么?

【问题讨论】:

  • 你不能那样做。 :a 只是传递了一个字符串。它没有得到评估。如果需要完全控制,则需要使用 DBMS_SQL 包。
  • 我明白了。用 DBMS_SQL 包怎么做?
  • 您需要将输入拆分为带有占位符的表达式以及这些占位符的值。如果您有可变数量的占位符,那么它会变得复杂,因为您将不得不使用具有不同数量的参数和逻辑的多个动态 SQL 语句来执行一个。或者您可以使用 cursor_sharing=force 的惰性选项。无论您做什么,这都极易受到 SQL 注入的影响,您需要验证输入 - 您最好使用带有允许过滤器的静态 SQL。

标签: oracle plsql dynamic-sql


【解决方案1】:

我在示例 2 中做错了什么以及使用占位符的正确方法是什么?

占位符语法用于在执行语句时传递要检查的值。预期的用法是这样的:

DECLARE
    v_out_1     varchar2(32);
    v_out_2     varchar2(32);
    plsql_block VARCHAR2(500);

BEGIN
    plsql_block := 'SELECT column FROM mytable WHERE filter_column = :a';

    EXECUTE IMMEDIATE plsql_block INTO v_out_1 USING 'some value';

    EXECUTE IMMEDIATE plsql_block INTO v_out_2 USING 'another value';
END;
/

【讨论】:

    【解决方案2】:

    CASE 表达式中可能的过滤列列入白名单:

    DECLARE
      v_out        VARCHAR2(32);
      column_name  VARCHAR2(30) := 'COLUMN1';
      column_value VARCHAR2(30) := 'value1';
      sql          VARCHAR2(500);
    BEGIN
      sql := 'SELECT column
              FROM   mytable
              WHERE  CASE :name
                     WHEN ''COLUMN1'' THEN column1
                     WHEN ''COLUMN2'' THEN column2
                     WHEN ''COLUMN3'' THEN column3
                     END = :value';
    
      EXECUTE IMMEDIATE sql INTO v_out USING column_name, column_value;
    END;
    /
    

    【讨论】:

    • 如果你像这样重写,那么动态 SQL 不会给你任何东西。这可能只是静态 SQL。
    猜你喜欢
    • 1970-01-01
    • 2011-10-03
    • 1970-01-01
    • 2013-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-29
    • 1970-01-01
    相关资源
    最近更新 更多