Query in a while loop fetching stale data - php

I am trying (and not succeeding) to run a while loop with a query that gets the last row in a table, uses that data then create a new row then selects the last row in the table again (which should be the row just created) then uses that data and creates a new row. This should repeat until the while loop is no longer true.
The problem I have is the while loop runs but always uses the row it selected the first time round. So the same row get inserted over and over until the while loop is false.
My question is how can I get the query to refresh when the while loop starts a new loop?
I have tried unset() but this did not work and am out of ideas. Here the while loop of my code (which is still in progress - still so much to add):-
while ($total_debt > 0) {
$get_dp_accounts_list_query = "SELECT account_id
FROM money_debt_planner
WHERE customer_id = '".$_SESSION['customer_id']."'
GROUP BY account_id";
$get_dp_accounts_list = $db->Execute($get_dp_accounts_list_query);
while (!$get_dp_accounts_list->EOF) {
$get_dp_accounts_listArray[] = array('account_id'=>$get_dp_accounts_list->fields['account_id']);
$get_dp_accounts_list->MoveNext();
}
foreach($get_dp_accounts_listArray as $acc_list) {
$get_last_dp_entry_query = "SELECT *
FROM money_debt_planner
WHERE customer_id = '".$_SESSION['customer_id']."'
AND account_id = '".$acc_list['account_id']."'
ORDER BY line_id DESC";
$get_last_dp_entry = $db->Execute($get_last_dp_entry_query);
if($get_last_dp_entry->fields['end_debt_balance'] <> 0) {
// calculate the interest this period
$accounts_balance = $get_last_dp_entry->fields['end_debt_balance'] + $get_last_dp_entry->fields['estimated_spending'];
$min_pay = $get_last_dp_entry->fields['min_pay_amount'];
$min_pay_rate = $get_last_dp_entry->fields['min_pay_rate'];
$interest_rate = $get_last_dp_entry->fields['interest_rate'];
$int_rate = $interest_rate /100;
$int_rate_a = $int_rate + 1;
$int_value_b = $accounts_balance ;
$int_value_c = ($int_rate_a * $int_value_b) - $int_value_b . ' ';
$int_value_d = $int_value_c / 12;
$statement_balance = $accounts_balance + $int_value_d;
$min_pay_rate = ($statement_balance) * $min_pay_rate / 100;
if($min_pay_rate < $min_pay) {
$new_bill_amount = $min_pay;
} else {
$new_bill_amount = $min_pay_rate;
}
if(($statement_balance) <= ($min_pay_rate) && ($statement_balance) <= $min_pay) {
$new_bill_amount = $statement_balance;
}
// next pay date
$next_due_day1 = date('d', strtotime ( $get_last_dp_entry->fields['date'] ));
$next_due_year_month1 = date('Y-m', strtotime ( $get_last_dp_entry->fields['date'] ));
$next_due_month_a_1 = strtotime ( "+ 1 month" , strtotime ( $next_due_year_month1 ) ) ;
$next_due_month_b_1 = date ( 'Y-m' , $next_due_month_a_1);
$total_days_in_this_month = date('t', strtotime($next_due_month_b_1) );
if($next_due_day1 >= $total_days_in_this_month) {
$next_due_date_a_1 = $total_days_in_this_month;
} else {
$next_due_date_a_1 = $next_due_day1;
}
$payment_date_from_account1 = $next_due_month_b_1 .'-' . $next_due_date_a_1;
$next_due1a = strtotime ( $payment_date_from_account1 ) ;
$next_due1 = date ( 'Y-m-d' , $next_due1a );
$dp_pay_date = $next_due1; // this will be 1 month from last entry
$interest_this_period = $int_value_d; // this will be interest on last end balance + est spending
$payment_this_period = $new_bill_amount; // this will be the min payment allowed including any over credit amount
$end_balance = ''; // this will be current open balance + spending + interest - payment
$sql = "INSERT INTO `money_debt_planner` (`customer_id`, `account_id`, `date`, `open_debt_balance`, `interest_rate`, `min_pay_rate`, `min_pay_amount`, `credit_limit`, `estimated_spending`, `interest_this_period`, `payment_this_period`, `end_debt_balance`)
VALUES ('".$_SESSION['customer_id']."', '".$acc_list['account_id']."', '".$dp_pay_date."', '".$get_last_dp_entry->fields['end_debt_balance']."', '".$get_last_dp_entry->fields['interest_rate']."', '".$get_last_dp_entry->fields['min_pay_rate']."', '".$get_last_dp_entry->fields['min_pay_amount']."', '".$get_last_dp_entry->fields['credit_limit']."', '".$get_last_dp_entry->fields['estimated_spending']."', '".$interest_this_period."', '".$payment_this_period."', '".$end_balance."')";
$db->Execute($sql);
} // end if balance zero
} // end account list
// to do this will be total debt balance utstanding
$total_debt = $total_debt - 1000;
}
Any help you can offer would be great :o)

