简体   繁体   English

使用分页(PHP,MySQL)时,计算运行总计/余额的最有效方法是什么?

[英]What's the most efficient way to calculate a running total/balance when using pagination (PHP, MySQL)

I have a MySQL table that stores mileage records logged by employees. 我有一个MySQL表,用于存储员工记录的里程记录。 I have a PHP page that outputs the mileage records for each employee in a table (newest to oldest) along with a running balance. 我有一个PHP页面,该表在一个表(最新到最旧)中输出每位员工的里程记录以及运行余额。 This all works fine. 这一切都很好。

The mileage records are growing faster than anticipated and it's now become apparent that pagination is required. 里程记录的增长速度超出了预期,并且现在很明显需要分页。 I have programmed the pagination and this works fine. 我已经对分页进行了编程,效果很好。 The problem I now have is that the pagination has 'broken' the running balance in the way that it ignores any values outside of the records that I have selected. 我现在遇到的问题是,分页忽略了我选择的记录之外的任何值,从而“破坏了”运行余额。 For example, imagine your bank account just provided a balance for the month of July without taking into account what was in your account in June. 例如,假设您的银行帐户仅提供了7月的余额,而没有考虑6月帐户中的余额。

Suggestions on how to tackle this problem in theory (I don't need line by line code) would be much appreciated as Google isn't throwing up much help. 理论上如何解决此问题的建议(我不需要一行一行的代码)将受到赞赏,因为Google并没有提供太多帮助。

EDIT 1 编辑1

Database and data

-- phpMyAdmin SQL Dump
-- version 4.0.10.14
-- http://www.phpmyadmin.net
--
-- Host: localhost:3306
-- Generation Time: Jul 21, 2016 at 07:11 PM
-- Server version: 5.1.73-cll
-- PHP Version: 5.4.31

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";

--
-- Database: `propsyst_main`
--

-- --------------------------------------------------------

--
-- Table structure for table `employee_mileage`
--

CREATE TABLE IF NOT EXISTS `employee_mileage` (
  `employee_mileage_id` int(11) NOT NULL AUTO_INCREMENT,
  `employee_mileage_employee_id` int(11) DEFAULT NULL,
  `employee_mileage_vehicle_id` smallint(6) DEFAULT NULL,
  `employee_mileage_start_postcode` varchar(8) COLLATE utf8_bin DEFAULT NULL,
  `employee_mileage_end_postcode` varchar(8) COLLATE utf8_bin DEFAULT NULL,
  `employee_mileage_mileage` decimal(6,2) DEFAULT NULL,
  PRIMARY KEY (`employee_mileage_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=8 ;

--
-- Dumping data for table `employee_mileage`
--

INSERT INTO `employee_mileage` (`employee_mileage_id`, `employee_mileage_employee_id`, `employee_mileage_vehicle_id`, `employee_mileage_start_postcode`, `employee_mileage_end_postcode`, `employee_mileage_mileage`) VALUES
(1, 1, 2, 'L17 0BZ', 'L36 9TJ', '1.00'),
(2, 1, 2, 'L17 0BZ', 'L36 9TJ', '2.00'),
(3, 1, 2, 'L17 0BZ', 'L36 9TJ', '3.00'),
(4, 1, 2, 'L17 0BZ', 'L36 9TJ', '4.00'),
(5, 1, 2, 'L17 0BZ', 'L36 9TJ', '5.00'),
(6, 1, 2, 'L17 0BZ', 'L36 9TJ', '6.00'),
(7, 1, 2, 'L17 0BZ', 'L36 9TJ', '7.00');

EDIT 2 编辑2

Query attempt which is not working; 查询尝试不起作用;

$statement = "SELECT *
from (
        SELECT     em.*, e.*,
                   @balance := @balance + em.employee_mileage_mileage as balance
        FROM       employee_mileage em
        CROSS JOIN (select   @balance := 0) init
        INNER JOIN employee e
on em.employee_mileage_employee_id = e.employee_id
        where      em.employee_mileage_employee_id = " . $employee_id . "
        order by   em.employee_mileage_id
        ) as base
ORDER BY   em.employee_mileage_id DESC";

$employee_mileage_query = mysqli_query($con,"{$statement} LIMIT {$startpoint} , {$per_page}") or die(mysql_error());

EDIT 3 编辑3

Database; 数据库;

-- phpMyAdmin SQL Dump
-- version 4.0.10.14
-- http://www.phpmyadmin.net
--
-- Host: localhost:3306
-- Generation Time: Jul 25, 2016 at 10:22 PM
-- Server version: 5.1.73-cll
-- PHP Version: 5.4.31

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";

--
-- Database: `propsyst_main`
--

-- --------------------------------------------------------

--
-- Table structure for table `employee_mileage`
--

CREATE TABLE IF NOT EXISTS `employee_mileage` (
  `employee_mileage_id` int(11) NOT NULL AUTO_INCREMENT,
  `employee_mileage_employee_id` int(11) DEFAULT NULL,
  `employee_mileage_vehicle_id` smallint(6) DEFAULT NULL,
  `employee_mileage_journey_date` date DEFAULT NULL,
  `employee_mileage_start_postcode` varchar(8) COLLATE utf8_bin DEFAULT NULL,
  `employee_mileage_end_postcode` varchar(8) COLLATE utf8_bin DEFAULT NULL,
  `employee_mileage_mileage` decimal(6,2) DEFAULT NULL,
  `employee_mileage_date_created` datetime DEFAULT NULL,
  `employee_mileage_created_by` int(11) DEFAULT NULL,
  PRIMARY KEY (`employee_mileage_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=7 ;

--
-- Dumping data for table `employee_mileage`
--

INSERT INTO `employee_mileage` (`employee_mileage_id`, `employee_mileage_employee_id`, `employee_mileage_vehicle_id`, `employee_mileage_journey_date`, `employee_mileage_start_postcode`, `employee_mileage_end_postcode`, `employee_mileage_mileage`, `employee_mileage_date_created`, `employee_mileage_created_by`) VALUES
(1, 32, 1, '2016-07-15', 'L17 0BZ', 'L6 5BJ', '4.19', '2016-07-25 10:15:01', 32),
(2, 32, 1, '2016-07-15', 'L6 5BJ', 'L17 0BZ', '4.19', '2016-07-25 10:15:01', 32),
(5, 32, 1, '2016-07-23', 'L17 0BZ', 'L17 1AE', '1.55', '2016-07-25 12:14:15', 32),
(3, 32, 1, '2016-07-21', 'L17 0BZ', 'L19 0PD', '2.03', '2016-07-25 12:09:24', 32),
(4, 32, 1, '2016-07-21', 'L19 0PD', 'L17 0BZ', '2.03', '2016-07-25 12:09:24', 32),
(6, 32, 1, '2016-07-23', 'L17 1AE', 'L17 0BZ', '1.55', '2016-07-25 12:14:15', 32);

Query; 查询;

$statement = "SELECT *
from (
        SELECT     em.*, e.*, v.*,
                   @balance := @balance + em.employee_mileage_mileage as balance
        FROM       employee_mileage em
        CROSS JOIN (select @balance := 0) init
        INNER JOIN employee e
        on em.employee_mileage_employee_id = e.employee_id
        INNER JOIN vehicle v
        on em.employee_mileage_vehicle_id = v.vehicle_id
        WHERE      em.employee_mileage_employee_id = " . $employee_id . "
        ORDER BY   em.employee_mileage_id
        ) as base
ORDER BY base.employee_mileage_id DESC";

$employee_mileage_query = mysqli_query($con,"{$statement} LIMIT {$startpoint} , {$per_page}") or die(mysql_error());

Output; 输出;

在此处输入图片说明

I would suggest calculating the running balance in your SQL query. 我建议您在SQL查询中计算运行余额。

Here is an example of what that SQL statement could look like: 这是该SQL语句的示例:

SELECT *
from (
        SELECT     *,
                   @balance := @balance + em.employee_mileage_mileage as balance
        FROM       (select     em.*, e.*, v.*
                    from       employee_mileage em
                    INNER JOIN employee e
                            on em.employee_mileage_employee_id = e.employee_id
                    INNER JOIN vehicle v
                            on em.employee_mileage_vehicle_id = v.vehicle_id
                    WHERE      em.employee_mileage_employee_id = ?
                    ORDER BY   em.employee_mileage_id ASC
                    ) em
        CROSS JOIN (select @balance := 0) init
        ) as base
ORDER BY base.employee_mileage_id DESC
LIMIT   ?, 2

The parameters in the above statement (marked with ? ) should be bound to: 以上语句中的参数(标记为? )应绑定到:

  • the employee_id you want to show the data for 您要显示其数据的employee_id
  • the start row of the current page (zero-based) 当前页面的开始行(从零开始)

The inner query goes through all rows for that particular employee and adds the running balance to every record. 内部查询遍历该特定员工的所有行,并将运行余额添加到每条记录。 Then the outer query reverses the sort order and applies the limit to it for paging purposes. 然后,外部查询将反转排序顺序并将限制应用于分页目的。

This solution needs no calculation to happen in PHP; 此解决方案无需在PHP中进行任何计算; the running balance is readily available in the query result set, and is correct on every page. 在查询结果集中可以很容易地找到运行余额,并且在每个页面上都正确。

Here is a small SQL fiddle demonstrating it for getting the second page, with 2 rows per page, from a total set of 6 rows, including the correct balance. 这是一个小的SQL小提琴,它演示了如何从总共6行(包括正确的余额)中获取第二页,每页2行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM