【问题标题】:Oracle Combine several columns into oneOracle 将多列合二为一
【发布时间】:2017-06-16 19:49:35
【问题描述】:

我有一个关于 Oracle Sql 的问题,

如果我有一个名为 A 的数据,有 8 列:

Spot| ID |Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday 
-------------------------------------------------------------------------
   A| 1  | 0.1  |0.15  | ...........................................
-------------------------------------------------------------------------
   A| 2  | 0.2  |0.2   | ...........................................
-------------------------------------------------------------------------
   A| 3  | 0.3  |0.25  | ...........................................
-------------------------------------------------------------------------
   A| 4  | 0.4  |0.4   | ...........................................
-------------------------------------------------------------------------

我可以把它转换成这样的表B吗:

Spot| Day of Week  | ID | Value 
-------------------------------------------------------------------------
   A| 1            | 1  |  0.1 
-------------------------------------------------------------------------
   A| 1            | 2  |  0.2 
-------------------------------------------------------------------------
   A| 1            | 3  |  0.3 
-------------------------------------------------------------------------
   A| 1            | 4  |  0.4 
-------------------------------------------------------------------------
   A| 2            | 1  |  0.15
-------------------------------------------------------------------------
 .......................................................................

将列(周日到周六)组合成一个名为“星期几”的新列

请问我该怎么做?谢谢!

【问题讨论】:

标签: sql oracle row transform


【解决方案1】:

你可以使用UNPIVOT:

Oracle 设置

CREATE TABLE your_table ( spot, id, sunday, monday, tuesday, wednesday, thursday, friday, saturday ) AS
  SELECT 'A', 1, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4 FROM DUAL UNION ALL
  SELECT 'A', 2, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45 FROM DUAL UNION ALL
  SELECT 'A', 3, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5 FROM DUAL;

查询

SELECT *
FROM   your_table
UNPIVOT ( Value FOR Day_of_week IN (
  sunday    AS 1,
  monday    AS 2,
  tuesday   AS 3,
  wednesday AS 4,
  thursday  AS 5,
  friday    AS 6,
  saturday  AS 7
 ) );

输出

S ID DAY_OF_WEEK VALUE
- -- ----------- -----
A  1           1    .1
A  1           2   .15
A  1           3    .2
A  1           4   .25
A  1           5    .3
A  1           6   .35
A  1           7    .4
A  2           1   .15
A  2           2    .2
A  2           3   .25
A  2           4    .3
A  2           5   .35
A  2           6    .4
A  2           7   .45
A  3           1    .2
A  3           2   .25
A  3           3    .3
A  3           4   .35
A  3           5    .4
A  3           6   .45
A  3           7    .5

【讨论】:

    【解决方案2】:

    基本上有三种方法可以做到这一点,每种方法都有其优点和缺点。 (可能不止三个,我知道的就这些。)

    第一种方法使用UNION ALL,适用于小表(性能不重要)。它适用于任何版本的 Oracle。它是这样的:

    select spot, 1 as day_of_week, id, sunday  as value from a union all
    select spot, 2               , id, monday           from a union all
    .......
    

    效率低下,因为基表 (A) 被读取七次,UNION ALL 的每个分支读取一次。有些行可能会被缓存,所以也许不是完全的 I/O 时间乘以 7,但它仍然是低效的。

    从 Oracle 11.1 开始,我们有了 PIVOTUNPIVOT。你需要反透视,像这样:

    select  spot, day_of_week, id, value
    from    a
    unpivot ( value for day_of_week in ( sunday as 1, monday as 2, .... ) )
    ;
    

    这会更快;目前尚不清楚甲骨文是如何在后台实现这一点的,它可能仍然会执行UNION ALL,但这是一个聪明的做法——同一行被使用了七次,而不是从磁盘中重复读取。当然,缺点是它在旧版本的 Oracle 中不可用。

    第三种方法使用笛卡尔连接。它运行速度很快,并且适用于所有版本。

    select a.spot, h.day_of_week, id,
           case h.day_of_week when 1 then sunday
                              when 2 then monday
                              ..................
                              when 7 then saturday
           end  as value
    from   a 
           cross join
           ( select level as day_of_week from dual connect by level <= 7) h
    ;
    

    此解决方案中的子查询h 可能看起来很花哨,但它所做的只是创建一个内联视图h,其中包含一个列day_of_week,其值从1 到7。它可以在任何其他方式,这只是一种快速(且常见)的方式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-28
      • 1970-01-01
      • 1970-01-01
      • 2012-11-08
      • 1970-01-01
      • 2019-09-30
      • 1970-01-01
      相关资源
      最近更新 更多