mySQL中的交叉表视图?
Posted
技术标签:
【中文标题】mySQL中的交叉表视图?【英文标题】:Crosstab View in mySQL? 【发布时间】:2013-04-14 08:20:15 【问题描述】:我不知道我的标题是否正确,但让我解释一下我在寻找什么。
我有两张桌子。
客户
clID (primary key)
ClName (varchar)
分数
ID (Primay key)
clID (F Key)
PlayDate (Date/Time)
Score (double)
客户表数据如下所示
clID clName
1 Chris
2 Gale
3 Donna
分数表数据如下所示
ID clID PlayDate Score
1 2 23/01/2012 -0.0125
2 2 24/01/2012 0.1011
3 3 24/01/2012 0.0002
4 3 26/01/2012 -0.0056
5 3 27/01/2012 0.0001
6 1 12/01/2012 0.0122
7 1 13/01/2012 0.0053
是否可以创建一个看起来像这样的视图
Date Chris Gale Donna
12/01/2012 0.0122 - -
13/01/2012 0.0053 - -
23/01/2012 - -0.0125 -
24/01/2012 - 0.1011 0.0002
26/01/2012 - - -0.0056
27/01/2012 - - 0.0001
如果以后有另一个新客户,那么我应该能够在现在将在此视图中创建的新列中检查该新客户的数据。
提前致谢。
【问题讨论】:
尝试检查此链接:***.com/questions/2852708/… 或 ***.com/questions/4336985/…。如果行到列的值已知,第一个很好,第二个是您使用 GROUP_CONCAT 但它实际上不会使您的行进入列。 【参考方案1】:这种类型的数据转换称为 PIVOT。 mysql 没有数据透视函数,但您可以使用带有 CASE
表达式的聚合函数来获取结果。
如果提前知道clients
的名称,那么您可以对查询进行硬编码:
select s.playdate,
sum(case when clname = 'Chris' then score end) Chris,
sum(case when clname = 'Gale' then score end) Gale,
sum(case when clname = 'Donna' then score end) Donna
from clients c
inner join scores s
on c.clid = s.clid
group by s.playdate;
见SQL Fiddle with Demo。
如果您有未知数量的客户端,或者您将添加您希望包含的新客户端而无需更改代码,那么您可以使用准备好的语句来生成动态 SQL:
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'sum(CASE WHEN clName = ''',
clName,
''' THEN score else ''-'' END) AS `',
clName, '`'
)
) INTO @sql
FROM clients;
SET @sql
= CONCAT('SELECT s.playdate, ', @sql, '
from clients c
inner join scores s
on c.clid = s.clid
group by s.playdate');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
见SQL Fiddle with Demo。两个查询都会给出相同的结果。
【讨论】:
我在考虑更多的观点。可能存在删除视图并在添加新客户端时重新创建视图的过程。 很棒的把戏,但是大表有很多数据,太重了:/ @Thermech 我同意,对于大量数据,有不同的方法可以做到这一点。【参考方案2】:对于每小时登录的快速“交叉表”概览,我使用:
SELECT _d
, GROUP_CONCAT(LPAD(_cnt,4," ") ORDER BY _h SEPARATOR " ") AS `. 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23`
FROM (
SELECT FROM_UNIXTIME(last_access_epoch,"%Y-%m-%d") AS _d
, FROM_UNIXTIME(last_access_epoch,"%H") AS _h
, COUNT(*) AS _cnt
FROM login_log
WHERE last_access_epoch < 3600*(@@timestamp DIV 3600) /* before current hour */
GROUP BY _d, _h
) AS t
GROUP BY _d
HAVING MIN(_h)="00" /* only full days */
;
【讨论】:
【参考方案3】:如果上述 GROUP_CONCAT 示例的数据量很大,则可能需要更改 group_concat_max_len 以避免由于截断而导致语法错误。
SET SESSION group_concat_max_len=4096;
见:Trouble with GROUP_CONCAT and Longtext in MySQL
【讨论】:
以上是关于mySQL中的交叉表视图?的主要内容,如果未能解决你的问题,请参考以下文章