简体   繁体   English

交叉表中的Group_Concat

[英]Group_Concat in Crosstab

With a table like: 用这样的表:

Name   Event     Time
Steve  Start    19:53
Steve  Event1   19:51
Steve  Stop     19:45
Steve  Start    18:13
Steve  Event2   18:01
Steve  Event1   17:51
Steve  Stop     17:45
Bob    Start    19:47
Bob    Event2   19:31
Bob    Stop     17:57

representing events that occur between start and stops times. 代表在开始时间和停止时间之间发生的事件。 I'd like to turn this into: 我想把它变成:

Name    Start   Stop   Event1    Event2
Steve  19:53    19:45    1         0
Steve  18:13    17:45    1         1
Bob    19:47    17:57    0         1

My attempt: 我的尝试:

select
    name,
    (CASE event WHEN 'start' THEN time ELSE NULL END) AS Start,
    (CASE event WHEN 'stop' THEN time ELSE NULL END) AS Stop,
    (CASE event WHEN 'event1' THEN 1 ELSE 0 END) AS Event1,
    (CASE event WHEN 'event2' THEN 1 ELSE 0 END) AS Event2
from atable

which results in: 结果是:

Name    Start   Stop    Event1  Event2
Steve   19:53   0   0   0
Steve   0   0   1   0
Steve   0   19:45   0   0
Steve   18:13   0   0   0
Steve   0   0   0   1
Steve   0   0   1   0
Steve   0   17:45   0   0
Bob 19:47   0   0   0
Bob 0   0   1   0
Bob 0   17:57   0   0

How do I get the records in a single row? 如何单行获取记录?

I did try a Group_CONCAT per: 我确实尝试了一个Group_CONCAT:

select
    name,
    GROUP_CONCAT((CASE event WHEN 'start' THEN time ELSE 0 END)) AS Start,
    GROUP_CONCAT((CASE event WHEN 'stop' THEN time ELSE 0 END)) AS Stop,
    GROUP_CONCAT((CASE event WHEN 'event1' THEN 1 ELSE 0 END)) AS Event1,
    GROUP_CONCAT((CASE event WHEN 'event2' THEN 1 ELSE 0 END)) AS Event2
from atable
group by name, event

But ended up with: 但最终导致:

Name    Start   Stop    Event1  Event2
Bob 0   0   1   0
Bob 19:47   0   0   0
Bob 0   17:57   0   0
Steve   0,0 0,0 1,1 0,0
Steve   0   0   0   1
Steve   19:53,18:13 0,0 0,0 0,0
Steve   0,0 19:45,17:45 0,0 0,0

And now tested: Working SQL FIDDLE 并经过测试:有效的SQL FIDDLE

How do I get the records in a single row? 如何单行获取记录?

Max or min would combine the rows, but since name isn't unique enough we need a 2nd way to identify the group within the group which would result in a 2nd row in your output. 最大值或最小值将合并行,但是由于名称不够唯一,我们需要第二种方法来标识组中的组,这将在输出中导致第二行。 We can do this using user variables on the event start and a counter. 我们可以在事件开始和计数器上使用用户变量来执行此操作。

This assumes: 假设:

  1. Ordering by time desc will retain the needed order 按时间顺序排序将保留所需的订单
  2. Multiple occurrences of 'start' in an event for the same user denote a new row needed in result. 同一用户在event多次出现“开始”表示结果中需要新的一行。
  3. Start will always have the lowest time for each set to become a row. 对于每个组来说,开始总是具有最短的时间成为一行。

.

***DDL***
CREATE table atable (
  name varchar(10),
  `event` varchar(10),
  `time` time);

INSERT into atable values 
('Steve',  'Start',    '19:53'),
('Steve',  'Event1',   '19:51'),
('Steve',  'Stop',     '19:45'),
('Steve',  'Start',    '18:13'),
('Steve',  'Event2',   '18:01'),
('Steve',  'Event1',   '17:51'),
('Steve',  'Stop',     '17:45'),
('Bob',    'Start',    '19:47'),
('Bob',    'Event2',   '19:31'),
('Bob',    'Stop',     '17:57');

***DML***
SELECT
    name,
    max(CASE event WHEN 'start' THEN time ELSE NULL END) AS Start,
    max(CASE event WHEN 'stop' THEN time ELSE NULL END) AS Stop,
    max(CASE event WHEN 'event1' THEN 1 ELSE 0 END) AS Event1,
    max(CASE event WHEN 'event2' THEN 1 ELSE 0 END) AS Event2
FROM (SELECT A.*, CASE WHEN @Name=Name and Event = 'Start' THEN @GRP:=@GRP+1
                       WHEN @Name <> Name THEN @GRP:=@GRP+1
                       ELSE @GRP
                  end as mGROUP,
                  CASE WHEN @Name <> NAME then 
                       @Name:=Name
                  END  as Name2
      FROM  atable A
      CROSS JOIN (Select @GRP:=0) x
      CROSS JOIN (Select @Name:='') y
      ORDER BY Name, Time Desc) z
GROUP BY Name, mGROUP

How this works: The inner query "Z" adds two columns, mGROUP and Name2 to your base data set "atable". 工作原理:内部查询“ Z”将两行mGROUP和Name2添加到基本数据集“ atable”中。 The Database engine initializes variables @GRP and @NAME via a cross join. 数据库引擎通过交叉联接初始化变量@GRP和@NAME。 We need @GRP so we can group each sub set of data together from atable to make it easier to combine the data. 我们需要@GRP,因此我们可以将每个子数据组从一起分组,以使合并数据更加容易。 This column represents the missing group by we need in order to use min/max to combine the rows in your pivot. 为了使用最小/最大组合您的数据透视图中的行,此列表示缺少的组。

The @Name variable is used as a control break method so we know when to increment the @grp counter. @Name变量用作控制中断方法,因此我们知道何时增加@grp计数器。 This value is reset in the Name2 column when the names vary. 名称不同时,将在“名称2”列中重置此值。 There are two times the @grp counter needs to be incremented. @grp计数器有两次需要增加。 Once is when a 'Start' event is encountered, once is when @Name changes. 一次是遇到“开始”事件,一次是@Name更改。 The mGROUP column does this increment for us and when no increment is needed, the same value is output as it's part of the same group. mGROUP列为我们执行此增量,并且在不需要增量时,将输出相同的值,因为它属于同一组。 (To see this work just run the inner query "Z" and evaluate the results) (要查看此工作,只需运行内部查询“ Z”并评估结果)

Now that we have the needed grouping mechanism to combine the groups using max, we can use simple aggregation to combine the rows which is done via the outer query. 现在,我们有了使用max组合组所需的分组机制,我们可以使用简单的聚合来组合通过外部查询完成的行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM