如何使用PHP和SQL按月对行进行分组,循环使用月内的天数并跳到下个月

How to group rows by month, loop days inside the month and skip to next month using PHP & SQL

提问人:Tony Chheng 提问时间:3/9/2023 最后编辑:Your Common SenseTony Chheng 更新时间:6/2/2023 访问量:74

问:

嗨,我正在尝试用数据库中的循环实现某些目标,但我没有解决方案。我想我已经接近解决方案,但真的需要帮助。我相信我需要在循环中循环,但不确定如何做到这一点。

如何使用PHP和SQL按月对行进行分组,在月份内循环天数并跳到下个月?

数据如下所示:

Creation_date | Project_name
2023-02-24 | Project A
2023-02-22 | Project B
2023-02-22 | Project C
2023-02-21 | Project..
2023-02-13 | Project..

2023-01-28 | Project..
2023-01-20 | Project..

2022-12-31 | Project..
2022-12-02 | Project..

2022-11-09 | Project..

2022-10-26 | Project..

代码如下

<?php
  $query = '
    SELECT
    Creation_date,
    DATE_FORMAT(Creation_date, "%m") Creation_date_m,
    DATE_FORMAT(Creation_date, "%M") Creation_date_M_full,
    DATE_FORMAT(Creation_date, "%Y") Creation_date_Y_full,
    Project_name
    FROM Projects
    ORDER BY Creation_date DESC
  ';
  $result = $conn->query($query);

  $previousMonth = null;
  $currentMonth = date('m');
?>

<?php while ($row = $result->fetch_assoc()): ?>
  <?php
    $month = $row['Creation_date_m'];
    $monthFull = $row['Creation_date_M_full'];
    $year = $row['Creation_date_Y_full'];

    if (!$previousMonth) {
      $previousMonth = $currentMonth;
    }

    // if there is a change of month, define the class to be set
    if ($month != $previousMonth) {
      $previousMonth = $month;
      $monthName = '<h2>' . $monthFull . ' ' . $year . '</h2>';
    } else {
      $monthName = "";
    }
  ?>

  <div class="month">
    <?= $monthName; ?>
    <div class="day-of-month"><?= $row['Creation_date']; ?></div>
  </div>
<?php endwhile; ?>

现在我的循环输出如下:

<div class="month">
  <h2>February 2023</h2>
  <div class="day-of-month">2023-02-24</div>
</div>

<div class="month">
  <div class="day-of-month">2023-02-22</div>
</div>

<div class="month">
  <div class="day-of-month">2023-02-22</div>
</div>

<div class="month">
  <h2>January 2023</h2>
  <div class="day-of-month">2023-01-28</div>
</div>

<div class="month">
  <div class="day-of-month">2023-01-20</div>
</div>

但是它应该输出如下内容:

<div class="month">
  <h2>February 2023</h2>
  <div class="day-of-month">2023-02-24</div>
  <div class="day-of-month">2023-02-22</div>
  <div class="day-of-month">2023-02-22</div>
</div>

<div class="month">
  <h2>January 2023</h2>
  <div class="day-of-month">2023-01-28</div>
  <div class="day-of-month">2023-01-20</div>
</div>

非常感谢,我希望它很清楚:)

php sql mysqli

评论

1赞 droopsnoot 3/9/2023
每次循环时,您都会输出,而不管月份是否发生了变化。将其移动到设置标题的部分。<div class="month">
0赞 Your Common Sense 3/9/2023
应该作为 stackoverflow.com/questions/7357073/ 的骗子关闭......
0赞 MatBailie 3/9/2023
@YourCommonSense 它很相似,但不是完全重复的。这需要每个月都有一个正面和反面,而不仅仅是月份之间的独立分隔符。如果 OP 已经在苦苦挣扎,我不会认为额外的步骤对他们来说是显而易见的/微不足道的。
0赞 Your Common Sense 3/9/2023
然后@MatBailie在那里写下额外的答案,因此它将对许多来自 Google 的人有所帮助。有一个可靠的答案比各种快速而肮脏的草图要好得多,这些草图带有未经测试的代码和可能的错别字。这就是重复答案的原因
0赞 MatBailie 3/9/2023
@YourCommonSense我从来没有写过php,所以我在一连串糟糕的答案中添加了;)随意编辑它,或者正如你自己所说,写下你自己的答案。

