可以将绑定变量连接到动态 SQL WHERE 子句以添加 AND 语句吗?

Posted

技术标签:

【中文标题】可以将绑定变量连接到动态 SQL WHERE 子句以添加 AND 语句吗?【英文标题】:Can a bind variable be concatenated to a dynamic SQL WHERE clause in order to add an AND statement? 【发布时间】:2018-02-21 22:41:28 【问题描述】:

我正在尝试使用绑定变量将AND 语句添加到动态WHERE 子句中,我收到以下Oracle 错误:

ORA-01830: 日期格式图片在转换整个输入字符串绑定变量之前结束

这是有问题的代码:

FUNCTION WhereClause RETURN VARCHAR2
IS
BEGIN
    where_sql := 'WHERE TRUNC( ' || parm_rec.SRC_DATE_COLUMN || ' ) < ADD_MONTHS( ' ||
                                  'ADD_MONTHS ( TRUNC (  NVL ( :SYS_OFFSET, SYSDATE ) - ( :DAY_OFFSET )), ' ||
                                  '( :MON_OFFSET * :kNEGATIVE ) ), ' ||
                                  '( :YR_OFFSET * ( :kANNUM * :kNEGATIVE ) ) ) ';

    RETURN where_sql;
END WhereClause;



PROCEDURE ArchiveSrcDateFilter
IS     
BEGIN
DBMS_OUTPUT.PUT_LINE('ArchiveDynamic - ENTER');
IF parm_rec.SRC_DATE_COLUMN IS NULL THEN parm_rec.SRC_DATE_COLUMN := 'NULL';
END IF;
    FOR i in tbl_cur
    LOOP
    where_sql := WhereClause; -- defines the WHERE clause (where_sql) via function, Spec will not return variable to body?
    /*** DYNAMIC SQL DECLARATIONS ***/
        arc_sql := 'DECLARE ' ||
                    /*** DYNAMIC %ROWTYPE SELECT ***/
                        'CURSOR arc_cur IS ' ||
                        'SELECT * '||
                        'FROM '  || i.ARC_TABLE_NAME || '; '||               --obtain ARCHIVE ARC_SCHEMA_NAME.ARC_TABLE_NAME
                        'TYPE arc_cur_type IS TABLE OF arc_cur%ROWTYPE; ' || -- dynamically set archive record cursor %ROWTYPE for BULK COLECT as table collection 
                        'arc_rec    arc_cur_type; ' ||                       -- define archive record as TABLE OF cursor.%ROWTYPE          

                    /*** ARCHIVE PARAMETERS CURSOR - SRC_CREATE_DATE IS NOT NULL***/
                        'CURSOR parm_cur IS '||
                        'SELECT :seq_val AS ARCHIVE_ID, '||
                        'A.*, ' ||
                        'SYSDATE AS ARCHIVE_DATE ' ||
                        'FROM ' || srcSchemaTable || ' A ' ||                -- archive SRC_SCHEMA_NAME.SRC_TABLE_NAME (source table not archive table)
                        where_sql || ' || :ADD_FILTER ' || ' ; ' ||

               /*** DYNAMIC SQL STATEMENT BODY ***/                   
                   'BEGIN '||
                        'IF parm_cur%ISOPEN THEN CLOSE parm_cur; ' ||
                        'END IF; ' ||
                        'OPEN parm_cur; ' ||
                        'LOOP ' ||
                            'FETCH parm_cur ' ||
                            'BULK COLLECT INTO arc_rec LIMIT 500; ' ||
                            'EXIT WHEN arc_rec.COUNT = 0; ' ||
                            'FORALL i IN 1..arc_rec.COUNT ' ||
                                'INSERT INTO ' || arcTable ||
                                ' VALUES arc_rec( i );' ||
                                'DBMS_OUTPUT.PUT_LINE( ''ARC_REC_COUNT: '' || arc_rec.COUNT ); ' ||
                        'END LOOP; ' ||
                        'CLOSE parm_cur; ' ||                                   
                        'DBMS_OUTPUT.PUT_LINE(''SUCCESS...''); '||
                    'END; ';
    DBMS_OUTPUT.PUT_LINE('ArchiveDynamic - INSIDE LOOP: ' || arc_sql );

        EXECUTE IMMEDIATE arc_sql
        USING seq_val, parm_rec.SYS_OFFSET, parm_rec.DAY_OFFSET, parm_rec.MON_OFFSET, kNEGATIVE, parm_rec.YR_OFFSET, kANNUM, parm_rec.ADD_FILTER;

    END LOOP;

