2

我需要有关 MySQL 查询的帮助。基本上是为了简化它:

我有一张来自气象站的气象数据表。测量参数之一是降雨量。我设法将计算结果转换为一个表格,其中有一列包含天数(2 月 1 日、2 月 2 日、2 月 3 日等),第二列给出了该特定日期的每日降雨量(0、3.5、14.2 等)。 )。

现在我接下来要做的是计算最长的干燥期和最长的潮湿期。换句话说,连续几天降雨量为 0 的最长时期,潮湿时期正好相反——大多数连续的“非零”天。

在我想要的输出中 - 期间的天数、开始日期和结束日期。所以基本上两个变量,比如说dry_count,dry_date,然后我会将其转换为输出,例如:“天数:dry_count,dry_date”。

我最初将它作为两个变量(dry_start 和dry_end),但这不起作用,因为如果有两个场合,例如最长的时间相同,那么我会想要它作为例如。2 月 3 日 - 2 月 5 日,3 月 8 日 - 3 月 11 日 - 所以最后需要将日期保存为一个变量,如果它不为空,那么它将添加一个逗号和另一个句点。

我尝试了各种方法,但都没有成功。数据是在 PHP 站点上从 MySQL 数据库中提取的,因此我在一段时间的语句中逐行获取结果。请问有什么帮助吗?我希望我解释得很好。

4

3 回答 3

2

如果我理解正确,您是在尝试将有关潮湿期和干燥期的新数据保存回行中,以供以后使用?

我认为这是因为随着每一天的添加,重新计算很容易......或者因为数据正在移动到其他地方?

无论如何,如果是这种情况,那么您可以采取的一种方法是使用两个新列:“wet_count”和“dry_count”。计算每一行。如果该行的湿/干值与前一天的值匹配,然后增加该值。如果没有,请将值归零并将适当的值设置为新值。因此:

day       rainfall    wet_count    dry_count
Feb 1     1           1            0
Feb 2     0.5         2            0
Feb 3     0.75        3            0
Feb 4     0           0            1
Feb 5     0           0            2
Feb 6     0           0            3
Feb 7     0.5         1            0
Feb 8     1.25        2            0
Feb 9     1.5         3            0
Feb 10    3.5         4            0
Feb 11    4.5         5            0

然后,您可以简单地从表中提取最大值,返回到该日期之前该列中的第一个 1,然后您就有了“最大时期”和“开始时间”。

对于每一天的数据,您只需计算与前一天的对比,然后运行两个非常简单的数据库搜索即可获得新的“最大周期”。

更具体地说 - 您提取 'wet_count' 的不同值,按降序排列,并且只取第一个答案。您在数据库上进行选择,其中所有湿计数 = 最大值或 1。您将获得与该特定值匹配的湿期数,以及可能的开始日期。最大值之前的 1 将是开始日期。

于 2013-05-10T13:09:17.470 回答
1

我认为相关子查询在 MySQL 中为此类问题提供了最佳方法。这个想法是在没有下雨的一天之后找到有雨的第一天,并将其用于分组目的。然后该组的最小值和最大值提供了干旱期的边界。

这是想法:

select min(date) as FirstDate, max(date) as LastDate,
       (max(date) - min(date) + 1) as DrySpellDays
from (select t.*,
             (select date
              from t t2
              where t2.rainfall > 0 and
                    t2.date > t.date
              order by t2.date desc
              limit 1
             ) as NextRainDate
      from t
      where t.rainfall = 0
     ) t
group by NextRainDate

连续雨天的计算遵循相同的结构,但逻辑相反:

select min(date) as FirstDate, max(date) as LastDate,
       (max(date) - min(date) + 1) as DrySpellDays,
       sum(t.rainfall) as TotalRainFall
from (select t.*,
             (select date
              from t t2
              where t2.rainfall = 0 and
                    t2.date > t.date
              order by t2.date desc
              limit 1
             ) as NextDryDate
      from t
      where t.rainfall > 0
     ) t
group by NextDryDate
于 2013-05-10T13:08:39.627 回答
0

这是一个未优化的 PHP 尝试。注意:这是未经测试的,我只是在这里输入的,没有要测试的东西,也没有论文来重新考虑这个以做得更好,所以可能会有很多改进。

$dry_date = NULL;
$dry_length = 0;
$wet_date = NULL;
$wet_length = 0;

$current_date = NULL;
$current_length = 0;

$dry_flip = false;
$wet_flip = false;
// assume you get "select date, rainfall from rainfalltable"
while($row = mysqli_fetch_array($result)) {
    // if rainfall is zero we do dry_day calculation
    if ($row['rainfall'] == 0) {
        // two options here - we already started counting or this is a new streak of dry days
        if ($dry_flip) {
            // if we already started, it's simple
            $current_length = $current_length +1;
        } else {
            // if we didn't start counting, let's reset the counter. 
            if ($wet_flip) {
            // First check the wet status - maybe we were counting it so let's save
                $wet_flip = false;
                if ($current_length > $wet_length) {
                    // since we got the longer streak, we update wet status
                    $wet_date = $current_date;
                    $wet_length = $current_length;
                }
                $current_date = NULL;
                $current_length = 0;
            }
            $current_length = $current_length + 1;      
            // One more thing to do         
            if ($current_length == 1) {
                $current_date = $row['date'];
            }
        }

        } else {
        // two options here - we already started counting or this is a new streak of dry days
        if ($wet_flip) {
            // if we already started, it's simple
            $current_length = $current_length +1;
        } else {
            // if we didn't start counting, let's reset the counter. 
            if ($dry_flip) {
            // First check the wet status - maybe we were counting it so let's save
                $dry_flip = false;
                if ($current_length > $wet_length) {
                    // since we got the longer streak, we update wet status
                    $dry_date = $current_date;
                    $dry_length = $current_length;
                }
                $current_date = NULL;
                $current_length = 0;
            }
            $current_length = $current_length + 1;      
            // One more thing to do         
            if ($current_length == 1) {
                $current_date = $row['date'];
            }
        }
    }


}
于 2013-05-10T13:33:47.737 回答