使用基于另一列中的值的查询将mysql表中的列拆分为多列

时间:2016-08-30 06:27:21

标签: mysql sql pivot

我有这张桌子:

Id   name   degree
1    Ahmad  BS
2    John   MA
3    Abed   MA
4    Sami   DR
5    Mona   BS
6    Sara   BS

我想根据程度拆分名称,这样程度就是标题,列中的任何空值都会用NULL填充

并且列中的名称将按Apathetically排序。

结果应该是:

BS      MA    DR
Ahmad   Abed  Sami
Mona    John  NULL
Sara    NULL  NULL

我尝试了什么:

SELECT 
  GROUP_CONCAT(if(degree = 'BS', name, NULL)) AS 'BS',
  GROUP_CONCAT(if(degree = 'MA', name, NULL)) AS 'MA',
  GROUP_CONCAT(if(degree = 'DR', name, NULL)) AS 'DR'
  FROM persons
  GROUP BY name;

但似乎不正确。

2 个答案:

答案 0 :(得分:1)

SET @rn1 := 0, @rn2 := 0, @rn3 := 0;

SELECT MAX(bs) AS `BS`,
       MAX(ms) AS `MS`,
       MAX(dr) AS `DR`
FROM (
    SELECT CASE WHEN degree = 'BS' THEN @rn1 := @rn1 + 1
            WHEN degree = 'MA' THEN @rn2 := @rn2 + 1
            WHEN degree = 'DR' THEN @rn3 := @rn3 + 1
        END AS `Row Number`,
        IF(degree = 'BS', name, NULL) AS `bs`,
        IF(degree = 'MA', name, NULL) AS `ma`,
        IF(degree = 'DR', name, NULL) AS `dr`
    FROM persons
    ORDER BY name
) AS temp
GROUP BY `Row Number`

由于我们希望将原始表中不同行的值放在pivoted表的同一行中,我们可以为每列设置一个单独的行号计数器(在本例中,三个计数器用于三种类型的度数),所以我们可以根据它们的行号将它们全部放在同一行。

在临时表中,我们列出了单独行中的所有值,并使用NULL填充行中的其他单元格。我们还根据度数类型递增计数器。回到外部查询,我们可以使用MAX()(或MIN())函数来显示该列中该特定行号的唯一非NULL值。

我希望这有助于某人。我正在寻找一个几乎完全相同的问题的答案,当我终于找到它时,我决定在StackExchange上注册,所以我可以回答这个问题。 SE社区为我提供了很多次有用的解决方案,这似乎是公平的:)

答案 1 :(得分:0)

select subBS.name as BS,
       subMA.name as MA,
       subDR.name as DR
from (select @rn1:=0, @rn2:=0, @rn3:=0) rn,
    (select name, @rn1:=@rn1+1 as row
    from t
    where degree='BS') subBS
  full outer join
    (select name, @rn1:=@rn1+1 as row
    from t
    where degree='MA') subMA on subBS.row=subMA.row
  full outer join
    (select name, @rn1:=@rn1+1 as row
    from t
    where degree='DR') subDR  on subBS.row=subDR.row

基于人工子查询的另一次尝试,其中行数大于每个子查询

我们将子查询定义为基于表的行数而没有限制,然后跳过空记录

select subBS.name as BS,
       subMA.name as MA,
       subDR.name as DR
from (select @rn:=0, @rn1:=0, @rn2:=0, @rn3:=0) rn,
    (select @rn:=@rn+1 as row
     from t) as main
  left outer join on main.row=subMA.row
    (select name, @rn1:=@rn1+1 as row
    from t
    where degree='BS'
    order by name) subBS
  left outer join
    (select name, @rn2:=@rn2+1 as row
    from t
    where degree='MA'
    order by name) subMA on main.row=subMA.row
  left outer join
    (select name, @rn3:=@rn3+1 as row
    from t
    where degree='DR'
    order by name) subDR on main.row=subDR.row
where subBS.name is not null 
   or subMA.name is not null 
   or subDR.name is not null