我已经阅读了有关数据透视表和将行交换到列的先前帖子,但我无法找到问题的正确答案。我在MySQL下面有表:
+--------+--------+
| Userid | gname |
+--------+--------+
| 12 | AVBD |
| 12 | ASD |
| 12 | AVFD |
| 12 | Aew1 |
| 12 | AVBD32 |
| 12 | ASD23 |
| 12 | AVBDe |
| 12 | ASDer |
| 45 | AVBD |
| 45 | ASD444 |
| 45 | AVBD44 |
| 45 | ASD44 |
| 453 | AVBD22 |
| 453 | ASD1 |
+--------+--------+
我想生成一个有序的数据透视表:
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
| Userid | gname1 | gname2 | gname3 | gname4 | gname5 | gname6 | gname7 | gname8 |
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
| 12 | AVBD | ASD | AVFD | Aew1 | AVBD32 | ASD23 | AVBDe | ASDer |
| 45 | AVBD | ASD444 | AVBD44 | ASD44 | | | | |
| 453 | AVBD22 | ASD1 | | | | | | |
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
gname
的名称是动态的,没有限制。
以下是数据设置以及SQLFiddle http://sqlfiddle.com/#!2/65fec
CREATE TABLE gnames
(`Userid` int, `gname` varchar(6))
;
INSERT INTO gnames
(`Userid`, `gname`)
VALUES
(12, 'AVBD'),
(12, 'ASD'),
(12, 'AVFD'),
(12, 'Aew1'),
(12, 'AVBD32'),
(12, 'ASD23'),
(12, 'AVBDe'),
(12, 'ASDer'),
(45, 'AVBD'),
(45, 'ASD444'),
(45, 'AVBD44'),
(45, 'ASD44'),
(453, 'AVBD22'),
(453, 'ASD1')
;
答案 0 :(得分:3)
如果MySQL支持窗口函数,这将更加容易,因为为每个userid
创建行号不一定是最容易的。我将通过硬编码查询(有限数量的结果)向您展示两种方法,然后我将包含一个使用动态SQL的版本。
为了获得最终结果,您需要gname
中每个userid
的一些序号。这可以通过几种不同的方式完成。
首先,您可以使用相关子查询count
每个用户gname
的数量,然后使用此序列通过{{1}的聚合函数创建新列表达式:
CASE
见SQL Fiddle with Demo。在子查询中,您为每个select
userid,
max(case when gnameNum = 1 then gname else '' end) gname1,
max(case when gnameNum = 2 then gname else '' end) gname2,
max(case when gnameNum = 3 then gname else '' end) gname3,
max(case when gnameNum = 4 then gname else '' end) gname4,
max(case when gnameNum = 5 then gname else '' end) gname5,
max(case when gnameNum = 6 then gname else '' end) gname6,
max(case when gnameNum = 7 then gname else '' end) gname7,
max(case when gnameNum = 8 then gname else '' end) gname8
from
(
select userid,
gname,
(select count(*)
from gnames d
where g.userid = d.userid
and g.gname <= d.gname) as gnameNum
from gnames g
) src
group by userid;
创建一个行号,然后在列创建中使用此新值。相关子查询的问题是您可能会遇到较大数据集的性能问题。
第二种方法是包含用户变量来创建行号。如果gname
与前一行相同,则此代码使用2个变量将前一行与当前行进行比较,并增加行数。同样,您将使用创建的行号将数据转换为新列:
userid
现在,为了动态执行此操作,您需要使用prepared statement。此过程将创建一个sql字符串,您将执行该字符串以获取最终结果。对于此示例,我使用了上面的用户变量查询:
select
userid,
max(case when rownum = 1 then gname else '' end) gname1,
max(case when rownum = 2 then gname else '' end) gname2,
max(case when rownum = 3 then gname else '' end) gname3,
max(case when rownum = 4 then gname else '' end) gname4,
max(case when rownum = 5 then gname else '' end) gname5,
max(case when rownum = 6 then gname else '' end) gname6,
max(case when rownum = 7 then gname else '' end) gname7,
max(case when rownum = 8 then gname else '' end) gname8
from
(
select
g.userid,
g.gname,
@row:=case when @prev=userid then @row else 0 end + 1 as rownum,
@prev:=userid
from gnames g
cross join
(
select @row:=0, @prev:=null
) r
order by userid, gname
) src
group by userid;
见SQL Fiddle with Demo。所有三个版本都会得到以下结果:
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'max(case when rownum = ',
rownum,
' then gname else '''' end) AS `gname',
rownum, '`'
)
) INTO @sql
from
(
select
g.userid,
g.gname,
@row:=case when @prev=userid then @row else 0 end + 1 as rownum,
@prev:=userid
from gnames g
cross join
(
select @row:=0, @prev:=null
) r
order by userid, gname
) src;
SET @sql = CONCAT('SELECT userid, ', @sql, '
from
(
select
g.userid,
g.gname,
@row:=case when @prev=userid then @row else 0 end + 1 as rownum,
@prev:=userid
from gnames g
cross join
(
select @row:=0, @prev:=null
) r
order by userid, gname
) src
group by userid');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
使用动态SQL时要考虑的一件事是MySQL有一个| USERID | GNAME1 | GNAME2 | GNAME3 | GNAME4 | GNAME5 | GNAME6 | GNAME7 | GNAME8 |
|--------|--------|--------|--------|--------|--------|--------|--------|--------|
| 12 | Aew1 | ASD | ASD23 | ASDer | AVBD | AVBD32 | AVBDe | AVFD |
| 45 | ASD44 | ASD444 | AVBD | AVBD44 | | | | |
| 453 | ASD1 | AVBD22 | | | | | | |
的设置长度,如果你创建了很多列,你可能会遇到问题。你想要考虑到这一点。这是另一个处理此MySQL and GROUP_CONCAT() maximum length的问题。