Related

I want to update each month's total sales on website but it is just updating the last sale made

I am creating an e-commerce website, in the admin dashboard, I want to show the total sales made in the particular month. So, I just fetched the sales according to the month and made a while loop to access each sale and an if else to check if the sales of a month are empty or not. But there is a problem, it is showing the last sale made ignoring the others.
<?php
$thisYr = date("Y");
$lastYr = $thisYr - 1;
$thisYrQ = $db->query("SELECT * FROM transactions WHERE YEAR(txn_date) = '{$thisYr}'");
$lastYrQ = $db->query("SELECT * FROM transactions WHERE YEAR(txn_date) = '{$lastYr}'");
$current = array();
$last = array();
$currentTotal = 0;
$lastTotal = 0;
while ($x = mysqli_fetch_assoc($thisYrQ)) {
$month = date("m",strtotime($x['txn_date']));
if (!array_key_exists($month,$current)) {
$current[(int)$month] = $x['grand_total'];
} else{
$current[(int)$month] += $x['grand_total'];
}
$currentTotal += $x['grand_total'];
}
while ($y = mysqli_fetch_assoc($lastYrQ)) {
$month = date("m",strtotime($y['txn_date']));
if (!array_key_exists($month,$current)) {
$last[(int)$month] = $y['grand_total'];
} else{
$last[(int)$month] += $y['grand_total'];
}
$lastTotal += $y['grand_total'];
}
?>
Since you're only interested in totals, let mysql do the job
SELECT SUM(grand_total) as grand_total, MONTH(txn_date) AS month FROM transactions WHERE YEAR(txn_date) = '{$thisYr}' GROUP BY MONTH(txn_date)
loop through the result & add it to data
while ($row = mysqli_fetch_assoc($q) ) {
$data[$row['month']] = $row['grand_total'];
}
then in your foreach loop you do the following
foreach (range(1, 12) as $month) {
if ( exists($data[$month]) ){
echo $data[$month];
}else{
echo "No data for month";
}
This should be faster & takes less time/memory ...etc

Compare date/time from form to dates/times in database

UPDATE
I edited my code, so now the time is checked correctly:
while($row = mysqli_fetch_array($result)){
$rid = $row['roomid'];
$begin = $row['start'];
$bval = strtotime($begin);
$einde = $row['end'];
$eval = strtotime($einde);
$staco = strtotime($start); //starttime posted from form
$endco = strtotime($end); //stoptime posted from form
$abegin = array(sta => $bval);
$aeinde = array(sto => $eval);
// print_r($abegin);
// print_r($aeinde);
foreach($aeinde as $sto) {
if($staco <= $sto) {$checksto = 1;}
else {$checksto = 0;}
}
foreach($abegin as $sta) {
if($endco <= $sta) {$checksta = 1;}
else {$checksta = 0;}
}
if($checksta == $checksto) {$ok = 1;} else {$ok = 0;}
print_r($ok);
}
}
}
So now: how do I check if $ok contains one or more 0's (don't book the room) or all 1's (book the room).
$roomstate = array(state => $ok) results in more than one array:
Array ( [state] => 0 ) Array ( [state] => 1 ) Array ( [state] => 1 )
I'm doing something wrong, because I think it should be possible to get all the different $ok's in one array and then
if(in_array(0,$roomstate)) { echo "Do not book";} else {$bookitsql = "INSERT INTO reservations ...";}
UPDATE: There is a flaw in my original logic to check availabilty with the rooms that needs to be solved first: now the rooms are not checked correct, so it is impossible to answer this question since the correct data is not displayed. My apologies.
For a system that books rooms I need to check with a new booking if the room is already is booked at the moment. The booking works with a form, and then it compares the results from the form with the content in the database for that room on that date.
while($row = mysqli_fetch_array($result)){
$rid = $row['roomid'];
$begin = $row['start'];
$bval = strtotime($begin);
$staco = strtotime($start);
$einde = $row['end'];
$eval = strtotime($einde);
$endco = strtotime($end);
$abegin = array(sta => $bval);
$aeinde = array(sto => $eval);
foreach($abegin as $sta) {
if($staco $checksta,checkstop => $checksto);
print_r($meh);
}
BetterQuestion:
Now I get `$staco` and `$endco`, which are the start and stoptime from the form.
I also get `$sta` and `$sto`, which are multiple start and stoptimes from the database.
Example:
existing reservations:
sta sto
1: 0800 0959
2: 1130 1259
So now when I get `$staco = 1000` and `$endco = 1114` it doesn't check right.
It only works if the new reservation is later than all the other reservations in the database. How can I solve this?
Your Target Pseudocode shows that you want it all be 0. $meh is an Array.
So what you do now is using a foreach on $meh and then Mark it as Occupied as soon as 1 appears. if this doesnt happen, you can assume that $meh is free, and do you Booking.
$roomState = 0;
foreach($meh as $mehValue){
if($mehValue == 1){
$roomState = 1;
}
}
if($roomState == 1){
print_r("room is occupied");
} else {
//insert stuff
}
Took a different approach, by checking date in my sql-statement.
So, the form posts $start and $end (when the users wants to make a reservation).
Now my code looks like this (and it looks ok, I think):
//form and other errormessages like username==0; $start>$end etcetera
else {
$reservationsql = "SELECT * FROM reservations WHERE roomid = '$roomid' AND ('$start' between start AND end) OR ('$end' between start AND end) OR ('$start' >= start AND '$end' <= end) OR ('$start' <= start AND '$end' >= end)";
$result = mysqli_query($link,$reservationsql) or die(mysql_error());
$num = mysqli_num_rows($result);
if($num>0) {"Error: room already booked at that moment";}
else {//$query = "INSERT INTO ..."}
}
}mysqli_close();
Thanks for all the help here and to think along with me.

Repeat Event Monthly php mktime

I have a reservation tool that allows for repeating events to be scheduled. I have been able to figure out daily and weekly repeating, but hung up on the monthly repeat because of the varying days in a month.
The goal is to repeat the reservation every third Thursday of the month for example. I thought I had it by using some simple math and scheduling it at interval of 28, but that did not work. I am assuming my code needs some additional variable.
I have a form that passes my numeric value and that worked as I mentioned for daily and weekly repeats. You will see I passed 28 as my value for monthly, but causes issue. It does repeat on the same day, but over time on the wrong week.
<input type="radio" class="radio" name="recurring_span" value="1" checked="checked"/><img src='images/icons/calendar-select-days-span.png' alt='daily' title='Daily'>
<input type="radio" class="radio" name="recurring_span" value="7"><img src='images/icons/calendar-select-days.png' alt='weekly' title='Weekly'/>
<input type="radio" class="radio" name="recurring_span" value="28"><img src='images/icons/calendar-select-days.png' alt='montly' title='Monthly'/>
</p>
The processing php is as follows (sorry if I am including too much, but as I said not great with PHP, figured more was better than less):
//store recurring reservation
if ($recurring_date > $reservation_date){
$repeatid = querySQL('res_repeat');
$keys[] = 'repeat_id';
$values[] = "'".$repeatid."'";
}
// UNIX time
$res_dat = mktime(0,0,0,(int)$m1,(int)$d1,(int)$y1);
$recurring_date = mktime(0,0,0,(int)$m2,(int)$d2,(int)$y2);
$recurring_date = ($recurring_date<$res_dat) ? $res_dat : $recurring_date;
// daily or weekly recurring?
$recurring_span = ($_POST['recurring_span']) ? $_POST['recurring_span'] : 1;
//cut both " ' " from reservation_pax
$res_pax = substr($_SESSION['reservation_pax'], 0, -1);
$res_pax = substr($_SESSION['reservation_pax'], 1);
// check if pax not '0'; prevent 'Christof Keller' bug
if ($res_pax < 1) {
$res_pax = 1;
}
//cut both " ' " from reservation_time
$startvalue = $_SESSION['reservation_time'];
$startvalue = substr($startvalue, 0, -1);
$startvalue = substr($startvalue, 1);
// do not subtract pax and table when reservation is moved
//$res_pax = ($_SESSION['outletID'] == $_POST['old_outlet_id']) ? $res_pax : $res_pax*2;
//$res_tbl = ($_SESSION['outletID'] == $_POST['old_outlet_id']) ? 1 : 2;
// main loop to store all reservations ( one or recurring)
while ( $res_dat <= $recurring_date) {
// build new reservation date
$index = '';
$index = array_search('reservation_date',$keys);
// build for availability calculation
$_SESSION['selectedDate'] = date('Y-m-d',$res_dat);
if($index){
$values[$index] = "'".$_SESSION['selectedDate']."'";
}else{
$keys[] = 'reservation_date';
$values[] = "'".$_SESSION['selectedDate']."'";
}
$index = '';
$index = array_search('reservation_wait',$keys);
if($index){
$values[$index] = '1';
}
//Check Availability
// =-=-=-=-=-=-=-=-=
// get Pax by timeslot
$resbyTime = reservationsByTime('pax');
$tblbyTime = reservationsByTime('tbl');
// get availability by timeslot
$occupancy = getAvailability($resbyTime,$general['timeintervall']);
$tbl_occupancy = getAvailability($tblbyTime,$general['timeintervall']);
$val_capacity = $_SESSION['outlet_max_capacity']-$occupancy[$startvalue];
$tbl_capacity = $_SESSION['outlet_max_tables']-$tbl_occupancy[$startvalue];
if( $res_pax > $val_capacity || $tbl_capacity < 1 ){
//prevent double array entry
$index = array_search('reservation_wait',$keys);
if($index>0){
if ($values[$index] == '0') {
// error on edit entry
$_SESSION['errors'][] = date($general['dateformat'],strtotime($_SESSION['selectedDate']))." "._wait_list;
}
$values[$index] = '1'; // = waitlist
}else{
// error on new entry
$keys[] = 'reservation_wait';
$values[] = '1'; // = waitlist
$_SESSION['errors'][] = date($general['dateformat'],strtotime($_SESSION['selectedDate']))." "._wait_list;
}
}
// END Availability
// number of database fields
$max_keys = count($keys);
// enter into database
// -----
$query = "INSERT INTO `$dbTables->reservations` (".implode(',', $keys).") VALUES (".implode(',', $values).") ON DUPLICATE KEY UPDATE ";
// Build 'on duplicate' query
for ($i=1; $i <= $max_keys; $i++) {
if($keys[$i]!=''){
$query .= $keys[$i]."=".$values[$i].",";
}else{
$max_keys++;
}
}
// run sql query
//echo "Query: ".$query;
$query = substr($query,0,-1);
$result = query($query);
$new_id = mysql_insert_id();
$_SESSION['result'] = $result;
// setup the right ID
if( isset($new_id) || $new_id != $_POST['reservation_id']){
$history_id = $new_id;
}else{
$history_id = $_POST['reservation_id'];
}
// store changes in history
$result = query("INSERT INTO `$dbTables->res_history` (reservation_id,author) VALUES ('%d','%s')",$history_id,$_POST['reservation_booker_name']);
// -----
// increase reservation date one day or week
$d1 += $recurring_span;
$res_dat = mktime(0,0,0,$m1,$d1,$y1);
} // end while: reservation to store
I should not I am not so great with PHP and trying to learn, my experience is limited to working with stumbling around existing code. For this project I have been working to customize and modify an opensource scheduling tool for my needs. Researching the mktime without much progress. Thanks in advance!

Fast compute average monthly sales for the past 6, 3, 1 months per product

I'm using PHP/MySQL
I have about 2,000 products. I have to compute the average monthly sales for the past 6, 3, 1 month(s) of each product and show it in the page at once...
Currently I have the following code (loop for each product):
$past_month_sales = $this->SalesPerProduct->getSalesForMonthYear( $acc_code,
$item_code, $past_month[0],
$past_month[1] );
$past_two_months_sales = $this->SalesPerProduct->getSalesForMonthYear( $acc_code,
$item_code, $past_two_months[0],
$past_two_months[1] );
$past_three_months_sales = $this->SalesPerProduct->getSalesForMonthYear( $acc_code,
$item_code, $past_three_months[0],
$past_three_months[1] );
$past_four_months_sales = $this->SalesPerProduct->getSalesForMonthYear( $acc_code,
$item_code, $past_four_months[0],
$past_four_months[1] );
$past_five_months_sales = $this->SalesPerProduct->getSalesForMonthYear( $acc_code,
$item_code, $past_five_months[0],
$past_five_months[1] );
$past_six_months_sales = $this->SalesPerProduct->getSalesForMonthYear( $acc_code,
$item_code, $past_six_months[0],
$past_six_months[1] );
//for past 3 months
if( $past_month_sales == 0
|| $past_two_months_sales == 0
|| $past_three_months_sales == 0){
$past_three_sales_ave = "n/a";
}else{
$past_three_sales_ave = round( ( $past_month_sales
+ $past_two_months_sales
+ $past_three_months_sales )
/ 3 );
}
//for past 6 months
if( $past_month_sales == 0
|| $past_two_months_sales == 0
|| $past_three_months_sales == 0
|| $past_four_months_sales == 0
|| $past_five_months_sales == 0
|| $past_six_months_sales == 0){
$past_six_sales_ave = "n/a";
}else{
$past_six_sales_ave = round( ( $past_month_sales
+ $past_two_months_sales
+ $past_three_months_sales
+ $past_four_months_sales
+ $past_five_months_sales
+ $past_six_months_sales )
/ 6 );
}
But the code above is very slow, even 100 products take ages to load...
My getSalesForMonthYear function look like this:
function getSalesForMonthYear( $account_code, $item_code, $month, $year ){
$sql = "select
SalesPerProduct.sales_value
from
sales_per_products as SalesPerProduct
where
account_code = '{$account_code}' and
item_code = '{$item_code}' and
month = '{$month}' and
year = '{$year}'";
$val = $this->query($sql);
if( empty( $val[0]['SalesPerProduct']['sales_value'] ) ){
$val = 0;
}else{
$val = $val[0]['SalesPerProduct']['sales_value'];
}
return $val;
}
Any idea how this can be fast? TIA!!!
you don't need to update the data every time click happens,so build a cache table to save the data and update every period of time you want
You should look in to SQL commands like AVG
http://www.w3schools.com/sql/sql_func_avg.asp
Its always better to do the calculation on the database side. No code you write will go faster than doing it before extracting it.
See that you have index your database good so it know what to do and when!
Thats the first you could do!
I think it will solve alot for you at this point.
If you then want to take it even one step futher you could check in to this.
http://www.sqlteam.com/article/intro-to-user-defined-functions-updated
http://www.w3schools.com/sql/sql_view.asp
You could create a function and view that extract all avg calls in one sql query. No need for several connections. Every connection will have some overhead starting up and so on that you could by pass again by doing everything on the database side!
maybe use an general function and don't check for each month.
and try to use indexes for months and sales_value
/*
$account_code - account
$item_code - item
$start_month - starting month - NOTE: this is integer: 1,2,....,10,11,12
$months - number of months to query
$year - the year
and SUM to auto calculate the sales_value
*/
function getSalesForMonths( $account_code, $item_code, $start_month, $months, $year ){
$addQuery = '';
$finalQuery = '';
for($i = 1; $i<=$months; $i++){
$addQuery .= 'month='.($start_month+$i);
if($i<$months){ $addQuery .= ' OR '; }
}
if($months > 1){
$finalQuery = '('.$addQuery.')';
} else {
$finalQuery = $addQuery;
}
$sql = "select
SUM(SalesPerProduct.sales_value)
from
sales_per_products as SalesPerProduct
where
account_code = '{$account_code}' and
item_code = '{$item_code}' and
".$finalQuery." and
year = '{$year}'";
$val = $this->query($sql);
if( empty( $val[0]['SalesPerProduct']['sales_value'] ) ){
$val = 0;
}else{
$val = $val[0]['SalesPerProduct']['sales_value'];
}
return $val;
}

Comparing missing numbers in an array. PHP

I got this script which looks up taken times in this table and then removes those times from these three arrays. The arrays are times 1-24.
The ultimate goal of this script is to compare all the missing times from these arrays and make one big array with only the available times.
The catch is it needs to check if a time is missing three times in a row. If it is, that time will not display in the final array.
For example:
<?php
include 'db-connect.php';
if (isset($_GET['month']) && isset($_GET['day']) && isset($_GET['year'])) {
$month = $_GET['month'];
$day = $_GET['day'];
$year = $_GET['year'];
//string together date
$date = $month."/".$day."/".$year;
//define the queries
$sql1 = mysql_query("SELECT start_time, server FROM classes WHERE date = '$date' AND server = '1'");
$sql2 = mysql_query("SELECT start_time, server FROM classes WHERE date = '$date' AND server = '2'");
$sql3 = mysql_query("SELECT start_time, server FROM classes WHERE date = '$date' AND server = '3'");
//define time lists for each server
$timelist1 = range(1, 24);
$timelist2 = range(1, 24);
$timelist3 = range(1, 24);
//unset the arrays with the taken times for server 1
while($query1 = mysql_fetch_array($sql1)) {
unset($timelist1[$query1['start_time'] - 1]);
}
//unset the arrays with the taken times for server 2
while($query2 = mysql_fetch_array($sql2)) {
unset($timelist2[$query2['start_time'] - 1]);
}
//unset the arrays with the taken times for server 3
while($query3 = mysql_fetch_array($sql3)) {
unset($timelist3[$query3['start_time'] - 1]);
}
//now see which times are missing three times in a row and make one final array of available times.
//code goes here...
}
?>
Instead of your current strategy you could just store the number of arrays each time is found in, like:
include 'db-connect.php';
if (isset($_GET['month']) && isset($_GET['day']) && isset($_GET['year'])) {
$month = $_GET['month'];
$day = $_GET['day'];
$year = $_GET['year'];
//string together date
$date = $month."/".$day."/".$year;
//define time list
$timelist = array_fill(1, 24, 0);
while($query1 = mysql_fetch_array($sql1)) {
$timelist[$query1['start_time']]++;
}
while($query2 = mysql_fetch_array($sql2)) {
$timelist[$query2['start_time']]++;
}
while($query3 = mysql_fetch_array($sql3)) {
$timelist[$query3['start_time']]++;
}
$timelist = array_keys(array_filter($timelist, 'equals3'));
function equals3($x){
return $x == 3;
}
Now $timelist is an array of times that were found in all three queries. If you want an array of times that were missing from at least one query use this instead of the last few lines:
$timelist = array_keys(array_filter($timelist, 'lessThan3'));
function lessThan3($x){
return $x < 3;
}
Edit for variable amount of servers.
// Here you can list the servers you want to include in the query
// In an array form so it can be filled easily
$servers = array(1,2,4,5);
$num_servers = count($servers);
// Convert servers into queryable format
$servers = '(\''.implode('\',\'', $servers).'\')';
$query = 'SELECT `start_time`, COUNT(*) as `count` FROM `classes`
WHERE `date` = \''.$date.'\' AND `server` IN '.$servers.'
GROUP BY `start_time`';
$result = mysql_query($query);
$timelist = array_fill(1, 24, 1);
while($row = mysql_fetch_row($result))
if($row[1] == $num_servers) // `start_time` is missing from at least one server
unset($timelist[$row[0]]);
$timelist = array_keys($timelist);
// Now $timelist is an array of times that are available on at least one server from the query
Please note that since your date variable comes from $_GET you should be very careful of MySQL Injection attacks. Someone could delete your whole database, or worse, if you don't have the right protection in place. Please read this: http://www.learnphponline.com/security/sql-injection-prevention-mysql-php

Categories