首页 > 解决方案 > 单独获取从现在到 30 天前几天的 SQL 数据

问题描述

我正在构建一个分析图表,我需要在其中显示过去 30 天内每天的访问次数。我尝试使用下面的循环,但由于在一个请求中发送了 30 个查询,它无法提取某些数据并大大减慢了页面加载时间。

有没有更好的方法来从 MySQL 数据库中获取这些数据,同时节省服务器资源并改善页面的加载时间?任何帮助表示赞赏。

              $conn = new mysqli("localhost", "db_host", "db_pwd", "db_name");
  
              $d2 = date('c', strtotime('-29 days'));

              $date = date("Y-m-d");

              $begin = new DateTime($d2);
              $end = new DateTime($date);
              $end = $end->modify('+1 day');

              $interval = new DateInterval('P1D');
              $daterange = new DatePeriod($begin, $interval ,$end);

              foreach($daterange as $date){

                $current = $date->format("Y-m-d");

                $sql = "SELECT COUNT(*) FROM stats WHERE link_id=$_GET[id] AND date='$current'";
                $result = mysqli_query($conn, $sql);
                if (mysqli_num_rows($result) > 0) {
                  while($row = mysqli_fetch_assoc($result)) { echo $row["COUNT(*)"]; }
                } else { echo "no results";}
              }

              $conn->close();        

标签: phpmysqlsqldatetimerecursive-query

解决方案


如果您每天至少访问一次,则可以使用聚合:

select date(dt) as dt_day, count(*) as cnt_visits
from stats 
where link_id = ? and dt >= current_date - interval 29 day
group by date(dt)
order by dt_day

有一个名为的列date在某种程度上具有误导性(尽管 MySQL 允许这样做)。为了清楚起见,我dt在查询中将列重命名为。

如果有几天没有访问,并且您仍然想显示它们,并显示0访问次数,那么它就有点棘手了。您需要先生成日期,然后left join是表格。您通常会使用日历表 - 或者,在 MySQL 8.0 中,您可以使用递归公用表表达式即时执行此操作:

with recursive cte as (
    select current_date as dt_day
    union all
    select dt_day - interval 1 day from cte where dt_day > current_date - interval 29 day
)
select c.dt_day, count(s.dt) as cnt_visits
from cte c
left join stats s 
    on  s.link_id = ? 
    and s.dt >= c.dt_day 
    and s.dt < c.dt_day + interval 1 day
group by c.dt_day
order by c.dt_day

推荐阅读