【问题标题】:Oracle SQL Query Denormalisation [duplicate]Oracle SQL查询非规范化[重复]
【发布时间】:2013-02-15 04:58:26
【问题描述】:

我正在尝试为新表准备数据,该表与现有表中的数据相同,但已非规范化。我有一个简单的场景,但我的想法是以最有效的方式返回结果

它基于以下简化场景:

Table X   | Table y
id        | id    Identifier  Value
123       | 123   1           A
          | 123   2           B

除了表 X 中的其他字段,我还需要返回我的查询:

123 A B

我考虑过:

解决方案一

select 
id,
(select Value...),
(select Value...)...

解决方案二:

select id,
y1.Value,
y2.Value
from x, y y1, y y2...

解决方案三: 使用 PL/SQL 并遍历游标

解决方案四: 将 y 提取到两个表 identifier1 和 identifier2 中(可能使用触发器)并在查询中加入这些表

由于某种原因,这些解决方案中的每一个都有一个主要缺点,我相信一个词可以让我想起解决这个问题的概念

【问题讨论】:

  • 从您的输出示例来看,您在表 Y 中拥有所有信息。或者您可以通过 id 连接 X 和 Y,并使用 Listagg() 或 WM_Concat (10g) 连接表 Y 中的值,而不是枢轴。不需要 PL/SQL。

标签: sql oracle pivot denormalization


【解决方案1】:

除非我遗漏了什么,否则您正在尝试透视数据。有几种方法可以做到这一点。

您可以使用聚合函数和CASE 表达式:

select x.id,
  max(case when y.identifier = 1 then y.value end) Value1,
  max(case when y.identifier = 2 then y.value end) Value2
from tablex x
left join tabley y
  on x.id = y.id
group by x.id

SQL Fiddle with Demo

根据您的 Oracle 版本,您可以使用 PIVOT 函数:

select id,
  Value1,
  Value2
from
(
  select x.id, y.identifier, y.value
  from tablex x
  left join tabley y
    on x.id = y.id
) 
pivot
(
  max(value)
  for identifier in ('1' as Value1, '2' as Value2)
) piv

SQL Fiddle with Demo

您可以多次加入:

select x.id,
  y1.value Value1,
  y2.value Value2
from tablex x
left join tabley y1
  on x.id = y1.id
  and y1.identifier = 1
left join tabley y2
  on x.id = y2.id
  and y2.identifier = 2

SQL Fiddle with Demo

如果您正在寻找动态解决方案,那么您可以使用 sys_refcursor 创建一个过程:

CREATE OR REPLACE procedure dynamic_pivot(p_cursor in out sys_refcursor)
as
    sql_query varchar2(8000) := 'select x.id ';

    begin
        for x in (select distinct identifier from tabley order by 1)
        loop
            sql_query := sql_query ||
                ' , max(case when y.identifier = '||x.identifier||' then y.value else null end) as Value'||x.identifier;

                dbms_output.put_line(sql_query);
        end loop;

        sql_query := sql_query || ' from tablex x
                                    left join tabley y
                                      on x.id = y.id
                                    group by x.id';
        dbms_output.put_line(sql_query);

        open p_cursor for sql_query;
    end;
/

这些解决方案在每个值的单独列中为您提供结果。如果您想要单列中的数据,则可以使用LISTAGG()

select x.id,
  listagg(y.value, ' ') within group (order by y.id) as Value
from tablex x
left join tabley y
  on x.id = y.id
group by x.id

SQL Fiddle with Demo

【讨论】:

  • 我认为他想要一个任意大小的枢轴(这在 SQL Server 中很容易使用 as XML 技巧)。
  • @Hogan 更新为包含动态解决方案。
  • 很好,现在我知道如何在 oracle 中做到这一点
  • @Hogan 它不像 sql server 那样简单。
  • 我没有花太多时间在 pivot 上,所以会围绕那个区域做一些阅读你的第一反应让我想起了 decode 功能,所以我会根据你的其他建议进行调查并进行一些性能分析select x.id, max(decode(y.identifier, 1, value )), max(decode(y.identifier, 2, value )) from tablex x, tabley y where x.id = y.id group by x。 ID;感谢您的快速回复。
猜你喜欢
  • 2013-02-05
  • 2017-05-09
  • 2016-04-04
  • 1970-01-01
  • 2015-03-30
  • 2011-03-22
  • 1970-01-01
  • 2012-12-31
  • 2018-03-29
相关资源
最近更新 更多