MySQL - 计数在其他值之间发生的值

时间:2014-02-13 04:06:45

标签: mysql sql count group-by

我想计算在特定值

之前发生的值的次数

以下是我的起始表

+-----------------+--------------+------------+
| Id              | Activity     |  Time      |
+-----------------+--------------+------------+
| 1               | Click        | 1392263852 |
| 2               | Error        | 1392263853 |
| 3               | Finish       | 1392263862 |
| 4               | Click        | 1392263883 |
| 5               | Click        | 1392263888 |
| 6               | Finish       | 1392263952 |
+-----------------+--------------+------------+

我想计算在完成结束之前发生了多少次点击。 我有一个非常迂回的方式来做这个,我写一个函数来找到最后一个 完成活动并查询完成之间的点击次数。 同样重复此错误。

我想要实现的是下表

+-----------------+--------------+------------+--------------+------------+
| Id              | Activity     |  Time      | Clicks       | Error      |
+-----------------+--------------+------------+--------------+------------+
| 3               | Finish       | 1392263862 | 1            | 1          |
| 6               | Finish       | 1392263952 | 2            | 0          |
+-----------------+--------------+------------+--------------+------------+

此表很长,所以我正在寻找一种有效的解决方案。 如果有人有任何想法。

谢谢堆!

4 个答案:

答案 0 :(得分:1)

这是一个复杂的问题。这是解决它的方法。通过为它们分配组标识符,需要将“完成”记录之间的组标识为相同。可以通过计算具有较大id的“完成”记录的数量来计算此标识符。

分配完成后,您可以使用聚合计算结果。

可以使用相关子查询计算组标识符:

select max(id) as id, 'Finish' as Activity, max(time) as Time,
       sum(Activity = 'Clicks') as Clicks, sum(activity = 'Error') as Error
from (select s.*,
             (select sum(s2.activity = 'Finish')
              from starting s2
              where s2.id >= s.id
             ) as FinishCount
      from starting s
     ) s
group by FinishCount;

答案 1 :(得分:1)

利用用户(会话)变量的版本

SELECT MAX(id) id,
       MAX(activity) activity,
       MAX(time) time,
       SUM(activity = 'Click') clicks,
       SUM(activity = 'Error') error
  FROM
(
  SELECT t.*, @g := IF(activity <> 'Finish' AND @a = 'Finish', @g + 1, @g) g, @a := activity
    FROM table1 t CROSS JOIN (SELECT @g := 0, @a := NULL) i
   ORDER BY time
) q
 GROUP BY g

输出:

| ID | ACTIVITY |       TIME | CLICKS | ERROR |
|----|----------|------------|--------|-------|
|  3 |   Finish | 1392263862 |      1 |     1 |
|  6 |   Finish | 1392263952 |      2 |     0 |

这是 SQLFiddle 演示

答案 2 :(得分:0)

尝试:

select      x.id
            , x.activity
            , x.time
            , sum(case when y.activity = 'Click' then 1 else 0 end) as clicks
            , sum(case when y.activity = 'Error' then 1 else 0 end) as errors
from        tbl x, tbl y
where       x.activity = 'Finish'
        and y.time < x.time
        and (y.time > (select max(z.time) from tbl z where z.activity = 'Finish' and z.time < x.time)
         or x.time = (select min(z.time) from tbl z where z.activity = 'Finish'))
group by    x.id
            , x.activity
            , x.time
order by    x.id

答案 3 :(得分:0)

此处为another method of using variables,与@peterm's略有不同:

SELECT
  Id,
  Activity,
  Time,
  Clicks,
  Errors
FROM (
  SELECT
    t.*,
    @clicks := @clicks + (activity = 'Click') AS Clicks,
    @errors := @errors + (activity = 'Error') AS Errors,
    @clicks := @clicks * (activity <> 'Finish'),
    @errors := @errors * (activity <> 'Finish')
  FROM
    `starting` t
  CROSS JOIN
    (SELECT @clicks := 0, @errors := 0) i
  ORDER BY
    time
) AS s
WHERE Activity = 'Finish'
;

与Peter的查询类似的是,这个查询使用的子查询返回所有行,沿途设置一些变量并将变量的值作为列返回。但是,对于大多数使用变量的方法而言,这可能是常见的,这就是这两个查询之间的相似性结束的地方。

区别在于如何计算累积结果。这里所有累积都在子查询中完成,主查询仅过滤Activity = 'Finish'上的派生数据集以返回最终结果集。相比之下,另一个查询使用外层的分组和聚合来获得累积的结果,这可能使它比我的慢。

与此同时,彼得的建议在编码方面更容易扩展。如果您碰巧需要扩展要考虑的活动数量,他的查询只需要以每个新活动向外部SELECT添加一个SUM(activity = '...') AS ...的形式进行扩展,而在我的查询中,您需要添加一个每个新活动的变量和几个表达式,以及外部SELECT中的一列,这会使得到的代码更快地膨胀。