使用列名取消透视

Posted

技术标签:

【中文标题】使用列名取消透视【英文标题】:Unpivot with column name 【发布时间】:2013-10-04 01:18:28 【问题描述】:

我有一张表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,我能够正确获取名称、标记,但无法将源表中的列名获取到所需结果集中的Subject 列。

我怎样才能做到这一点?

到目前为止,我已经完成了以下查询(获取姓名、标记)

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

) as UnPvt

【问题讨论】:

你能发布你到目前为止所做的事情吗?查询/输出。 【参考方案1】:

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

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

见SQL Fiddle with demo

【讨论】:

@bluefeet 有没有一种方法可以让您无需指定名称(数学、科学、英语)?我正在对许多表执行此操作,所有表都具有相同的结构但具有不同的列名。 @LBogaardt 不,您需要明确定义要包含的列。 @LBogaardt 看看我的回答here,您可以使用动态 sql 来取消透视,而无需指定列名。【参考方案2】:

您也可以尝试使用以下代码的逻辑序列来尝试标准的 sql 反透视方法。 以下代码有 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! VALUES,当不可用时,可以用带有 SELECT ... UNION ... SELECT ... 的子查询替换 ... 想知道 CROSS JOIN 的性能...【参考方案3】:

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

select name, Subject, Marks 
from studentmarks
Cross Join (
values (Maths,'Maths'),(Science,'Science'),(English,'English')
) un(Marks, Subject)
where marks is not null;

【讨论】:

以上是关于使用列名取消透视的主要内容,如果未能解决你的问题,请参考以下文章

使用 column_name 函数取消透视表

Oracle 11g:取消透视多个列并包含列名

使用数据透视在 Oracle 中显示列名

在 SQL Unpivot 中包含列名

sql 在postgresql中使用动态列名创建交叉表/数据透视表形式的hstore字段

将数据透视到新的列名 - Oracle SQL