取消透视列名称


127

我有一张StudentMarks有栏的桌子Name, Maths, Science, English。数据就像

Name,  Maths, Science, English  
Tilak, 90,    40,      60  
Raj,   30,    20,      10

我想像下面这样安排它:

Name,  Subject,  Marks
Tilak, Maths,    90
Tilak, Science,  40
Tilak, English,  60

使用unpivot,我可以正确获取Name,Marks,但无法将源表中的列名获取到Subject所需结果集中的列。

我该如何实现?

到目前为止,我已经到达以下查询(获取名称,商标)

select Name, Marks from studentmarks
Unpivot
(
  Marks for details in (Maths, Science, English)

) as UnPvt

1
您可以张贴您到目前为止所做的事情吗?查询/输出。
哈特CO

Answers:


204

您的查询非常接近。您应该能够使用以下内容,其中包括subject最终选择列表:

select u.name, u.subject, u.marks
from student s
unpivot
(
  marks
  for subject in (Maths, Science, English)
) u;

参见带有演示的SQL Fiddle


@bluefeet有没有一种方法可以使您不需要指定名称(数学,科学,英语)?我正在对许多具有相同结构但具有不同列名的表执行此操作。
LBogaardt

1
@LBogaardt不,您需要显式定义要包括的列。
jjjjjjjjjjj

@LBogaardt在这里看看我的答案,您可以使用动态sql 取消透视,而无需指定列名。
塔林

8

您也可以通过使用带有以下代码的逻辑序列来尝试标准sql取消透视方法。以下代码包含3个步骤:

  1. 使用交叉联接为每一行创建多个副本(在这种情况下,还创建主题列)
  2. 创建“标记”列并使用案例表达式填写相关值(例如:如果主题是科学,则从“科学”列中选择值)
  3. 删除任何空值组合(如果存在,如果基本表中完全没有空值,则可以完全避免使用表表达式)

     select *
     from 
     (
        select name, subject,
        case subject
        when 'Maths' then maths
        when 'Science' then science
        when 'English' then english
        end as Marks
    from studentmarks
    Cross Join (values('Maths'),('Science'),('English')) AS Subjct(Subject)
    )as D
    where marks is not null;

这也适用于任何RDBMS!值,当不可用时,可以用SELECT ... UNION ... SELECT ...子查询代替。尽管对CROSS JOIN的性能感到疑惑...
Cristi S.18.10.18


0

使用交叉联接的另一种方法是在交叉联接中指定列名

select name, Subject, Marks 
from studentmarks
Cross Join (
values (Maths,'Maths'),(Science,'Science'),(English,'English')
) un(Marks, Subject)
where marks is not null;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.