使用配置表的动态SQL

时间:2016-04-01 13:13:45

标签: sql oracle dynamic-sql ansi-sql

我有一个表,其中包含需要创建的动态SQL视图列表

SEEDING_TABLE
-------------
KEYVALUE|VIEW_TO_BE_CREATED|FROMTABLE|NOOFCOLS
1|A|A1|3
2|B|B1|4
3|C|C1|5

另一个表,其中包含上述种子表的实际列名

ORDERCOLS_FORVIEW
KEYVALUE|FROMTABLE|COLSAVAILABLE
1|A1|NUM1
1|A1|NUM2
1|A1|NUM3
2|B1|NUM1
2|B1|NUM2
2|B1|NUM3
2|B1|NUM4
3|C1|NUM1
3|C1|NUM2
3|C1|NUM3
3|C1|NUM4
3|C1|NUM5

表FROMTABLEs的定义如下

A1 -> KEYVALUE|NUM1|NUM2|NUM3
B1 -> KEYVALUE|NUM1|NUM2|NUM3|NUM4
C1 -> KEYVALUE|NUM1|NUM2|NUM3|NUM4|NUM5

在完成所有逻辑和魔术之后,结果应该是一个动态SQL,它应该产生下面的视图语句

DYNAMIC_ENTRIES -> TEXT|TABLE|RANK
TEXT                                                       |TABLE | RANK
CREATE OR REPLACE VIEW A AS SELECT                         | A    | 1
KEYVALUE,                                                  | A    | 2
NUM1 AS KEY1,                                              | A    | 3
NUM1 AS NO1,                                               | A    | 4
NUM1||'|'||NUM2 AS KEY2,                                   | A    | 5
NUM2 AS NO2,                                               | A    | 6
NUM1||'|'||NUM2||'|'||NUM3 AS KEY3,                        | A    | 7
NUM3 AS NO3                                                | A    | 8
FROM A1;                                                   | A    | 9
CREATE OR REPLACE VIEW B AS SELECT                         | B    | 1
KEYVALUE,                                                  | B    | 2
NUM1 AS KEY1,                                              | B    | 3
NUM1 AS NO1,                                               | B    | 4
NUM1||'|'||NUM2 AS KEY2,                                   | B    | 5
NUM2 AS NO2,                                               | B    | 6
NUM1||'|'||NUM2||'|'||NUM3 AS KEY3,                        | B    | 7
NUM3 AS NO3,                                               | B    | 8
NUM1||'|'||NUM2||'|'||NUM3||'|'||NUM4 AS KEY4,             | B    | 9
NUM4 AS NO4                                                | B    | 10
FROM B1;                                                   | B    | 11
CREATE OR REPLACE VIEW C AS SELECT                         | C    | 1
KEYVALUE,                                                  | C    | 2
NUM1 AS KEY1,                                              | C    | 3
NUM1 AS NO1,                                               | C    | 4
NUM1||'|'||NUM2 AS KEY2,                                   | C    | 5
NUM2 AS NO2,                                               | C    | 6
NUM1||'|'||NUM2||'|'||NUM3 AS KEY3,                        | C    | 7
NUM3 AS NO3,                                               | C    | 8
NUM1||'|'||NUM2||'|'||NUM3||'|'||NUM4 AS KEY4,             | C    | 9
NUM4 AS NO4                                                | C    | 10
NUM1||'|'||NUM2||'|'||NUM3||'|'||NUM4||'|'||NUM5 AS KEY5,  | C    | 11
NUM5 AS NO5                                                | C    | 12
FROM C1;                                                   | C    | 13

假设对于种子表中的每个条目,我们都有查找中可用列的完整列表。逻辑是,对于种子表中的每个条目,我们需要将条目插入到最终的动态SQL表中,以使用FROMTABLE为VIEW_TO_BE_CREATED列中的条目创建视图。对于FROMTABLE中具有NUM1 ... NUMn等序列的每一列,它们需要像树一样连接。

我很困惑如何处理这个问题。我们可以创建任意数量的中间表或视图来实现这一目标。任何指针都会非常感激吗?

1 个答案:

答案 0 :(得分:1)

这有点乱,但是您可以在纯SQL中执行此操作,从分层查询开始以获取连接的字符串:

select keyvalue, fromtable, colsavailable, rnk,
  ltrim(sys_connect_by_path(colsavailable, '||''|''||'), '||''|''||') as path
