计算温度低于 0 的连续天数
Posted
技术标签:
【中文标题】计算温度低于 0 的连续天数【英文标题】:count consecutive days where temp is below 0 【发布时间】:2014-11-19 18:02:51 【问题描述】:我正在尝试计算我的数据库中温度低于 0 的连续天数。我可以使用选择计数而不是连续天数来获得低于 0 的总天数。然后我希望能够显示第一天和最后一天以及计数。 该表每分钟更新一次。
假设我有一个最小的表,例如:
datetime temp
11/14/2014 7:21:31 -2.4
11/14/2014 7:22:31 -2.4
11/15/2014 5:03:31 2.4
11/15/2014 5:04:31 2.4
11/16/2014 5:10:31 -0.2
11/16/2014 5:11:31 -0.2
11/17/2014 5:13:31 -0.2
11/17/2014 5:14:31 -0.2
11/18/2014 5:15:31 2
11/18/2014 5:16:31 2
在示例中,连续天数为 2,第一个日期为 11/16/2014,最后一个日期为 11/17/2014,总天数(我可以得到)为 3。
感谢收看。
编辑: 我想要最长的连续连胜纪录。至于我是如何获取数据的,这是一个简单的选择语句: 从 mytable 中选择 datetime、temp;
【问题讨论】:
这是 mysql,所以那些不是日期 ;-) 如果有超过一组连续的日子——比如 14-15 和 17-18,会怎样。 是的,我刚刚从样本中导出了日期和时间。这是一个日期时间列。至于你的问题,我正在寻找最长的连续几天,它应该是最早的(按日期计算)。 请相应地修改您的问题。 [另外,要么你想要最早的(日期方面),要么你想要最长的 - 你不能同时拥有(或者只是巧合)] - 你是如何“导出”这些的日期!?!? 【参考方案1】:考虑以下...
数据集...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
( dt datetime NOT NULL PRIMARY KEY
, temp DECIMAL(5,2) NOT NULL);
INSERT INTO my_table VALUES
('2014-11-14 7:21:31', -2.4),
('2014-11-14 7:22:31', -2.4),
('2014-11-15 5:03:31', 2.4),
('2014-11-15 5:04:31', 2.4),
('2014-11-16 5:10:31', -0.2),
('2014-11-16 5:11:31', -0.2),
('2014-11-17 5:13:31', -0.2),
('2014-11-17 5:14:31', -0.2),
('2014-11-18 5:15:31', 2),
('2014-11-18 5:16:31', 2);
解决方案 1 - 如果您只想知道最长运行的长度...
SELECT MAX(@count := IF(a.result = b.result, @count + 1, 1)) LongestRun
FROM
( SELECT DISTINCT DATE(x.dt) date
, COALESCE(y.temp,x.temp) < 0 result
FROM my_table x
LEFT
JOIN my_table y
ON DATE(y.dt) = DATE(x.dt) AND y.temp < 0
) a
CROSS
JOIN (SELECT @count := 0) vars
LEFT
JOIN
( SELECT DISTINCT DATE(x.dt) date
, COALESCE(y.temp,x.temp) < 0 result
FROM my_table x
LEFT
JOIN my_table y
ON DATE(y.dt) = DATE(x.dt) AND y.temp < 0
) b
ON b.date = a.date - INTERVAL 1 DAY
WHERE a.result = 1;
+------------+
| LongestRun |
+------------+
| 2 |
+------------+
解决方案 2 - 如果您还想要一些其他信息
SELECT a.date start
, MIN(c.date) end
, DATEDIFF(MIN(c.date),a.date) + 1 LongestRun
FROM
( SELECT DISTINCT DATE(x.dt) date
, COALESCE(y.temp,x.temp) < 0 result
FROM my_table x
LEFT
JOIN my_table y
ON DATE(y.dt) = DATE(x.dt) AND y.temp < 0
) a
LEFT
JOIN
( SELECT DISTINCT DATE(x.dt) date
, COALESCE(y.temp,x.temp) < 0 result
FROM my_table x
LEFT
JOIN my_table y
ON DATE(y.dt) = DATE(x.dt) AND y.temp < 0
) b
ON b.date = a.date - INTERVAL 1 DAY
AND b.result = 1
LEFT
JOIN
( SELECT DISTINCT DATE(x.dt) date
, COALESCE(y.temp,x.temp) < 0 result
FROM my_table x
LEFT
JOIN my_table y
ON DATE(y.dt) = DATE(x.dt) AND y.temp < 0
) c
ON c.date >= a.date
AND c.result = 1
LEFT
JOIN
( SELECT DISTINCT DATE(x.dt) date
, COALESCE(y.temp,x.temp) < 0 result
FROM my_table x
LEFT
JOIN my_table y
ON DATE(y.dt) = DATE(x.dt) AND y.temp < 0
) d
ON d.date = c.date + INTERVAL 1 DAY
AND d.result = 1
WHERE a.result = 1
AND b.date IS NULL
AND c.date IS NOT NULL
AND d.date IS NULL
GROUP
BY a.date
ORDER
BY LongestRun DESC
LIMIT 1;
+------------+------------+------------+
| start | end | LongestRun |
+------------+------------+------------+
| 2014-11-16 | 2014-11-17 | 2 |
+------------+------------+------------+
对于聚合数据,只需发出单独的查询。
【讨论】:
为您的方法竖起大拇指,它甚至比我的还要快(2 毫秒对 5 毫秒)。【参考方案2】:您需要使用date
字段将您的表连接到自身。像这样的:
SELECT dt, temp FROM
(
SELECT date(t1.`datetime`) as dt, t1.temp
FROM mytable t1 LEFT JOIN mytable AS t2
ON date(t2.`datetime`) = (date(t1.`datetime`)-interval 1 day)
) TMP WHERE temp < 0
【讨论】:
(顺便说一句,保留字列表中明确排除了日期时间 - 但我同意这种观点,如果不是解决方案!)【参考方案3】:使用自定义变量和一些增量逻辑来计算冻结天数(温度低于零)。这应该让你开始
SELECT
t1.endofstreakdate,
IF(t1.freeze > 0, @m := @m + 1, @m := t1.freeze) AS streak
FROM (
SELECT
DATE(t.datetime) AS endofstreakdate,
DAYOFYEAR(t.datetime) AS doy,
MIN(t.temp) AS low,
IF(MIN(t.temp) < 0, @i := @i + 1, @i := @i - @i) AS freeze
FROM (
SELECT
@i := 0,
@m := 0
) v,
temperature t
GROUP BY doy
) t1
LEFT JOIN (
SELECT
DAYOFYEAR(t.datetime) AS doy,
MIN(t.temp) AS low,
IF(MIN(t.temp) < 0, @i := @i + 1, @i := @i - @i) AS freeze
FROM (
SELECT
@i := 0,
@m := 0
) v,
temperature t
GROUP BY doy
) t2
ON t2.doy = t1.doy - 1
这将为您提供所有唯一日期(不含时间)的列表以及温度低于 0 的天数,例如
endofstreakdate streak
2014-11-14 1
2014-11-15 0
2014-11-16 1
2014-11-17 2
2014-11-18 0
您现在可以ORDER BY streak DESC, endofstreakdate ASC LIMIT 1
获取最早出现的最长冻结期(它返回低于零的天数和该期的最后一天)。
【讨论】:
以上是关于计算温度低于 0 的连续天数的主要内容,如果未能解决你的问题,请参考以下文章