【问题标题】:Get SQL data individually for days between now and 30 days ago单独获取从现在到 30 天前几天的 SQL 数据
【发布时间】:2021-03-24 00:23:21
【问题描述】:

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

【问题讨论】:

  • @Dharman 由于使用 SQL 查询提取的数据是在没有用户直接输入的情况下插入到数据库中的,因此该实例实际上是否需要准备好的语句?
  • 是的,您应该始终使用它们。为什么你会选择不这样做?

标签: php mysql sql datetime recursive-query


【解决方案1】:

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

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

【讨论】:

  • 我会有几天不会接待访问,所以这个方法不起作用吗?有什么办法可以适应有些天来访和有些不来访的日子吗?
  • @Austin:我正在打字,而你正在评论...查看我的更新。
  • 除了重命名“日期”列之外,公用表表达式查询是否可以通过将其插入我当前的查询语句中直接使用,或者是否还必须进行其他更改?跨度>
  • @Austin:递归查询应该做你想做的事(我刚刚在link_id上添加了过滤器,我忘记了。但请注意,这需要 MySQL 8.0。我建议运行查询在将其合并到您的 PHP 代码之前,首先直接在您最喜欢的 SQL 客户端(phpmyadmin 或类似的)中。
  • 我在 MySQL 中测试了查询,然后将其实现到我的代码中,查询工作正常。感谢您的快速解决方案。我已接受您的回答,因为这是最好的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-26
  • 1970-01-01
  • 2020-06-02
  • 2018-02-19
  • 2019-11-15
  • 1970-01-01
相关资源
最近更新 更多