I am trying to find a better way to output pagination results for financial transactions with a total amount starting from the last transaction of the first and first (oldest) transactions of the last and cannot seem to find an effective way to do this.
Pulling results with only OFFSET
and LIMIT
will not work, because I'm trying to display the current amount.
Out of desperation, I finally went with a multidimensional array, where each array in the main array contains x number of records and accesses the results by calling each fragment of records (for example, $transArr[0]
will contain the first 38 records, $transArr[1]
next 38, etc.). I'm sure this is a terribly inefficient way to handle this, and I would love any suggestions.
Here's what I came up with - sorry, this is a lot of code, including paginated links and data formatting. This is only one object in the class.
public function fetchTransactionsDev($currPage = null) { global $db; //Balance the account, set accountBalance variable $this->balanceAccount(); $accountBalance = $this->accountBalance; $runningTotal = $accountBalance; //Start the Running Total as the balance $prevAmount = 0; //Starts at 0, will be used to calculate running total below //Fetch number of rows and calculate number of pages for paginated links $numRows = $db->query("SELECT COUNT(*) FROM transactions"); $numRows = $numRows->fetchColumn(); $this->totalTrans = $numRows; //Number of rows to display per page $rowsPerPage = 35; //Find out total pages, factoring in that the array starts at 0 $totalPages = ceil($numRows / $rowsPerPage) - 1; //Get current page or set default if (isset($currPage) && is_numeric($currPage)) { $currentPage = (int) $currPage; } else { $currentPage = 0; } //Set $currPage to $totalPages if greater than total if ($currentPage > $totalPages) { $currentPage = $totalPages; } if ($currentPage < 1) { $currentPage = 0; } //Offset of the list, based on current page $offset = ($currentPage - 1) * $rowsPerPage; //Array to hold transactions; counters for number of arrays and number of entries per array $transArr = array(); $arrCount = 0; $i = 0; //Fetch the transactions $sql = "SELECT amount, payee, cat, date FROM transactions ORDER BY id DESC, date DESC"; $fetchTransactionsSQL = $db->query($sql); while ($transactionDetails = $fetchTransactionsSQL->fetch()) { $date = date("m/d", strtotime($transactionDetails['date'])); $payee = stripslashes($transactionDetails['payee']); $category = $transactionDetails['cat']; $amount = $transactionDetails['amount']; $runningTotal -= $prevAmount; $amountOutput = money_format("%n", $amount); $runningTotalOutput = money_format("%n", $runningTotal); //Add new array to $transArr with a maximum of x num entries if ($i <= $rowsPerPage) { $transArr[$arrCount][] = array("date" => $date, "payee" => $payee, "category" => $category, "amountOutput" => $amountOutput, "runningTotalOutput" => $runningTotalOutput); $i++; } else { //If over x number of entries, start a new array under $transArr and reset increment counter $arrCount++; $i = 0; $transArr[$arrCount][] = array("date" => $date, "payee" => $payee, "category" => $category, "amountOutput" => $amountOutput, "runningTotalOutput" => $runningTotalOutput);; } if ($arrCount > $currentPage) { break; } $prevAmount = $amount; //Needed for calculating running balance } //Output the results to table foreach ($transArr[$currentPage] as $transaction) { echo " <tr> <td>{$transaction['date']}</td> <td><strong>{$transaction['payee']}</strong></td> <td>{$transaction['category']}</td> <td>{$transaction['amountOutput']}</td> <td>{$transaction['runningTotalOutput']}</td> </tr> "; } //Create paginated links if ($currentPage > 0) { $prevPage = $currentPage - 1; $this->pageLinks = "<a href='{$_SERVER['PHP_SELF']}?currentPage=$prevPage'>Prev</a>"; } if ($currentPage != $totalPages) { $nextPage = $currentPage + 1; $runningBal = $runningTotal - $prevAmount; $this->pageLinks .= " <a href='{$_SERVER['PHP_SELF']}?currentPage=$nextPage'>Next</a>"; } }
Again, thanks for any suggestions!
UPDATE
Here is my updated SQL, according to the answer provided. This shows the correct current balance (Running Balance = Running Balance - previous amount), but I'm stuck trying to create paginated results.
$dough = new doughDev; $dough->balanceAccount(); $accountBalance = $dough->accountBalance; $setRunning = $db->query("SET @running := $accountBalance, @prevAmount = 0"); $getRunning = $db->query("SELECT amount, @running := @running - @prevAmount AS running, @prevAmount := amount AS prevAmount FROM transactions ORDER BY id DESC, date DESC");