简体   繁体   English

取消列名相同的两个表之间的联接

[英]sql - Unpivot a join between two tables with the same column names

I am having trouble with unpivoting the results of a join between two tables. 我无法取消两个表之间的联接结果。 The two tables are defined as: 这两个表定义为:

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;

I want to unpivot this to get a row for each ID/test combination, to achieve the result: 我想取消此操作以获取每个ID /测试组合的一行,以实现结果:

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

If I write the unpivot without specifying the columns I'm interested in, it looks like this: 如果我在未指定我感兴趣的列的情况下编写取消透视,则它看起来像这样:

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'
                                                  )
        )

This generates the error ORA-00918: column ambiguously defined 这将产生错误ORA-00918:列定义不明确

If I try to write it with specifying the columns to use, it looks like this: 如果我尝试通过指定要使用的列来编写它,则它看起来像这样:

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'
                                                  )
        )

This generates the error ORA-01748: only simple column names allowed here 这将产生错误ORA-01748:此处仅允许使用简单的列名称

Is there a way to get this unpivot to work? 有没有办法使这个枢纽起作用? I could put one of the tables into a subquery, but it seems pretty suboptimal to use a subquery just for changing the alias of a column. 我可以将其中一个表放入子查询中,但是使用子查询仅用于更改列的别名似乎不太理想。

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        |
+----+--------+-----------+-----------+

The problem, as you saw, is the ambiguous column names. 如您所见,问题在于列名不明确。 There are really two problems. 确实有两个问题。 One is the id column. 一个是id列。 You can deal with it by using a different join syntax - instead of on j.id = f.id write using(id) . 您可以使用其他连接语法来处理它-而不是on j.id = f.idusing(id) Check the documentation for this join syntax if you are not familiar with it. 如果您不熟悉此联接语法,请查阅文档。

However, the ambiguity of the test_1 column name can't be addressed this way, and as you saw, you can't use table qualifiers with unpivot . 但是,无法通过这种方式解决test_1列名称的歧义,并且如您所见,您不能将表限定符与unpivot

The correct solution, in this situation, is to have the entire join as a subquery (not just one of the tables); 在这种情况下,正确的解决方案是将整个连接作为子查询(而不仅仅是表之一); select from ( join subquery ) unpivot...

Of course, you could change the column names in the tables (to j_test_1 , f_test_1 etc.) but that may be too much trouble. 当然,您可以将表中的列名更改(更改为j_test_1f_test_1等),但这可能会带来太多麻烦。 If you go that way, the id column name should still be the same in both tables, and you would still need the using(id) syntax. 如果采用这种方式,则两个表中的id列名称仍应相同,并且仍然需要using(id)语法。

Problem is that the column names are same for the two tables and if you try to use aliases in the UNPIVOT, it'll give error saying - simple names expected . 问题在于两个表的列名相同,并且如果您尝试在UNPIVOT中使用别名,则会给出错误提示- 预期为简单名称

In Oracle 12c+, use OUTER APPLY : 在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

In order versions, do the join in subquery, do aliasing and then use UNPIVOT : 在订单版本中,执行子查询中的联接,进行别名处理,然后使用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'
    )
);

I don't think "unpivot" is the right approach. 我认为“无误”是正确的方法。 If you have only one row per id in each table, then use union all or a similar approach. 如果每个表中的每个id只有一行,请使用union all或类似方法。 Here is the idea: 这里是想法:

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 ;

You should also recognize that using separate tables for separate months is a really bad idea. 您还应该认识到,在单独的月份中使用单独的表确实是个主意。 You should be storing all the data in a single table, with a column specifying the month. 您应该将所有数据存储在一个表中,并在其中指定月份。

Ps 聚苯乙烯

Could also be solved like this 也可以这样解决

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         

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM