2

I am trying to get output as below image:

enter image description here

Below is my table structure and entries:

enter image description here

I have tried with below query:

$from_date = '2018-04-01';  
$to_date = '2018-09-01';  

$cid = mysqli_query($con_db,"SELECT * FROM tbl_silver_stock WHERE stockdate between '$from_date' and '$to_date'");

I am having issue with how to check month is complete and get the total values of columns.

Please help me.

5
  • Your query should work as expected -- what are $fdate and $tdate? Also, is $con_db correct and has an active connection been set up? Commented Oct 22, 2018 at 21:47
  • @ObsidianAge Yes query is working fine, but I can't check one month is complete. Commented Oct 22, 2018 at 21:48
  • @mageDev0688 is that a typo $to_date = '2018-09-2018'; ? Commented Nov 1, 2018 at 10:53
  • @Ingus Yes, this date will be enter by user using bootstrap datepicker Commented Nov 1, 2018 at 11:04
  • '2018-09-2018' is not a valid date Commented Nov 5, 2018 at 7:13

3 Answers 3

1
+50

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:

  1. It's a good idea to check that the expected submission data exists before trying to access the values.
  2. It's also advisable to perform some level of validation on submitted data. How far you go with that is up to you.
  3. You need to use a prepared statement because it is a bad idea to allow user-supplied data to go unimpeded into your query.
  4. 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:

enter image description here

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for the solution, I have gone through this but I have seen you can't added theTotal as per "Default" valuation: after complete the month.
@mageDev0688 I've fixed my typos ($row needed to be $rows) and I changed the stockdate alias so that the ORDER BY worked as intended. If the format of the KG and Value data isn't perfect, I trust that you can tidy that part up.
thanks let me try and after complete, I'll accept your answer.
thank you so much for your solution. You have described everything with the solution and I get new concept with this.
Yes, I gave you now, please check.
1

I've approached this as a standard reporting problem. The idea being

  • read in each row from the database,
  • check to see if the month has changed and put out month totals and accumulate overall totals,
  • output row data,
  • accumulate month totals

at the end of data

  • output the last months totals,
  • output overall totals.

Other things which I've included are

  • using prepared statements, always a good idea
  • extracting common code to functions (formatting & displaying values, adding totals)

As I use arrays of virtually the same format as the data rows to accumulate the totals, I can use the same code that displays the line data as I use for the totals, this means that any formatting of this data is in one place rather than being repeated in various points in the code.

Code -

$from_date = '2018-04-01';
$to_date = '2018-09-01';

if ( !$cid = $conn->prepare("SELECT * 
                FROM tbl_silver_stock 
                WHERE stockdate between ? and ?"))   {
    die( "Error:".$conn->error );
}
$cid->bind_param("ss", $from_date, $to_date);
if ( !$cid->execute())  {
    die( "Error:".$cid->error );
}
if ( !$result = $cid->get_result())  {
    die( "Error:".$cid->error );
}

echo '<table><tr><td>Date</td><td>Particulars</td><td>Vch Type</td>
            <td>Vch No</td><td colspan="2">Inwards</td>
            <td colspan="2">Outwards</td><td colspan="2">Closing</td>
        </tr><tr><td colspan="4">&nbsp;</td><td>Quantity</td>
            <td>Value</td><td>Quantity</td><td>Value</td>
            <td>Quantity</td><td>Value</td>
        </tr>';

$sumKeys = ['in_quantity', 'in_price_value', 'out_quantity', 'out_price_value', 'cls_quantity', 'cls_price_value'];
// Create blank totals arrays
$totals = array_fill_keys($sumKeys, 0);
$totalsMonth = array_fill_keys($sumKeys, 0);
$lastMonth = null;
// Set to allow correct formatting
setlocale(LC_MONETARY, 'en_IN');
while ( $entry = $result->fetch_assoc()) {
    $month = date("m-Y", strtotime($entry['stockdate']));
    // If month has changed (but not for first loop)
    if ( ($lastMonth??$month) != $month ) {
        echo '<tr><td colspan="4">Totals as per "Default" valuation:</td>'
            .outputValues($totalsMonth).'</tr>';
        // Add month totals to overall total
        addTotals($totals, $totalsMonth);
        // Reset totals for month
        $totalsMonth = array_fill_keys($sumKeys, 0);
    }
    $lastMonth = $month;
    echo "<tr>
            <td>".date("d-m-Y", strtotime($entry['stockdate']))."</td>
            <td>$entry[particulars]</td>
            <td>$entry[vch_type]</td>
            <td>".(!empty($entry['vch_number'])?$entry['vch_number']:'')."</td>"
            .outputValues($entry)."</tr>";
    // Add current entry to monthly totals
    addTotals($totalsMonth, $entry);
}
// Output last monthly totals
echo '<tr><td colspan="4">Totals as per "Default" valuation:</td>'
    .outputValues($totalsMonth).'</tr>';
addTotals($totals, $totalsMonth);
// Output grand totals
echo '<tr><td colspan="4">Grand Totals as per "Default" valuation:</td>'
        .outputValues($totals).'</tr></table>';

// Output common values with appropriate formatting
function outputValues ( $entry ){
    return "<td>".(!empty($entry['in_quantity'])?$entry['in_quantity']."KG":'&nbsp;')."</td>
        <td>".(!empty($entry['in_price_value'])?money_format('%!i', $entry['in_price_value']):'&nbsp;')."</td>
        <td>".(!empty($entry['out_quantity'])?$entry['out_quantity']."KG":'&nbsp;')."</td>
        <td>".(!empty($entry['out_price_value'])?money_format('%!i', $entry['out_price_value']):'&nbsp;')."</td>
        <td>".(!empty($entry['cls_quantity'])?$entry['cls_quantity']."KG":'&nbsp;')."</td>
        <td>".(!empty($entry['cls_price_value'])?money_format('%!i', $entry['cls_price_value']):'&nbsp;')."</td>";
}
// Add on new values
function addTotals ( &$to, $add )   {
    $to['in_quantity'] += $add['in_quantity'];
    $to['in_price_value'] += $add['in_price_value'];
    $to['out_quantity'] += $add['out_quantity'];
    $to['out_price_value'] += $add['out_price_value'];
    $to['cls_quantity'] += $add['cls_quantity'];
    $to['cls_price_value'] += $add['cls_price_value'];
}

1 Comment

There's valuable advice in here. (I wasn't aware of the currency being used.)
0

Let's see :

$from_date = '2018-04-01';  
$to_date = '2018-09-30';
$is_complete=true; //boolean to check if month is complete
$month_marker=0; //to keep track of month's changes
echo '<table><tr><th>Date</th><th>In price value</th></tr>';
//we add a ORDER BY to make sure we get the lines as needed
$cid = mysqli_query($con_db,"SELECT *,YEAR(stockdate) as year,MONTH(stockdate) as month FROM tbl_silver_stock WHERE stockdate between '$from_date' and '$to_date' ORDER BY stockdate");
while($line=mysqli_fetch_assoc($cid)){
  if($month_marker!=$line['month']){//change of month
    if($month_marker>0)echo '<tr><td>Total for month '.$month_marker.' : </td><td>'.$total_in_price.'</td></tr>';
    $month_marker=$line['month'];
    $total_in_price=0; //the monthly total price of your lines
  }
  if($line['year']>=date('Y') AND $line['month']>=date('m'))$is_complete=false;//here you could use "=" instead of ">=" but it's more robust that way
  echo '<tr><td>'.$line['stockdate'].'</td><td>'.$line['in_price_value'].'</td></tr>';
  $total_in_price+=$line['in_price_value'];
}
if(!$is_complete)$incomplete=' - Incomplete month !';
else $incomplete='';
echo '<tr><td>Total for month '.$month_marker.$incomplete.' : </td><td>'.$total_in_price.'</td></tr>'; //we add this outside the while loop because else we'll miss the last month

echo '</table>';

It's not optimized (you probably should use functions to regroup the echos together, maybe use some arrays instead of one-use vars like $total_in_price, etc) and not tested, but you should get the gist.

3 Comments

thanks for your answer, but how I can print all the month rows and after print the total? Please suggest. I'm print all out put in the <table><tr><td></td></tr></table>.
@mageDev0688 what exactly is the problem with the given answer? Why not use the given code and rework on your own what is not working?
Good point but here you go, I made the example with 2 columns instead of text. You'll just need to add more columns to match your wanted output. I hope it's clearer that way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.