from ordercols_forview
start with rnk = 1
connect by keyvalue = prior keyvalue
and rnk = prior rnk + 1
and prior dbms_random.value is not null
order by keyvalue, fromtable, colsavailable, rnk;

  KEYVALUE FR COLS        RNK PATH                                             
---------- -- ---- ---------- --------------------------------------------------
         1 A1 NUM1          1 NUM1                                              
         1 A1 NUM2          2 NUM1||'|'||NUM2                                   
         1 A1 NUM3          3 NUM1||'|'||NUM2||'|'||NUM3                        
         2 B1 NUM1          1 NUM1                                              
         2 B1 NUM2          2 NUM1||'|'||NUM2                                   
         2 B1 NUM3          3 NUM1||'|'||NUM2||'|'||NUM3                        
         2 B1 NUM4          4 NUM1||'|'||NUM2||'|'||NUM3||'|'||NUM4             
         3 C1 NUM1          1 NUM1                                              
         3 C1 NUM2          2 NUM1||'|'||NUM2                                   
         3 C1 NUM3          3 NUM1||'|'||NUM2||'|'||NUM3                        
         3 C1 NUM4          4 NUM1||'|'||NUM2||'|'||NUM3||'|'||NUM4             
         3 C1 NUM5          5 NUM1||'|'||NUM2||'|'||NUM3||'|'||NUM4||'|'||NUM5  

我认为你的表确实有另一个你没有显示的列给出列位置。如果不是,你可以以某种方式生成 - 可能基于column_id为基表列,按字母顺序或其他。您只需要连接子句的连续数字序列。

然后,您可以使用两个联合来获取这些列和路径值的文本部分(因为它们必须是最终表中的单独行),以及SELECT ...FROM ...的额外行线。每个都需要另一个生成的排名。这些可以从CTE中的排名中生成:

with ordercols_forview_cte as (
  select keyvalue, fromtable, colsavailable, rnk,
    ltrim(sys_connect_by_path(colsavailable, '||''|''||'), '||''|''||') as path
  from ordercols_forview
  start with rnk = 1
  connect by keyvalue = prior keyvalue
  and rnk = prior rnk + 1
  and prior dbms_random.value is not null
)
select 'CREATE OR REPLACE VIEW ' || s.view_to_be_created || ' AS SELECT ' as text,
  s.view_to_be_created, 1 as rnk
from seeding_table s
union all
select 'KEYVALUE,' as text,
  s.view_to_be_created, 2 as rnk
from seeding_table s
union all
select o.path || ' AS KEY' || o.rnk
  || case when o.rnk < s.noofcols then ',' end,
  s.view_to_be_created, (o.rnk * 2) + 1 as rnk
from seeding_table s
join ordercols_forview_cte o on o.keyvalue = s.keyvalue
union all
select o.colsavailable || ' AS NO' || o.rnk
  || case when o.rnk < s.noofcols then ',' end as text,
  s.view_to_be_created, (o.rnk * 2) + 2 as rnk
from seeding_table s
join ordercols_forview_cte o on o.keyvalue = s.keyvalue
union all
select 'FROM ' || o.fromtable || ';' as text,
  s.view_to_be_created, (s.noofcols * 2) + 3 as rnk
from seeding_table s
join ordercols_forview_cte o on o.keyvalue = s.keyvalue
where o.rnk = s.noofcols
order by view_to_be_created, rnk;

您的起始数据生成:

TEXT                                                         V        RNK
------------------------------------------------------------ - ----------
CREATE OR REPLACE VIEW A AS SELECT                           A          1
KEYVALUE,                                                    A          2
NUM1 AS KEY1,                                                A          3
NUM1 AS NO1,                                                 A          4
NUM1||'|'||NUM2 AS KEY2,                                     A          5
NUM2 AS NO2,                                                 A          6
NUM1||'|'||NUM2||'|'||NUM3 AS KEY3                           A          7
NUM3 AS NO3                                                  A          8
FROM A1;                                                     A          9
CREATE OR REPLACE VIEW B AS SELECT                           B          1
KEYVALUE,                                                    B          2
NUM1 AS KEY1,                                                B          3
NUM1 AS NO1,                                                 B          4
NUM1||'|'||NUM2 AS KEY2,                                     B          5
NUM2 AS NO2,                                                 B          6
NUM1||'|'||NUM2||'|'||NUM3 AS KEY3,                          B          7
NUM3 AS NO3,                                                 B          8
NUM1||'|'||NUM2||'|'||NUM3||'|'||NUM4 AS KEY4                B          9
NUM4 AS NO4                                                  B         10
FROM B1;                                                     B         11
CREATE OR REPLACE VIEW C AS SELECT                           C          1
KEYVALUE,                                                    C          2
NUM1 AS KEY1,                                                C          3
NUM1 AS NO1,                                                 C          4
NUM1||'|'||NUM2 AS KEY2,                                     C          5
NUM2 AS NO2,                                                 C          6
NUM1||'|'||NUM2||'|'||NUM3 AS KEY3,                          C          7
NUM3 AS NO3,                                                 C          8
NUM1||'|'||NUM2||'|'||NUM3||'|'||NUM4 AS KEY4,               C          9
NUM4 AS NO4,                                                 C         10
NUM1||'|'||NUM2||'|'||NUM3||'|'||NUM4||'|'||NUM5 AS KEY5     C         11
NUM5 AS NO5                                                  C         12
FROM C1;                                                     C         13