答:

0赞 droopsnoot 3/9/2023 #1

您只需要在月份 div 发生变化时输出它。像这样(未经测试的)代码:

<?php while ($row = $result->fetch_assoc()): ?>
  <?php
    $month = $row['Creation_date_m'];
    $monthFull = $row['Creation_date_M_full'];
    $year = $row['Creation_date_Y_full'];

    // if there is a change of month, define the class to be set
    if ($month != $previousMonth) {
      $monthName = '<div class="month"><h2>' . $monthFull . ' ' . $year . '</h2>';
      $monthEnd = '</div>';
    } else {
      $monthName = "";
      $monthEnd = "";
    }
    echo $monthName; 
    ?>
    <div class="day-of-month"><?= $row['Creation_date']; ?></div>
    <?php
    $previousMonth = $month; // set it here so it changes every time.
    echo $monthEnd;
endwhile; ?>

如果月份发生变化,则包含标题并包含关闭者,否则它们都是空的。$monthName$monthEnd

您无需检查是否为 null,因为它仍然与您从数据库返回的月份不同。您确实需要在每次输出行时更改它,而不仅仅是每次输出标题时。$previousMonth

我不确定是从哪里来的,所以我把它改成了循环内。也许这里有一个错别字。$rowCountTable$row

评论

0赞 Tony Chheng 3/9/2023
嗨,非常感谢,我将测试代码。对于$rowCountTable来说,这是我的错误,应该$row,谢谢!
0赞 Tony Chheng 3/9/2023
它似乎不起作用,你认为我们应该使用嵌套循环吗?就像循环 div.month 一样,我在里面为 div.day-of-month 放了另一个循环?
1赞 MatBailie 3/9/2023
@droopsnot 不要回声月末 每个循环。仅当有一个月的变化时才回显它,除了第一个循环,以及循环结束后的额外时间。
1赞 Your Common Sense 3/9/2023
“例如不要将数据库代码与HTML输出代码混合在一起。并将 HTML 格式化为 HTML,而不是 PHP 字符串,从而造成“一团糟的引号”
1赞 Your Common Sense 3/9/2023
您可以从 MySQL 中获取一个 2-dim 数组,按年月索引,然后使用嵌套循环将其输出到 HTML 中
0赞 MatBailie 3/9/2023 #2

我不是PHP程序员,但基本结构应该是:

  • 从数据库读取下一行
  • 如果行是不同的月份,则写一个 AND a<\div><div>
  • 写入当前数据库行的 div
  • 循环回以读取所有数据库行
  • 写上个月的最终结束 div

上面唯一的警告是确保你在第一个开始 div 之前写完了一个结束 div。

如果我正确理解PHP语法,下面应该这样做。

<?php
  $query = '
    SELECT
    Creation_date,
    DATE_FORMAT(Creation_date, "%m") Creation_date_m,
    DATE_FORMAT(Creation_date, "%M") Creation_date_M_full,
    DATE_FORMAT(Creation_date, "%Y") Creation_date_Y_full,
    Project_name
    FROM Projects
    ORDER BY Creation_date DESC
  ';
  $result = $conn->query($query);

  $previousMonth = "";
  $closeMonth = "";
?>
<?php
  while ($row = $result->fetch_assoc()):
?>
  <?php
    $month = $row['Creation_date_m'];
    $monthFull = $row['Creation_date_M_full'];
    $year = $row['Creation_date_Y_full'];

    // if the month has changed
    // - record the month in previousMonth
    // - close the preceding month, if there was one
    // - open the new month
    if ($month != $previousMonth) {
      $previousMonth = $month;
      echo $closeMonth;
      echo '<div class="month">' ;
      echo '<h2>' . $monthFull . ' ' . $year . '</h2>';
      $closeMonth = '<\div>';
    }
  ?>
    <div class="day-of-month"><?= $row['Creation_date']; ?></div>
<?php
  endwhile;
  echo $closeMonth
?>