I'll leave the styling and optimizations to you. Normally I like to identify "groups" or "batches" with a temporary value and keep a rolling tally of the columns' sums as I loop the data. However, because there were so many columns to sum, I changed my mind half way through development and decided to use array_column() and array_sum(). Either technique would be just find, IMO.
As matters of stability/security:
- It's a good idea to check that the expected submission data exists before trying to access the values.
- It's also advisable to perform some level of validation on submitted data. How far you go with that is up to you.
- You need to use a prepared statement because it is a bad idea to allow user-supplied data to go unimpeded into your query.
- When you are done developing/testing your code, be sure to remove the error messages. You mustn't let the public see the error messages because they contain valuable details that malicious actors may exploit.
Tested Code:
$_GET['from'] = '2018-04-01';
$_GET['to'] = '2018-09-18';
$config = ['localhost', 'root', '', 'dbname'];
$sql = "SELECT DATE_FORMAT(stockdate, '%Y-%m') AS batch,
DATE_FORMAT(stockdate, '%e-%c-%Y') AS formatteddate,
particulars,
vch_type,
vch_number,
in_quantity,
in_price_value,
out_quantity,
out_price_value,
cls_quantity,
cls_price_value
FROM tbl_silver_stock
WHERE stockdate BETWEEN ? AND ?
ORDER BY stockdate, particulars";
if (!$conn = new mysqli(...$config)) {
echo "Database Connection Error: $conn->connect_error";
} elseif (!$stmt = $conn->prepare($sql)) {
echo "Prepare Syntax Error: $conn->error";
} elseif (!$stmt->bind_param("ss", $_GET['from'], $_GET['to']) || !$stmt->execute() || !$result = $stmt->get_result()) {
echo "Statement Error: $stmt->error";
} elseif (!$result->num_rows) {
echo "No Rows between {$_GET['from']} and {$_GET['to']}";
} else {
while ($row = $result->fetch_assoc()) {
$results[] = $row; // for grand total
$batch[array_shift($row)][] = $row; // group by year-month value
}
?>
<table border=1>
<tr>
<td rowspan=2>Date</td>
<td rowspan=2>Particulars</td>
<td rowspan=2>Vch Type</td>
<td rowspan=2>Vch No</td>
<td colspan=2>Inwards</td>
<td colspan=2>Outwards</td>
<td colspan=2>Closing</td>
</tr>
<tr>
<td>Quantity</td>
<td>Value</td>
<td>Quantity</td>
<td>Value</td>
<td>Quantity</td>
<td>Value</td>
</tr>
<?php
foreach ($batch as $ym => $rows) {
foreach ($rows as $row) {
echo "<tr>";
echo "<td>{$row['formatteddate']}</td>";
echo "<td>{$row['particulars']}</td>";
echo "<td>{$row['vch_type']}</td>"; // a lookup array or table join is required for these values
echo "<td>" , ($row['vch_number'] == 0 ? '' : $row['vch_number']) , "</td>";
echo "<td>" , ($row['in_quantity'] == 0 ? '' : "{$row['in_quantity']}KG") , "</td>";
echo "<td>" , ($row['in_price_value'] == 0 ? '' : number_format($row['in_price_value'], 2)) , "</td>";
echo "<td>" , ($row['out_quantity'] == 0 ? '' : "{$row['out_quantity']}KG") , "</td>";
echo "<td>" , ($row['out_price_value'] == 0 ? '' : number_format($row['out_price_value'], 2)) , "</td>";
echo "<td>" , ($row['cls_quantity'] == 0 ? '' : "{$row['cls_quantity']}KG") , "</td>";
echo "<td>" , ($row['cls_price_value'] == 0 ? '' : number_format($row['cls_price_value'], 2)) , "</td>";
echo "</tr>";
}
$sum['in_quantity'] = array_sum(array_column($rows, 'in_quantity'));
$sum['in_price_value'] = array_sum(array_column($rows, 'in_quantity'));
$sum['out_quantity'] = array_sum(array_column($rows, 'out_quantity'));
$sum['out_price_value'] = array_sum(array_column($rows, 'out_price_value'));
$sum['cls_quantity'] = array_sum(array_column($rows, 'cls_quantity'));
$sum['cls_price_value'] = array_sum(array_column($rows, 'cls_price_value'));
echo "<tr>";
echo "<td colspan=4>Totals as per \"Default\" valuation:</td>";
echo "<td>" , ($sum['in_quantity'] == 0 ? '' : "{$sum['in_quantity']}KG") , "</td>";
echo "<td>" , ($sum['in_price_value'] == 0 ? '' : number_format($sum['in_price_value'], 2)) , "</td>";
echo "<td>" , ($sum['out_quantity'] == 0 ? '' : "{$sum['out_quantity']}KG") , "</td>";
echo "<td>" , ($sum['out_price_value'] == 0 ? '' : number_format($sum['out_price_value'], 2)) , "</td>";
echo "<td>" , ($sum['cls_quantity'] == 0 ? '' : "{$sum['cls_quantity']}KG") , "</td>";
echo "<td>" , ($sum['cls_price_value'] == 0 ? '' : number_format($sum['cls_price_value'], 2)) , "</td>";
echo "</tr>";
}
$grand['in_quantity'] = array_sum(array_column($results, 'in_quantity'));
$grand['in_price_value'] = array_sum(array_column($results, 'in_price_value'));
$grand['out_quantity'] = array_sum(array_column($results, 'out_quantity'));
$grand['out_price_value'] = array_sum(array_column($results, 'out_price_value'));
$grand['cls_quantity'] = array_sum(array_column($results, 'cls_quantity'));
$grand['cls_price_value'] = array_sum(array_column($results, 'cls_price_value'));
echo "<tr>";
echo "<td colspan=4>Grand Totals as per \"Default\" valuation:</td>";
echo "<td>" , ($grand['in_quantity'] == 0 ? '' : "{$grand['in_quantity']}KG") , "</td>";
echo "<td>" , ($grand['in_price_value'] == 0 ? '' : number_format($grand['in_price_value'], 2)) , "</td>";
echo "<td>" , ($grand['out_quantity'] == 0 ? '' : "{$grand['out_quantity']}KG") , "</td>";
echo "<td>" , ($grand['out_price_value'] == 0 ? '' : number_format($grand['out_price_value'], 2)) , "</td>";
echo "<td>" , ($grand['cls_quantity'] == 0 ? '' : "{$grand['cls_quantity']}KG") , "</td>";
echo "<td>" , ($grand['cls_price_value'] == 0 ? '' : number_format($grand['cls_price_value'], 2)) , "</td>";
echo "</tr>";
echo "</table>";
}
Output:

$fdateand$tdate? Also, is$con_dbcorrect and has an active connection been set up?$to_date = '2018-09-2018';?