我想计算在特定值
之前发生的值的次数以下是我的起始表
+-----------------+--------------+------------+
| 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 |
+-----------------+--------------+------------+--------------+------------+
此表很长,所以我正在寻找一种有效的解决方案。 如果有人有任何想法。
谢谢堆!
答案 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中的一列,这会使得到的代码更快地膨胀。