PLSQL - 使用规则 table 列为每个记录创建动态字段
PLSQL - Create dynamic field foreach records using rules table columns
我正在寻找构建存储过程 (Oracle 11g) 以将 fact_table(源)中的所有记录(所有字段)插入 target_table(目的地),但它应该创建一个附加字段 "dynamic_key",它将包含一些列的值,由竖线“|”连接。
对于每条记录,"which columns to use to build the dynamic_key"上的信息存储在rule_table.
中
示例(假设所有列都是 VARCHAR2):
fact_table (tech_name, dim1, dim2, dim3, dim4, dim5,其他领域..)
前任。 fact_table('foo', 'time', 'width', 'height', 'volume',
'perimeter', 其他领域.. )
rules_table (tech_name, filed1, field2, field3) 例如。
rules_table('foo', dim2, dim4) 列tech_name用于连接
(f.tecnical_name=r.tecnical_name) 在 fact_table 和 rules_table 之间
获取列。
target_tables (dynamic_key, tecnical_name, dim1, dim2, dim3, dim4,
dim5,其他领域..)
在此示例代码中,存储过程应该:
插入 target_table(dynamic_key, tecnical_name, dim1, dim2, dim3, dim4, dim5, otherfields..)
值(<b>'width|volume'</b>、'foo'、'time'、'width'、'height'、'volume'、'perimeter', 其他领域.. )
我认为最好的方法是使用 CURSOR 和 Dynamic SQL 但是构建起来很麻烦 dynamic_key 而且效率不高:我必须一次处理并插入一条记录。
您可以通过以下方式实现:
- 用
SELECT ... USER_TAB_COLS
枚举所有 table 列以创建 INSERT
的静态部分
- 迭代规则并为
dynamic key
列构建大型 CASE
表达式
- 使用
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;
我正在寻找构建存储过程 (Oracle 11g) 以将 fact_table(源)中的所有记录(所有字段)插入 target_table(目的地),但它应该创建一个附加字段 "dynamic_key",它将包含一些列的值,由竖线“|”连接。
对于每条记录,"which columns to use to build the dynamic_key"上的信息存储在rule_table.
中示例(假设所有列都是 VARCHAR2):
fact_table (tech_name, dim1, dim2, dim3, dim4, dim5,其他领域..) 前任。 fact_table('foo', 'time', 'width', 'height', 'volume', 'perimeter', 其他领域.. )
rules_table (tech_name, filed1, field2, field3) 例如。 rules_table('foo', dim2, dim4) 列tech_name用于连接 (f.tecnical_name=r.tecnical_name) 在 fact_table 和 rules_table 之间 获取列。
target_tables (dynamic_key, tecnical_name, dim1, dim2, dim3, dim4, dim5,其他领域..)
在此示例代码中,存储过程应该:
插入 target_table(dynamic_key, tecnical_name, dim1, dim2, dim3, dim4, dim5, otherfields..)
值(<b>'width|volume'</b>、'foo'、'time'、'width'、'height'、'volume'、'perimeter', 其他领域.. )
我认为最好的方法是使用 CURSOR 和 Dynamic SQL 但是构建起来很麻烦 dynamic_key 而且效率不高:我必须一次处理并插入一条记录。
您可以通过以下方式实现:
- 用
SELECT ... USER_TAB_COLS
枚举所有 table 列以创建INSERT
的静态部分
- 迭代规则并为
dynamic key
列构建大型CASE
表达式 - 使用
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;