PLSQL - 使用规则表列

时间:2016-12-09 10:27:33

标签: sql plsql oracle11g cursor dynamic-sql

我正在寻找最好的方法(代码最简单,最快速的方法)来构建存储过程(Oracle 11g),将所有记录(所有字段)从fact_table(源)插入到target_table(目标),但它应该创建一个额外的字段" dynamic_key"它将包含某些列的值,由管道" |"连接。

对于每条记录,"用于构建dynamic_key" 的列的信息存储在rule_table中。

示例(假设所有列都是VARCHAR2):

  1. fact_table(tech_name,dim1, dim2 ,dim3, dim4 ,dim5,otherfields ..) 防爆。 fact_table(' foo',' time',' width',' height',' volume', ' perimeter',otherfields ..)

  2. rules_table(tech_name,filed1,field2,field3)Ex。 rules_table(' foo', dim2 dim4 )列tech_name用于加入 fact_table和rules_table之间的(f.tecnical_name = r.tecnical_name) 获得专栏。

  3. target_tables(dynamic_key,tecnical_name,dim1,dim2,dim3,dim4, dim5,otherfields ..)

  4. 在此示例代码中,存储过程应该:

    INSERT INTO target_table(dynamic_key, tecnical_name, dim1, dim2, dim3, dim4, dim5, otherfields..) 
    VALUES('width|volume', 'foo', 'time', 'width' , 'height', 'volume', 'perimeter', otherfields.. )

    我认为最好的方法是使用CURSOR和动态SQL,但是建立dynamic_key非常有效:我必须及时处理和插入一条记录。

1 个答案:

答案 0 :(得分:1)

您可以通过以下方式实现这一目标:

  • 使用SELECT ... USER_TAB_COLS枚举所有表格列,以创建INSERT
  • 的静态部分
  • 迭代规则并为CASE列构建大型dynamic key表达式
  • 使用EXECUTE IMMEDIATE运行生成的语句

完整示例:

create table fact_table (tech_name varchar2(30), dim1 varchar2(30),
  dim2 varchar2(30), dim3 varchar2(30), dim4 varchar2(30),
  dim5 varchar2(30));

insert into fact_table values('foo', 'time', 'width' , 'height', 'volume', 'perimeter');
insert into fact_table values('bar', 'time', 'width' , 'height', 'volume', 'perimeter');
commit;

create table target_table as 
select t1.*, cast(null as varchar2(100)) as dynamic_key
from fact_table t1
where 1=0;  

create table rules_table(tech_name varchar2(30), field1 varchar2(30), field2 varchar2(30),
  field3 varchar2(30));

insert into rules_table values('foo', 'dim2', 'dim4', null);
insert into rules_table values('bar', 'dim1', null, null);
commit;

declare
  CRLF constant varchar2(10) := chr(13) ||chr(10);
  procedure insert_it is
      l_SQL varchar2(4000);
      l_columns varchar2(4000);
    begin
      -- get comma-separated list of columns present in FACT_TABLE
      select listagg(column_name, ',') within group(order by column_name)
      into l_columns
      from user_tab_cols
      where table_name = 'FACT_TABLE';
      -- build INSERT statement
      l_SQL := ' insert into target_table(' || l_columns || ', dynamic_key)' || CRLF ||
               '   select ' || l_columns || ',' || CRLF ||
               '      (case tech_name' || CRLF;
      -- build case branches from rules table
      for cur in (select * from rules_table order by tech_name)
        loop
          l_SQL := l_SQL || ' when ''' || cur.tech_name || ''' then ' ||
                     cur.field1 || (case when cur.field2 is not null then '|| ''|'' ||' || cur.field2 
                                         else null end)
                                || (case when cur.field3 is not null then '|| ''|'' ||' || cur.field3
                                         else null end) || CRLF;
        end loop;
        -- close case statement and add FROM clause
        l_SQL := l_SQL || 'end) from fact_table';                                            
        dbms_output.put_line(l_SQL);
        execute immediate l_SQL;                                      

    end;
begin
  insert_it;
end;