3

我有一列有两列。一个是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 的频率。

4

5 回答 5

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 链接

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

于 2013-11-08T12:54:41.567 回答
1

据我了解,您每分钟都有一个查询。所以你对性能没有问题。

您可以添加标志:

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

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

于 2013-11-08T12:44:45.447 回答
1

改编自:如何查询多个子记录集中的不同值

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;
于 2013-11-08T12:50:32.980 回答
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;
于 2013-11-08T13:06:16.293 回答
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
于 2013-11-08T12:46:20.457 回答