您可以稍微改变它,使用seeding_tableordercols_forview_cte之间的连接进行另一次CTE并将其用于联合。您还可以从递归CTE(来自Oracle 11g)获取路径:

with r (keyvalue, fromtable, colsavailable, rnk, path) as (
  select keyvalue, fromtable, colsavailable, rnk, colsavailable
  from ordercols_forview
  where rnk = 1
  union all
  select ocfv.keyvalue, ocfv.fromtable, ocfv.colsavailable, ocfv.rnk,
    r.path || q'[||'|'||]' || ocfv.colsavailable
  from r
  join ordercols_forview ocfv
  on ocfv.keyvalue = r.keyvalue
  and ocfv.fromtable = r.fromtable
  and ocfv.rnk = r.rnk + 1
)
select * from r;

然后可以使用它;如上所述,这会在另一个CTE中的递归CTE和种子表之间进行连接,但是您只需用递归的CTE替换分层查询CTE:

with r (keyvalue, fromtable, colsavailable, rnk, path) as (
  select keyvalue, fromtable, colsavailable, rnk, colsavailable
  from ordercols_forview
  where rnk = 1
  union all
  select ocfv.keyvalue, ocfv.fromtable, ocfv.colsavailable, ocfv.rnk,
    r.path || q'[||'|'||]' || ocfv.colsavailable
  from r
  join ordercols_forview ocfv
  on ocfv.keyvalue = r.keyvalue
  and ocfv.fromtable = r.fromtable
  and ocfv.rnk = r.rnk + 1
),
combined_cte as (
  select s.keyvalue, s.view_to_be_created, s.noofcols,
    r.fromtable, r.colsavailable, r.rnk, r.path
  from seeding_table s
  join r on r.keyvalue = s.keyvalue
)
select 'CREATE OR REPLACE VIEW ' || c.view_to_be_created || ' AS SELECT ' as text,
  c.view_to_be_created, c.rnk
from combined_cte c
where c.rnk = 1
union all
select 'KEYVALUE,' as text,
  c.view_to_be_created, c.rnk + 1 as rnk
from combined_cte c
where c.rnk = 1
union all
select c.path || ' AS KEY' || c.rnk
  || case when c.rnk < c.noofcols then ',' end,
  c.view_to_be_created, (c.rnk * 2) + 1 as rnk
from combined_cte c
union all
select c.colsavailable || ' AS NO' || c.rnk
  || case when c.rnk < c.noofcols then ',' end as text,
  c.view_to_be_created, (c.rnk * 2) + 2 as rnk
from combined_cte c
union all
select 'FROM ' || c.fromtable || ';' as text,
  c.view_to_be_created, (c.noofcols * 2) + 3 as rnk
from combined_cte c
where c.rnk = c.noofcols
order by view_to_be_created, rnk;

得到相同的结果:

TEXT                                                         V        RNK
------------------------------------------------------------ - ----------
CREATE OR REPLACE VIEW A AS SELECT                           A          1
KEYVALUE,                                                    A          2
NUM1 AS KEY1,                                                A          3
NUM1 AS NO1,                                                 A          4
NUM1||'|'||NUM2 AS KEY2,                                     A          5
NUM2 AS NO2,                                                 A          6
...
NUM1||'|'||NUM2||'|'||NUM3 AS KEY3,                          C          7
NUM3 AS NO3,                                                 C          8
NUM1||'|'||NUM2||'|'||NUM3||'|'||NUM4 AS KEY4,               C          9
NUM4 AS NO4,                                                 C         10
NUM1||'|'||NUM2||'|'||NUM3||'|'||NUM4||'|'||NUM5 AS KEY5     C         11
NUM5 AS NO5                                                  C         12
FROM C1;                                                     C         13