从现在到 30 天前的几天分别获取 SQL 数据

Get SQL data individually for days between now and 30 days ago

我正在构建一个分析图表,我需要在其中显示过去 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();        

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

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 table。您通常会使用日历 table - 或者,在 MySQL 8.0 中,您可以使用递归通用 table 表达式即时执行此操作:

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