【问题标题】:sql - Unpivot a join between two tables with the same column namessql - 取消透视具有相同列名的两个表之间的连接
【发布时间】:2017-02-13 01:16:38
【问题描述】:

我无法对两个表之间的联接结果进行反透视。这两个表定义为:

create table scores_jan (
   id number
 , test_1 number
 , test_2 number
 , test_3 number
 );

create table scores_feb (
   id number
 , test_1 number
 , test_2 number
 , test_3 number
 );

insert into scores_jan values (1, 50, 60, 70);
insert into scores_feb values (1, 55, 65, 75);
commit;

我想对此进行反透视,为每​​个 ID/测试组合获取一行,以实现结果:

ID    TEST_NUMBER    JAN_SCORE    FEB_SCORE
1     test_1         50           55
1     test_2         60           65
1     test_3         70           75

如果我在未指定我感兴趣的列的情况下编写 unpivot,它看起来像这样:

select *
  from scores_jan j
  join scores_feb f
    on j.id = f.id
unpivot ( (jan_score, feb_score) for test_name in ( (test_1, test_1) as 'test_1'
                                                  , (test_2, test_2) as 'test_2'
                                                  , (test_3, test_3) as 'test_3'
                                                  )
        )

这会产生错误 ORA-00918: column ambiguously defined

如果我尝试通过指定要使用的列来编写它,它看起来像这样:

select *
  from scores_jan j
  join scores_feb f
    on j.id = f.id
unpivot ( (jan_score, feb_score) for test_name in ( (j.test_1, f.test_1) as 'test_1'
                                                  , (j.test_2, f.test_2) as 'test_2'
                                                  , (j.test_3, f.test_3) as 'test_3'
                                                  )
        )

这会产生错误 ORA-01748: only simple column names allowed here

有没有办法让这个 unpivot 工作?我可以将其中一个表放入子查询中,但仅使用子查询来更改列的别名似乎不太理想。

【问题讨论】:

  • 编辑您的问题并显示您想要达到的结果。
  • @GordonLinoff 已添加预期结果。
  • @spielchecker - 您使用的是哪个版本的 Oracle?
  • @GordonLinoff oracle12c

标签: sql oracle


【解决方案1】:
select      *

from        (         select 'JAN_SCORE' as mth,id,test_1,test_2,test_3 from scores_jan s
            union all select 'FEB_SCORE'       ,id,test_1,test_2,test_3 from scores_feb s 
            ) unpivot (score for test in (test_1,test_2,test_3))
              pivot (max(score) for mth in ('JAN_SCORE','FEB_SCORE'))

order by    test   

+----+--------+-----------+-----------+
| ID | TEST   | JAN_SCORE | FEB_SCORE |
+----+--------+-----------+-----------+
| 1  | TEST_1 | 50        | 55        |
+----+--------+-----------+-----------+
| 1  | TEST_2 | 60        | 65        |
+----+--------+-----------+-----------+
| 1  | TEST_3 | 70        | 75        |
+----+--------+-----------+-----------+

【讨论】:

  • PIVOT 有什么用?我没有在问题中看到它。否则,+1 表示不需要加入;在我的书中 THIS 是正确的答案。
  • @mathguy - 检查请求的结果 - JAN 列和 FEB 列
  • 这似乎回答了 OP 的澄清问题。
【解决方案2】:

问题是两个表的列名相同,如果您尝试在 UNPIVOT 中使用别名,它会给出错误提示 - simple names expected

在 Oracle 12c+ 中,使用 OUTER APPLY

select j.id, x.*
  from scores_jan j
  join scores_feb f
    on j.id = f.id
outer apply (
    select 'test_1' test_name, j.test_1 jan_score, f.test_1 feb_score from dual union all
    select 'test_2', j.test_2, f.test_2 from dual union all
    select 'test_3', j.test_3, f.test_3 from dual
) x

在顺序版本中,在子查询中加入,做别名,然后使用UNPIVOT

select * 
from (      
    select 
        j.id,
        j.test_1 j_test_1,
        j.test_2 j_test_2,
        j.test_3 j_test_3,
        f.test_1 f_test_1,
        f.test_2 f_test_2,
        f.test_3 f_test_3
    from scores_jan j
    join scores_feb f
        on j.id = f.id
    ) 
unpivot (
    (jan_score, feb_score) 
    for test_name in (
        (j_test_1, f_test_1) as 'test_1',
        (j_test_2, f_test_2) as 'test_2',
        (j_test_3, f_test_3) as 'test_3'
    )
);

【讨论】:

    【解决方案3】:

    如您所见,问题在于列名不明确。确实有两个问题。一个是id 列。您可以使用不同的连接语法来处理它 - 而不是 on j.id = f.idusing(id)。如果您不熟悉此连接语法,请查看文档。

    但是,test_1 列名的歧义无法通过这种方式解决,并且如您所见,您不能将表限定符与 unpivot 一起使用。

    在这种情况下,正确的解决方案是将整个联接作为子查询(而不仅仅是其中一个表); select from ( join subquery ) unpivot...

    当然,您可以更改表格中的列名(更改为j_test_1f_test_1 等),但这可能太麻烦了。如果你这样做,id 列名在两个表中应该仍然相同,你仍然需要using(id) 语法。

    【讨论】:

      【解决方案4】:

      我不认为“unpivot”是正确的方法。如果每个表中每个id 只有一行,则使用union all 或类似方法。这是一个想法:

      select j.id, j.test_1 as test from scores_jan union all
      select j.id, j.test_2 as test from scores_jan union all
      select j.id, j.test_3 as test from scores_jan union all
      select f.id, f.test_1 as test from scores_feb union all
      select f.id, f.test_2 as test from scores_feb union all
      select f.id, f.test_3 as test from scores_feb ;
      

      您还应该认识到,在不同月份使用不同的表格是一个非常糟糕的想法。您应该将所有数据存储在一个表中,并用一列指定月份。

      【讨论】:

      • UNPIVOT 绝对是正确的答案 - 它只需要读取每个表一次。这种UNION ALL 方法读取每个表三次。
      【解决方案5】:

      附言

      也可以这样解决

      select      id,test,jan_score,feb_score
      
      from                scores_jan j
                  join    (select  id as fid,test_1 as f1,test_2 as f2,test_3 as f3 
                           from    scores_feb
                           ) f
                  on      j.id = f.fid
                  unpivot ((jan_score,feb_score) for (test) in 
                     ((test_1,f1) as 'test_1',(test_2,f2) as 'test_2',(test_3,f3) as 'test_3')) u
      
      order by    test         
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-25
        • 2021-07-08
        • 2016-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多