【问题标题】:How to make one column in to more colums如何将一列变成多列
【发布时间】:2015-12-28 06:09:09
【问题描述】:

我有一个关于 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
…

通过选择查询我想实现这个:

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 行的表,我无法更改结构,我需要此查询用于分析目的

【问题讨论】:

标签: mysql sql


【解决方案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;

【讨论】:

  • 当我运行你的解决方案时,它不是累积的,所以在 9 月 21 日的那一行我希望所有用户在此之前都将纽约作为他们的设置中的城市,如果你能举一个动态的例子查询太棒了,我从未使用过准备好的语句
【解决方案2】:

你想要一个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

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

【讨论】:

  • 感谢您帮助我,但我需要将它们放在不同的列中,以便为营销人员制作漂亮的图表;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-13
  • 1970-01-01
相关资源
最近更新 更多