【问题标题】:Oracle 10g - flatten relational data dynamicallyOracle 10g - 动态展平关系数据
【发布时间】:2011-04-28 01:53:45
【问题描述】:

我正在使用 Oracle 10g。我有以下关系结构,我认为我需要将其展平,因此在客户端,网格视图显示正确的列数。

可以将下面的 TableA 配置为使用启用字段启用或禁用它的任何一个记录。

TableB 通过字段 fk 存储与 TableA 相关的计算值。对于 docid 1,有为“nm1”和“nmn4”计算的值,但没有为“nm2”计算的值。

我的问题是,对于 TableA 的特定配置,我需要返回一个记录集,该记录集包含 TableA 中已启用记录的完整补充,无论 TableB 中的 docid 是否具有计算值。我希望动态创建的输出如下所示。

有什么想法吗?

TableA
id     nm     enabled
1     'nm1'   1
2     'nm2'   1
3     'nm3'   0
4     'nm4'   1


TableB
id     fk(A.id)     docid     value
1      1            1         .8
2      4            1         .6
3      1            2         .3
4      2            2         .4
5      4            2         .7
6      2            3         .6
7      4            3         .8

Output as records
1     'nm1'     .8       'nm2'     null     'nm4'     .6
2     'nm1'     .3       'nm2'     .4       'nm4'     .7
3     'nm1'     null     'nm2'     .6       'nm4'     .8

【问题讨论】:

  • 你能提供更多关于输出的细节吗?我无法理解它是如何形成的......
  • 我刚刚重新格式化了输出。我想会更清楚。

标签: oracle recordset flatten


【解决方案1】:

我确信有更好的方法来做到这一点,但这就是我想出的。另外,您发布的问题似乎有点模糊,所以我不完全确定我是否正确回答了这个问题。

首先,您需要获取所有可能结果的稀疏表,然后再次连接以获取值。

这将输出作为单列数据。如果不使用动态 SQL 或其他方式创建查询,实际上不可能为每个查询自定义列数。

sys_connect_by_path 用于将多行数据拼接成一行。

with table_a as (
  select 1 as id, 'nm1' as nm, 1 as enabled from dual union all
  select 2 as id, 'nm2' as nm, 1 as enabled from dual union all
  select 3 as id, 'nm3' as nm, 0 as enabled from dual union all
  select 4 as id, 'nm4' as nm, 1 as enabled from dual
),
table_b as (
  select 1 as id, 1 as a_id, 1 as docid, 0.8 as value from dual union all
  select 2 as id, 4 as a_id, 1 as docid, 0.6 as value from dual union all
  select 3 as id, 1 as a_id, 2 as docid, 0.3 as value from dual union all
  select 4 as id, 2 as a_id, 2 as docid, 0.4 as value from dual union all
  select 5 as id, 4 as a_id, 2 as docid, 0.7 as value from dual union all
  select 6 as id, 2 as a_id, 3 as docid, 0.6 as value from dual union all
  select 7 as id, 4 as a_id, 3 as docid, 0.8 as value from dual 
),
cartesian_prod as (
  select b.docid, a.id, a.nm
  from 
    table_a a
    cross join (select distinct docid from table_b) b
  where a.enabled = 1
)
select 
  docid, 
  ltrim(max(sys_connect_by_path(nm || ' ' || value, ', ')), ', ') as value
from (
  select 
    c.docid, 
    c.nm, 
    nvl(to_char(b.value), 'null') as value, 
    row_number() over (partition by c.docid order by c.id) as rown
  from 
    cartesian_prod c 
    left outer join table_b b on (b.docid = c.docid and c.id = b.a_id)
)
start with rown = 1
connect by docid = prior docid and rown = prior rown + 1
group by docid

【讨论】:

    【解决方案2】:

    对我来说,这看起来像是pivot query 的一个亚种。您可以通过将表 B 与表 A 连接起来进行过滤,然后限制启用(类似于select B.* from B, A where B.A_id = A.id and A.enabled = 1)。然后你可以转动它。

    【讨论】:

    • 我使用了您上面提供的链接中的示例,它完全符合我的需要。感谢所有回复的人。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-26
    • 1970-01-01
    • 2011-04-24
    • 2015-04-25
    • 2011-03-05
    • 1970-01-01
    相关资源
    最近更新 更多