2

我不知道我的标题是正确的,但让我解释一下我在寻找什么。

我有两张桌子。

客户

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

如果以后有另一个新客户端,那么我应该能够在现在将在此视图中创建的新列中检查该新客户端的数据。

提前致谢。

4

3 回答 3

6

这种类型的数据转换称为 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。两个查询都会给出相同的结果。

于 2013-04-14T15:41:05.420 回答
0

对于每小时登录的快速“交叉表”概述,我使用:

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 */
;
于 2018-07-26T06:33:04.530 回答
0

如果上面的 GROUP_CONCAT 示例有大量数据,则可能需要更改 group_concat_max_len 以避免由于截断而导致语法错误。

SET SESSION group_concat_max_len=4096;

请参阅:MySQL 中 GROUP_CONCAT 和 Longtext 的问题

于 2020-01-02T14:29:43.407 回答