Suming up total amount of fees by year and splitting the data into a table with year on top and total at the bottom

OldPadawan :

Here are the 2 tables structures (minified for a MCVE - they have more rows not needed here):

++++++++++++++++++++++++++++++++ FEES ++++++++++++++++++++++++++++++++++

fee_id +++ fee_amount +++ fee_date   +++ fee_student_ID +++ fee_paid +++

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1      +++  200       +++ 2019-12-05 +++ 1              +++ N       ++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2      +++  200       +++ 2020-01-05 +++ 1              +++ N       ++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3      +++  200       +++ 2020-01-05 +++ 1              +++ N       ++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4      +++  250       +++ 2020-01-05 +++ 2              +++ N       ++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5      +++  250       +++ 2020-02-05 +++ 2              +++ N       ++++

The tables are linked -> fee_student_ID = student_ID

++++++++++++++++++++ STUDENTS +++++++++++++++++++++

student_ID +++ student_name   +++ student_phone +++ 

+++++++++++++++++++++++++++++++++++++++++++++++++++
1          +++ John Doe       +++ 123456789     +++
+++++++++++++++++++++++++++++++++++++++++++++++++++
2          +++ Jane Doe       +++ 987654321     +++

With my SQL query, I can retrieve and order the data (I need only rows where "paid" is late/coming soon). What I need is:

  1. group by year
  2. sum amount by year

I achieve #1 like this (and it works as expected):

$pdo = new PDO("mysql:host=localhost;dbname=$dbname", $adminDBuser, $adminDBpwd);

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);

$stmt = $pdo->prepare(" SELECT tbl_fees.*, tbl_students.*, YEAR(tbl_fees.fee_date) AS yearfee 
FROM tbl_fees, tbl_students 
WHERE tbl_fees.fee_student_ID=tbl_students.student_ID 
AND tbl_fees.fee_paid='N' 
AND tbl_fees.fee_date <= DATE_ADD(NOW(), INTERVAL 7 DAY) 
ORDER BY tbl_fees.fee_date ");

$stmt->execute();

$results = $stmt->fetchAll();

foreach( $results as $row ) {

if ($row['yearfee'] != $yearfee) {
echo "<tr colspan=\"5\" class=\"table-title-year\"><td class=\"table-title-year\">
". $row['yearfee']."
</td></tr>";
//**-- adds a row on top of the list, with the YEAR, and splits the data => OK
}

echo"<tr><td>$fee_id</td><td>",my_formated_date($fee_date),"</td>
<td><a href=\"/student-data.php?id=$student_ID\">$student_name</a></td>
<td>$fee_amount</td><td>$fee_paid</td></tr>\n\r";

}

Now, what I want to add is another, at the bottom of each "year split". This row would show the total amount of unpaid/soon to be paid fees. Like below, which is the expected outcome:

-----------------------------------------
YEAR : 2019
-----------------------------------------
1 --- John Doe --- 2019-12-05 --- 200 ---
-----------------------------------------
TOTAL : 200
-----------------------------------------
YEAR : 2020
-----------------------------------------
2 --- John Doe --- 2020-01-05 --- 200 ---
3 --- Jane Doe --- 2020-01-05 --- 250 ---
4 --- John Doe --- 2020-02-05 --- 200 ---
5 --- Jane Doe --- 2020-02-05 --- 250 ---
-----------------------------------------
TOTAL : 900
-----------------------------------------

How do I achieve the above table, using SQL query or PHP?

I've searched the MySQL (and other related topics in the doc) and this tutorial (amongst others), but can't find a way to adapt it to my case.

I've tested something like this, with a single year or for each known separate year (all throwing errors anyway...):

  • SUM(tbl_fees.fee_amount) FILTER (WHERE EXTRACT(YEAR FROM tbl_fees.fee_date) = 2019) AS yearlySumTotal1
  • SUM(tbl_fees.fee_amount) WHERE EXTRACT(YEAR FROM tbl_fees.fee_date) = '2019' AS yearlySumTot1
ankabot :
<?php
$results = [
    ['id' => 1, 'name' => 'John Doe', 'date' => '2019-12-05', 'amount' => 200],
    ['id' => 2, 'name' => 'John Doe', 'date' => '2020-01-05', 'amount' => 200],
    ['id' => 3, 'name' => 'John Doe', 'date' => '2020-01-05', 'amount' => 250],
    ['id' => 4, 'name' => 'John Doe', 'date' => '2020-02-05', 'amount' => 200],
    ['id' => 5, 'name' => 'John Doe', 'date' => '2020-02-05', 'amount' => 250],
];

$year = '';
$total = 0;

echo '<pre>';
foreach ($results as $row) {
    $rowyear = substr($row['date'], 0, 4);

    if ($year != $rowyear) {
        // avoid displaying in the begining of the table
        if ($total) {
            display_total_row($total);
        }

        display_year_row($rowyear);

        $year = $rowyear;
        $total = 0;
    }

    echo '-----------------------------------------' . PHP_EOL;
    echo sprintf('%d --- %s --- %s --- %s ---', $row['id'], $row['name'], $row['date'], $row['amount']) . PHP_EOL;
    echo '-----------------------------------------' . PHP_EOL;

    $total += $row['amount'];
}

// display last total
display_total_row($total);

echo '</pre>';

function display_year_row($year) {
    echo '-----------------------------------------' . PHP_EOL;
    echo 'YEAR : ' . $year . PHP_EOL;
    echo '-----------------------------------------' . PHP_EOL;
}

function display_total_row($total) {
    echo '-----------------------------------------' . PHP_EOL;
    echo 'TOTAL : ' . $total . PHP_EOL;
    echo '-----------------------------------------' . PHP_EOL;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=350592&siteId=1