计算非连续值

时间:2017-06-09 09:38:05

标签: mysql sql

所以我有以下结构:

+------+---------------+---------------+----+
| guid | current_level | current_value | pk |
+------+---------------+---------------+----+
| a    |           100 |            12 |  1 |
| a    |           200 |            12 |  2 |
| a    |           200 |            12 |  3 |
| a    |           200 |            12 |  4 |
| a    |           200 |            12 |  6 |
| a    |           300 |            14 |  7 |
| a    |           300 |            12 |  9 |
| a    |           300 |            12 | 10 |
| a    |           300 |            14 | 12 |
| b    |           100 |            10 |  5 |
| b    |           100 |            10 |  8 |
| b    |           200 |            12 | 11 |
| b    |           200 |            12 | 13 |
+------+---------------+---------------+----+

我希望计算a和b非连续地达到200级的次数(300次,但现在只有200次) 即我期待的结果:

+------+-------+-------+
| guid | level | times |
+------+-------+-------+
| a    |   200 |     1 |
| b    |   200 |     1 |
+------+-------+-------+

(我不能做到独特,因为200s的单独条纹应分开计算)

当我执行以下操作时:

set @id = "none";
set @lev = 10; -- arbitary non zero starting level

SELECT  guid, current_level , if(@id <> guid, @lev := 10, 0) AS useless, case when @id <> guid then @id := guid else 0 end AS useless2
         , (case when (current_level = 200 AND current_level <> @lev) then 1 else 0 end) as TIMES
        , if(current_level = 200 AND current_level <> @lev, @lev := current_level, 0) AS useless3

 FROM (SELECT * FROM sensor_logs order by guid) as T

我明白了:

+------+---------------+---------+----------+----------+----------+
| guid | current_level | useless | useless2 | TIMES    | useless3 |
+------+---------------+---------+----------+----------+----------+
| a    |           100 |      10 | a        |        0 |        0 |
| a    |           200 |       0 | 0        |        1 |      200 |
| a    |           200 |       0 | 0        |        0 |        0 |
| a    |           200 |       0 | 0        |        0 |        0 |
| a    |           200 |       0 | 0        |        0 |        0 |
| a    |           300 |       0 | 0        |        0 |        0 |
| a    |           300 |       0 | 0        |        0 |        0 |
| a    |           300 |       0 | 0        |        0 |        0 |
| a    |           300 |       0 | 0        |        0 |        0 |
| b    |           100 |      10 | b        |        0 |        0 |
| b    |           100 |       0 | 0        |        0 |        0 |
| b    |           200 |       0 | 0        |        1 |      200 |
| b    |           200 |       0 | 0        |        0 |        0 |
+------+---------------+---------+----------+----------+----------+

所以现在总结TIMES列并按guid分组应该可以解决问题,即:

set @id = "none";
set @lev = 10; -- arbitary non zero starting level

SELECT  guid, current_level , if(@id <> guid, @lev := 10, 0) AS useless, case when @id <> guid then @id := guid else 0 end AS useless2
         , sum(case when (current_level = 200 AND current_level <> @lev) then 1 else 0 end) as TIMES
        , if(current_level = 200 AND current_level <> @lev, @lev := current_level, 0) AS useless3

 FROM (SELECT * FROM sensor_logs order by guid) as T
 GROUP BY guid

但我得到以下内容:

+------+---------------+---------+----------+----------+----------+
| guid | current_level | useless | useless2 | TIMES    | useless3 |
+------+---------------+---------+----------+----------+----------+
| a    |           100 |      10 | a        |        4 |        0 |
| b    |           100 |      10 | b        |        2 |        0 |
+------+---------------+---------+----------+----------+----------+

我不明白为什么总结一个有两个1的列(每个guid一个)导致4和2。

我做错了吗?或者更多地与查询(和求和函数)如何执行的基础机制有关?

1 个答案:

答案 0 :(得分:1)

您的第一个查询最好这样写:

SELECT  guid, current_level , if(@id <> guid, @lev := 10, 0) AS useless, case when @id <> guid then @id := guid else 0 end AS useless2
         , (case when (current_level = 200 AND current_level <> @lev) then 1 else 0 end) as TIMES
        , if(current_level = 200 AND current_level <> @lev, @lev := current_level, 0) AS useless3

 FROM sensor_logs
 , (SELECT @id := 'none', @lev := 10) var_init_subquery
 ORDER BY guid

在需要时,不仅在子查询中明确地进行排序不仅更加干净,在子查询中执行它也可能导致错误的执行计划(这意味着在临时表的情况下性能不佳)。

对于最终结果,您不应该直接应用GROUP BY等。 SELECT(以及因此您的变量和计算)在之后评估。要在计算后进行分组,请将查询放在子查询中:

SELECT guid, SUM(times) FROM (
    SELECT  guid, current_level , if(@id <> guid, @lev := 10, 0) AS useless, case when @id <> guid then @id := guid else 0 end AS useless2
             , (case when (current_level = 200 AND current_level <> @lev) then 1 else 0 end) as TIMES
            , if(current_level = 200 AND current_level <> @lev, @lev := current_level, 0) AS useless3

     FROM sensor_logs
     , (SELECT @id := 'none', @lev := 10) var_init_subquery
     ORDER BY guid
) sq
GROUP BY guid