计算mysql表中从0到1的值变化

时间:2013-11-08 12:25:21

标签: mysql select

我有一个包含两列的列。一个是TIMESTAMP,另一个是DIGITAL_BIT

值数字位可以是0或1,并在白天更改几次。一天中的每一分钟都存储在此表中。我需要以某种方式阅读一天这个值从0变为1的次数。

是否可以创建一个返回此更改计数的查询?我的想法是这样的:

select * from mytable where digital_bit = 1 and digital_bit (of previous row) = 0 order by timestamp

这可以通过查询完成,还是我必须处理程序中的所有数据?

由于

样品

timestamp | digital_bit

100000    | 0
100001    | 0
100002    | 1
100003    | 1
100004    | 0
100005    | 1
100006    | 0
100007    | 0
100008    | 1

以上应该返回3,因为数字值从0传递到1的3倍。我需要计算数字值从0变为1的频率。

5 个答案:

答案 0 :(得分:3)

你走了。这将使您计算digital_bit从0切换到1的次数(在您的示例中,这将返回3)。

SELECT COUNT(*)
FROM mytable curr
WHERE curr.digital_bit = 1
AND (
    SELECT digital_bit
    FROM mytable prev
    WHERE prev.timestamp < curr.timestamp
    ORDER BY timestamp DESC
    LIMIT 1
) = 0

SQLFiddle link

(原始答案依赖于顺序的时间戳:例如,没有从100001跳转到100003.答案现在已经更新,没有限制。)

答案 1 :(得分:1)

这对于大量数据来说不太可能有效,但是您可以获取所有行并计算它们的序列号,然后再次执行相同操作,但序列号偏移1.然后加入2这些计算出的序列号匹配但是第一个的数字位为0而另一个的数字位为1: -

SELECT COUNT(*)
FROM
(
    SELECT mytable.timestamp, mytable.digital_bit, @aCount1:=@aCount1+1 AS SeqCount
    FROM mytable 
    CROSS JOIN (SELECT @aCount1:=1) sub1
    ORDER BY timestamp
) a
INNER JOIN
(
    SELECT mytable.timestamp, mytable.digital_bit, @aCount2:=@aCount2+1 AS SeqCount
    FROM mytable 
    CROSS JOIN (SELECT @aCount2:=0) sub1
    ORDER BY timestamp
) b
ON a.SeqCount = b.SeqCount
AND a.digital_bit = 0
AND b.digital_bit = 1

编辑 - 替代解决方案,我很想知道这是如何表现的。它避免了添加序列号的需要,也避免了相关的子查询: -

SELECT COUNT(*)
FROM
(
    SELECT curr.timestamp, MAX(curr2.timestamp) AS MaxTimeStamp
    FROM mytable curr
    INNER JOIN mytable curr2
    ON curr.timestamp > curr2.timestamp
    AND curr.digital_bit = 1
    GROUP BY curr.timestamp
) Sub1
INNER JOIN mytable curr
ON Sub1.MaxTimeStamp = curr.timestamp
AND curr.digital_bit = 0

答案 2 :(得分:1)

改编自:How do I query distinct values within multiple sub record sets

select count(*)
from (select t1.*,
             (select digital_bit
              from table t2
              where t2.timestamp < t1.timestamp
              order by timestamp desc LIMIT 1
             ) as prevvalue
      from table t1
     ) t1
where prevvalue <> digital_bit and digital_bit = 1;

答案 3 :(得分:1)

如果每分钟有一次结果,你可以简单地将表连接到自己,并且 使用timestamp + 1以及leftbit!= rightbit作为连接条件。

http://sqlfiddle.com/#!8/791c0/6

所有变更:

SELECT 
  COUNT(*)
FROM 
  test a
INNER JOIN
  test b
ON 
  a.digital_bit != b.digital_bit
  AND b.timestamp = a.timestamp+1;

从0变为1

SELECT 
  COUNT(*)
FROM 
  test a
INNER JOIN
  test b
ON 
  a.digital_bit = 0 AND
  a.digital_bit != b.digital_bit
  AND b.timestamp = a.timestamp+1;

从1更改为0

SELECT 
  COUNT(*)
FROM 
  test a
INNER JOIN
  test b
ON 
  a.digital_bit = 1 AND
  a.digital_bit != b.digital_bit
  AND b.timestamp = a.timestamp+1;

答案 4 :(得分:0)

据我所知,你每分钟都有一个查询。所以你对性能没有任何问题。

您可以添加标记:

timestamp | digital_bit | changed

100000    | 0           | 0
100001    | 0           | 0
100002    | 1           | 1
100003    | 1           | 0
100004    | 0           | 1
100005    | 1           | 1
100006    | 0           | 1
100007    | 0           | 0
100008    | 1           | 1

在插入之前进行检查:

SELECT digital_bit
FROM table
ORDER BY timestamp DESC
LIMIT 1

如果digital_bit不同,请插入带有标记的新行。

然后你就可以拿COUNT个旗帜:

SELECT COUNT(*)
FROM table
WHERE DATE BETWEEN (start, end)
      AND changed = 1

希望能在答案中看到更好的解决方案。