如何将一列放入更多列中

时间:2015-12-27 14:17:20

标签: mysql sql

我对mySQL数据库有一个非常复杂的SQL问题。 我将首先介绍这个问题所需的所有表格:

用户表:

Id  date_created
------------------------------
1   2015-09-19T14:18:07.000Z 
2   2015-09-20T01:16:34.000Z
3   2015-09-21T15:10:21.000Z
…

设置表:

Id  User_id     setting_key     setting_value
----------------------------------------------
1   1           city            1
2   3           city            2
3   2           city            1
…

城市名称表:

Id  name
------------------
1   New York    
2   Los Angeles
3   Boston
…

使用select-query我想实现这个目标:

date            New York    Los Angeles     Boston  …
------------------------------------------------------
2015-09-19      1           0               0   
2015-09-20      2           0               0
2015-09-21      2           1               0
…

对于某个范围内的每个日期,有多少用户设置纽约,洛杉矶,洛杉矶.... 我唯一能做到的就是这个查询:

select date(u.date_created), n.name, count(u.id)
from user u inner join setting s
    on u.id = s.user_id
    and setting_key = 'city'
    inner join name n
    on s.setting_value = n.id
where u.date_created > '2015-09-19T14:18:07.000Z'
group by 1, 2 

然后我得到了这个结果:

date        name        count
-------------------------------
2015-09-19  New York    1
2015-09-19  Los Angeles 0
2015-09-19  Boston      0
2015-09-20  New York    1
2015-09-20  Los Angeles 0
2015-09-20  Boston      0
2015-09-21  New York    0
2015-09-21  Los Angeles 1
2015-09-21  Boston      0
…

每个城市都有行,而不是每个城市的列,这不是累积的。有人知道(复杂的)答案吗?如果问题不明确,请问,实际上这些是50.000行的表,我无法改变结构,我需要这个查询用于分析目的

2 个答案:

答案 0 :(得分:1)

如果您知道城市的名称,只需使用条件聚合:

select date(u.date_created), 
       sum(name = 'New York') as NewYork,
       sum(name = 'Los Angeles' as LosAngeles,
       sum(name = 'Boston') as Boston
from user u inner join
     setting s
     on u.id = s.user_id and
        setting_key = 'institution' inner join
     education_niveau en
     on s.setting_value = en.id
where u.date_created > '2015-09-19T14:18:07.000Z'
group by 1;

如果你不知道城市的名称或者有一个未知的数字,那么你将需要动态SQL - 即构造SQL,准备一个语句,然后执行它。

编辑:

起初并不是很明显这个问题是关于累积计数的。为此,使用变量:

select dte,
       (@ny := @ny + NewYork) as NewYork,
       (@la := @la + LosAngeles) as LosAngeles,
       (@b := @b + Boston) as NewYork
from (select date(u.date_created) as dte, 
             sum(name = 'New York') as NewYork,
             sum(name = 'Los Angeles' as LosAngeles,
             sum(name = 'Boston') as Boston
      from user u inner join
           setting s
           on u.id = s.user_id and
              setting_key = 'institution' inner join
           education_niveau en
           on s.setting_value = en.id
      where u.date_created > '2015-09-19T14:18:07.000Z'
      group by 1
      order by 1
     ) us cross join
     (select @ny := 0, @la := 0, @b := 0) params
order by 1;

答案 1 :(得分:0)

你想要一个pivot,mysql本身不支持它。但是,这可能适合您:

select date, group_concat(concat(name, '=', uid_count)) cities
from (
    select date(u.date_created) date, en.name, count(u.id) uid_count
    from user u
    join setting s on u.id = s.user_id
    join education_niveau en on s.setting_value = en.id
    where u.date_created > '2015-09-19T14:18:07.000Z'
    and setting_key = 'institution'
    group by 1, 2) x
group by 1

将产生如下结果:

date            Cities
------------------------------------------------------
2015-09-19      New York=1   
2015-09-20      New York=2
2015-09-21      New York=2,Los Angeles=1

这种方法的主要优点是返回的城市范围完全基于数据。