END ArchiveSrcDateFilter;

这是 ArchiveSrcFilter 过程中 :ADD_FILTER 绑定变量所在的特定代码段(注意:我已尝试对绑定变量进行不同的串联迭代但没有成功,这只是我在发布之前的最后一次尝试问题在这里):

'CURSOR parm_cur IS '||
'SELECT :seq_val AS ARCHIVE_ID, '||
'A.*, ' ||
'SYSDATE AS ARCHIVE_DATE ' ||
'FROM ' || srcSchemaTable || ' A ' ||
where_sql || ' || :ADD_FILTER ' || ' ; ' ||

以及以最后一个参数作为绑定的EXECUTE IMMEDIATE USING:

EXECUTE IMMEDIATE arc_sql
USING seq_val, parm_rec.SYS_OFFSET, parm_rec.DAY_OFFSET, parm_rec.MON_OFFSET, kNEGATIVE, parm_rec.YR_OFFSET, kANNUM, parm_rec.ADD_FILTER;

parm_rec.ADD_FILTER = AND STATUS = 1062

是否可以通过将绑定连接到 where 来做我正在尝试的事情?

如果我连接 parm_rec.ADD_FILTER 对象变量或硬编码 AND STATUS = 1062,代码将毫无例外地执行,我不明白我收到的奇怪错误消息。

我可以连接parm_rec.ADD_FILTER 来代替绑定变量,并且代码毫无例外地执行,但是我尝试让绑定变量工作没有成功。

感谢任何建议和/或见解。

谢谢!

【问题讨论】:

那部分 -- where_sql || ' || :ADD_FILTER ' || ' ; ' || ——根本没有意义。您正在应用字符串连接 ||到一个合乎逻辑的条件。这行不通。不过,您得到的错误看起来与此无关。 你会认为它是无关的,但它只有在我尝试以我现在的方式使用绑定变量时才会发生。到目前为止,您和@Allen 之间的哪个共识表明它不是正确的使用,也不可能。感谢您的反馈。 【参考方案1】:

没有。列名(即STATUS)和运算符(即AND=)永远无法从绑定变量中解析。

【讨论】:

对象变量parm_rec.ADD_FILTER的使用会受到SQL注入的影响吗?该软件包可能不会与外部网页交互或受制于外部使用;但是,我很好奇在这种情况下 SQL 注入是否是一个潜在问题?感谢您的反馈。 任何时候你将一个 SQL 语句连接在一起,你就有被 SQL 注入的风险。您需要根据应用程序从何处获取用于构造 SQL 的值来确定风险的程度。 DBMS_ASSERT 可用于进一步降低对象和列名称的风险,但没有用于附加比较的内置验证。 任何连接?哪里有双管?我不关心这个特定程序中的 SQL 注入,它仅供内部使用,并且将在没有非 IT 表示层的情况下位于多层安全性后面(例如,数据库开发/管理工具)。我想我只是不太了解 SQL 注入的机制。嗨,去研究我去!感谢您的反馈。 @TheSchnitz 在查询中使用连接很好(即select 'x' || some_column from table)。使用它来构造查询是一个潜在的漏洞(即execute immediate 'select ' || column_name || ' from table')。

以上是关于可以将绑定变量连接到动态 SQL WHERE 子句以添加 AND 语句吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何将字符串变量传递给动态sql中的where子句

在Linq-to-SQL中使用WHERE子句时出错

如何使用动态 WHERE 子句将网格视图绑定到数据源?

MS Access SQL 多个 JOIN 和 WHERE 子句

Pyodbc - 使用 WHERE 子句运行 SQL 查询(语法错误)

where条件放在子SQL语句中是否查询速度更快?