带有运行总计的分页结果

Nig*_*ICU 5 php mysql

我一直试图想出最好的方法来输出具有运行总计的金融交易的分页结果,首先是最近的交易,最后是第一个(最旧的)交易,但似乎无法找到一种有效的方法来解决它.

单独使用OFFSET和提取结果LIMIT将不起作用,因为我正在尝试显示运行总数。

出于绝望,我最终使用了一个多维数组,其中主数组中的每个数组都包含 x 个条目,并通过调用每个条目块来访问结果(例如,$transArr[0]将包含前 38 条记录、$transArr[1]接下来的 38条记录等) )。我确信这是一种非常低效的处理方式,我会喜欢任何和所有建议。

这是我想出的 - 抱歉,它有很多代码,包括分页链接和数据格式。这只是一个类中的一个对象。

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>";
    }
}
Run Code Online (Sandbox Code Playgroud)

再次感谢您的任何建议!

更新

这是我更新的 SQL,与提供的答案一致。这显示了正确的运行平衡(运行平衡 = 运行平衡 - 先前的金额),但我在尝试创建分页结果时被卡住了。

$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");
Run Code Online (Sandbox Code Playgroud)

Nig*_*ICU 0

利用我从这个问题的其他答案中学到的一些知识(特别是 MySQL 变量 - 感谢 Marc B),我为这个问题制定了一个相当简单的解决方案。对于初学者来说,分页链接代码的一部分包括通常在 MySQL 查询中使用的偏移量。我没有在传统意义上使用它,而是首先将计数器设置为 1,并在每次运行 while 循环时递增 1。当计数器达到偏移值时,我开始输出结果,当达到偏移量+每页总行数时结束。当到达末尾时,我跳出 while 循环。

看起来速度相当快。如果有人想提出任何建议,请随意!这是最终的代码:

public function fetchTransactions($currPage = null) {
        global $db;
        //Balance account
        $this->balanceAccount();
        $accountBalance = $this->accountBalance;
        //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
        $totalPages = ceil($numRows / $rowsPerPage);
        //Get current page or set default
        if (isset($currPage) && is_numeric($currPage)) {
            $currentPage = (int) $currPage;
        } else {
            $currentPage = 1;
        }
        //Set $currPage to $totalPages if greater than total
        if ($currentPage > $totalPages) {
            $currentPage = $totalPages;
        }
        if ($currentPage < 1) {
            $currentPage = 1;
        }
        //Offset of the list, based on current page
        $offset = ($currentPage - 1) * $rowsPerPage;
        //Set end point for records per page
        $end = $offset + $rowsPerPage;

        //Start counter for retrieving records for current page
        $i = 1;

        //Fetch the transactions
        $setRunning = $db->query("SET @running := $accountBalance, @prevAmount = 0"); //Sets varaible for calculating running total
        $sql = "SELECT amount, @running := @running - @prevAmount AS running, @prevAmount := amount AS prevAmount, payee, cat, date 
        FROM transactions ORDER BY id DESC, date DESC";
        $fetchTransactionsSQL = $db->query($sql);
        while ($transactionDetails = $fetchTransactionsSQL->fetch()) {
            $amount = $transactionDetails['amount'];
            //If counter reaches beginning of offset, start outputting results. End when the last row for result set is reached
            if ($i >= $offset && $i < $end) {
                $date = date("m/d", strtotime($transactionDetails['date']));
                $payee = stripslashes($transactionDetails['payee']);
                $category = $transactionDetails['cat'];
                $amountOutput = money_format("%n", $amount);
                $runningTotalOutput = money_format("%n", $transactionDetails['running']);
                echo "
                <tr>
                    <td>$date</td>
                    <td><strong>$payee</strong></td>
                    <td>$category</td>
                    <td>$amountOutput</td>
                    <td>$runningTotalOutput</td>
                </tr>                    
                ";
            }
            //If the end of the result set has been reached, break out of while loop. Else, increment the counter
            if ($i == $end) {
                break;
            } else {
                $i++;
            }
        }
        //Create paginated links
        if ($currentPage > 1) {
            $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>";
        }
    }
Run Code Online (Sandbox Code Playgroud)