Reputation: 11
This is how my table looks like (this is just an example, my table contains a huge amount of rows):
ID | date | transfer | prov |
--------------------------------------------------------------
1 | 2020-08-21 14:13:14 | 2020-08-31 | 100 |
2 | 2020-08-21 14:13:14 | 2020-08-31 | 200 |
3 | 2020-08-21 14:13:11 | 2020-07-29 | 100 |
4 | 2020-08-20 13:05:59 | 2020-08-29 | 50 |
This is my code:
<table>
<thead>
<tr>
<th>Januar</th>
<th>Februar</th>
<th>Mars</th>
<th>April</th>
<th>Mai</th>
<th>Juni</th>
<th>Juli</th>
<th>August</th>
<th>September</th>
<th>Oktober</th>
<th>November</th>
<th>Desember</th>
</tr>
<?php
$res = $link -> query("SELECT SUM(prov) as sum
FROM sales
WHERE YEAR(transfer) = YEAR(CURRENT_DATE())
GROUP BY MONTH(transfer)
ORDER BY MONTH(transfer)");
echo '<tr>';
while( $row = $res->fetch_assoc() ) {
echo "<td>$row[sum]</td>";
}
echo '</tr>';
?>
</thead>
</table>
So this should basically return 250 for August month, 100 for July and 0 for the rest of the months. But when using this only the cell Januar and Februar displays the value, and the other cells is not there. What am I doing wrong?
This is how it looks like live: https://ibb.co/8bd6JWP (the 12750 has transfer date in August, not January, so all cells should have value 0, but August should have 12750)
Upvotes: 0
Views: 185
Reputation: 12036
Try something like this (a bit cleaner and more understandable solution):
<?php
$months = array(
1 => 'Januar',
2 => 'Februar',
3 => 'Mars',
4 => 'April',
5 => 'Mai',
6 => 'Juni',
7 => 'Juli',
8 => 'August',
9 => 'September',
10 => 'Oktober',
11 => 'November',
12 => 'Desember');
?>
<table>
<thead>
<tr>
<?php
foreach($months as $month)
echo "<th>$month</th>";
?>
</tr>
<?php
$res = $link -> query("SELECT MONTH(transfer) as month, SUM(prov) as sum
FROM sales
WHERE YEAR(transfer) = YEAR(CURRENT_DATE())
GROUP BY MONTH(transfer)
ORDER BY MONTH(transfer)"); // you don't need to order the results anymore
$results = array();
while($row = $res->fetch_assoc()){
$results[$row['month']] = $row['sum'];
}
echo '<tr>';
foreach($months as $m_id => $month){
if(isset($results[$m_id]))
echo "<td>".$results[$m_id]."</td>";
else
echo "<td>0</td>";
}
echo '</tr>';
?>
</thead>
</table>
Upvotes: 1
Reputation: 108676
Keep in mind that SQL handles sets of data rows. Your sample data and query generate a set of two rows of data. And, your php code reads that set and generates a <td>nnn</td>
HTML table column for each row in your set. There's only two of them. Hence only two columns in your HTML table. That's WHY your code doesn't do what you want. This db-fiddle. https://www.db-fiddle.com/f/nfv5wDnBWWgP8dq8E26QtZ/0 demonstrates.
The more interesting question: how do you get it to work? It's surprisingly tricky until you get used to it. There are various solutions. My favorite is to use a query that generates the set of twelve rows you want and then LEFT JOINs your actual data to that set.
MONTH(sometdate)
generates integers in the range [1-12]. So if you can use a set of those twelve integers in your query you'll have what you want.
Try this.
SELECT SUM(prov) as sum
FROM seq_1_to_12
LEFT JOIN sales ON seq_1_to_12.seq = MONTH(transfer)
AND YEAR(transfer) = YEAR(CURRENT_DATE())
GROUP BY seq_1_to_12.seq
ORDER BY seq_1_to_12.seq
If you use the MariaDB variant of MySQL, that mysterious table seq_1_to_12
is already defined for you. Hooray. Otherwise, you need to define it yourself in your query. A good way is this. https://www.db-fiddle.com/f/nfv5wDnBWWgP8dq8E26QtZ/1
SELECT seq_1_to_12.seq, IFNULL(SUM(prov),0) as sum
FROM (
SELECT 1 AS seq UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL
SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL
SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL
SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12
) seq_1_to_12
LEFT JOIN sales ON seq_1_to_12.seq = MONTH(transfer)
AND YEAR(transfer) = YEAR(CURRENT_DATE())
GROUP BY seq_1_to_12.seq
ORDER BY seq_1_to_12.seq
Notice some things about this.
IFNULL(SUM(prov,0))
makes the result set show zeros for your missing months' data rather than nulls. It makes your report a little cleaner.YEAR(transfer) = YEAR(CURRENT_DATE())
in the ON
clause of your LEFT JOIN
rather than in a WHERE
clause. Why? When a WHERE clause (or ORDER BY or GROUP BY clause) mentions a column in a LEFT JOINed table, it converts the LEFT JOIN to an ordinary inner JOIN. Inner JOIN operations suppress rows from the right side of the JOIN; LEFT JOINs preserve them.GROUP BY
and ORDER BY
your sequence values.I wrote up an article about this a while ago.
Upvotes: 1
Reputation: 5224
You aren't checking the returned values. You need to select
the month in addition to the aggregated values. You then can check if the month your on is the month you have values. I would select all your values first, put them in an array, then iterate over the months and check the array to see if it has values.
Rough idea:
$monthdata = array(7 => 10, 8 => 22 );
for($x =1; $x <= date('n'); $x++){
echo date('F', strtotime('2020-' . $x . '-01')) . PHP_EOL;
if(!empty($monthdata[$x])) {
echo $monthdata[$x];
} else {
echo 0;
}
echo PHP_EOL;
}
and change the query to:
SELECT SUM(prov) as sum, MONTH(transfer) as month
so you can use $row['month']
. The $monthdata
should be built as:
$monthdata[$row['month']] = $row['sum'];
during iteration of the select.
Upvotes: 1