以表名作为参数的动态SQL

时间:2017-04-04 15:38:16

标签: sql oracle plsql dynamic-sql

我正在尝试执行一个过程,我将表名和2个列名称作为参数发送到其中:

EXECUTE IMMEDIATE 'select avg(@column1) from @Table1 where REF_D = @column2' into ATTR_AVG;

我尝试在'@'':''||'的组合中使用变量,但似乎没有任何效果。

是否有人使用表名作为参数。这里有一些解决方案,但对于SQL Server

2 个答案:

答案 0 :(得分:2)

您只能将绑定变量(用冒号表示)用于值,而不能用于结构的某些部分。您必须将表名和列名连接到查询中:

EXECUTE IMMEDIATE 'select avg(' || column1 | ') from ' || Table1 
  || ' where REF_D = ' || column2 into ATTR_AVG;

这意味着REF_D是一个固定的列名,可以出现在您为此调用的任何表格中;在之前的一个似乎是变量的问题中。如果它实际上是一个字符串变量,那么你需要绑定并设置:

EXECUTE IMMEDIATE 'select avg(' || column1 | ') from ' || Table1 
  || ' where ' || column2 || ' = :REF_D' into ATTR_AVG using REF_D;

如果它应该是一个日期,你应该确保本地变量是正确的类型,或者明确地转换它。

答案 1 :(得分:1)

您需要使用||构造可执行语句(或者将其定义为包含占位符的一个字符串,然后可以使用replace进行操作)。类似的东西:

create or replace procedure demo
    ( p_table   user_tab_columns.table_name%type
    , p_column1 user_tab_columns.column_name%type
    , p_column2 user_tab_columns.column_name%type )
is
    attr_avg number;
begin
    execute immediate
        'select avg(' || p_column1 || ') from ' || p_table ||
        ' where ref_d = ' || p_column2
    into attr_avg;

    dbms_output.put_line('Result: ' || attr_avg);
end demo;

首先在调试器友好变量中构建字符串通常是个好主意,例如:

create or replace procedure demo
    ( p_table   user_tab_columns.table_name%type
    , p_column1 user_tab_columns.column_name%type
    , p_column2 user_tab_columns.column_name%type )
is
    attr_avg number;
    sql_statement varchar2(100);
begin
    sql_statement :=
        'select avg(' || p_column1 || ') from ' || p_table ||
        ' where ref_d = ' || p_column2;

    execute immediate sql_statement into attr_avg;

    dbms_output.put_line('Result: ' || attr_avg);
end demo;

根据ref_d的不同,您可能需要小心比较它,因此上述内容可能需要更多工作,但希望它能为您提供这个想法。

编辑:但是请参阅Alex Poole的回答,了解有关绑定变量使用的说明。如果ref_d是可能需要变量的变量:

    sql_statement :=
        'select avg(' || p_column1 || ') from ' || p_table ||
        ' where ' || p_column2 || ' = :b1';

    execute immediate sql_statement into attr_avg using ref_d;

(惯例是将搜索表达式放在右边,例如where name = 'SMITH'而不是where 'SMITH' = name,尽管它们与SQL是相同的。)