Php 从两个不同的表中获取两列的总和

Php 从两个不同的表中获取两列的总和,php,mysql,math,sum,Php,Mysql,Math,Sum,我有两个MySQL表,结构如下(我删除了不相关的列) 该系统的工作方式是,您点一顿饭,每顿饭都有成本,每一份订单都存储在edinners\u details中。示例行如下所示: mysql> SELECT * FROM `edinners_details` LIMIT 1; +------------+------------------+--------------+ | details_id | details_pupil_id | details_cost | +----------

我有两个MySQL表,结构如下(我删除了不相关的列)

该系统的工作方式是,您点一顿饭,每顿饭都有成本,每一份订单都存储在
edinners\u details
中。示例行如下所示:

mysql> SELECT * FROM `edinners_details` LIMIT 1;
+------------+------------------+--------------+
| details_id | details_pupil_id | details_cost |
+------------+------------------+--------------+
|          1 |            18343 |           25 |
+------------+------------------+--------------+
mysql> SELECT * FROM `edinners_payments` LIMIT 1;
+------------+------------------+----------------+
| payment_id | payment_pupil_id | payment_amount |
+------------+------------------+----------------+
|          1 |            18343 |             20 |
+------------+------------------+----------------+
通常情况下,人们会批量支付这些餐费——如果他们在20天内有价值40英镑的餐费,他们会在月底付清。每次他们付款时,都会有一个新行进入
edinners\u payments
表,示例行如下:

mysql> SELECT * FROM `edinners_details` LIMIT 1;
+------------+------------------+--------------+
| details_id | details_pupil_id | details_cost |
+------------+------------------+--------------+
|          1 |            18343 |           25 |
+------------+------------------+--------------+
mysql> SELECT * FROM `edinners_payments` LIMIT 1;
+------------+------------------+----------------+
| payment_id | payment_pupil_id | payment_amount |
+------------+------------------+----------------+
|          1 |            18343 |             20 |
+------------+------------------+----------------+
因此,从这两行中我们可以看出,此人目前负债5英镑——他们吃了25英镑的饭,只付了20英镑。随着时间的推移,系统中的每个用户都会有很多行,我可以通过执行一个简单的查询(如

SELECT SUM(`details_cost`) AS `meal_total` 
FROM `edinners_details` 
WHERE `details_pupil_id` = '18343';
然后,为了获得他们支付的金额,我只需执行以下查询:

SELECT SUM(`payment_amount`) AS `payment_total` 
FROM `edinners_payments` 
WHERE `payment_pupil_id` = '18343';
SELECT * FROM (
    SELECT `details_cost` AS `cost` 
    FROM `edinners_details` 
    WHERE `details_pupil_id` = '18343'
    GROUP BY `details_id`
) AS `details`, (
    SELECT `payment_amount` AS `amount` 
    FROM `edinners_payments` 
    WHERE `payment_pupil_id` = '18343'
    GROUP BY `payment_id`
) AS `payment`;
我的最终目标是能够看到谁欠的钱最多,但是要循环我的
users
表中的每个用户并为他们运行这两个查询,我相信这会非常慢,所以理想情况下,我想做的是将上面两个查询合并成一个查询,也许还需要一个额外的列(
餐费总额
-
付款总额
)我尝试了一些方法来实现这一点,包括联接和子查询,但它们似乎都重复了
edinners\u details
中每个
edinners\u付款
行中的每一行相关内容-因此,如果有3个细节和4个付款,则将有12行被拉出,这意味着要执行列上的SUM()为我提供了一个远远超过其应有值的值。运行此查询是证明这一点的一个好方法:

SELECT SUM(`payment_amount`) AS `payment_total` 
FROM `edinners_payments` 
WHERE `payment_pupil_id` = '18343';
SELECT * FROM (
    SELECT `details_cost` AS `cost` 
    FROM `edinners_details` 
    WHERE `details_pupil_id` = '18343'
    GROUP BY `details_id`
) AS `details`, (
    SELECT `payment_amount` AS `amount` 
    FROM `edinners_payments` 
    WHERE `payment_pupil_id` = '18343'
    GROUP BY `payment_id`
) AS `payment`;
这给了我以下结果:

+------+--------+
| cost | amount |
+------+--------+
|  2.5 |     20 |
|  2.5 |      6 |
|  2.5 |      3 |
|  2.5 |   1200 |
|  2.5 |     20 |
|  2.5 |      6 |
|  2.5 |      3 |
|  2.5 |   1200 |
|  2.5 |     20 |
|  2.5 |      6 |
|  2.5 |      3 |
|  2.5 |   1200 |
|  2.5 |     20 |
|  2.5 |      6 |
|  2.5 |      3 |
|  2.5 |   1200 |
|  2.5 |     20 |
|  2.5 |      6 |
|  2.5 |      3 |
|  2.5 |   1200 |
+------+--------+
+--------------+---------------+
| details_cost | payment_total |
+--------------+---------------+
|           50 |          6145 |
+--------------+---------------+
将总和加在其中,如下所示:

SELECT SUM(`details`.`cost`) AS `details_cost`, SUM(`payment`.`amount`) AS `payment_total` FROM (
    SELECT `details_cost` AS `cost` 
    FROM `edinners_details` 
    WHERE `details_pupil_id` = '18343'
    GROUP BY `details_id`
) AS `details`, (
    SELECT `payment_amount` AS `amount` 
    FROM `edinners_payments` 
    WHERE `payment_pupil_id` = '18343'
    GROUP BY `payment_id`
) AS `payment`;
给我以下结果:

+------+--------+
| cost | amount |
+------+--------+
|  2.5 |     20 |
|  2.5 |      6 |
|  2.5 |      3 |
|  2.5 |   1200 |
|  2.5 |     20 |
|  2.5 |      6 |
|  2.5 |      3 |
|  2.5 |   1200 |
|  2.5 |     20 |
|  2.5 |      6 |
|  2.5 |      3 |
|  2.5 |   1200 |
|  2.5 |     20 |
|  2.5 |      6 |
|  2.5 |      3 |
|  2.5 |   1200 |
|  2.5 |     20 |
|  2.5 |      6 |
|  2.5 |      3 |
|  2.5 |   1200 |
+------+--------+
+--------------+---------------+
| details_cost | payment_total |
+--------------+---------------+
|           50 |          6145 |
+--------------+---------------+
如果这是可行的,
细节成本
将是12.5,
付款总额
将是1229,但事实并非如此。你可以清楚地看到上述结果中的重复,我很抱歉,所有成本都是2.5,这让它变得不那么明显,但它们是5份单独的餐单,已经支付了4笔款项。有人知道吗你知道我该如何同时得到点餐费用和付款总额吗


感谢当前,您的查询正在执行一个交叉连接,它将第一个表中的每一行连接到第二个表中的每一行,因此返回大量冗余结果。但是,两个表都有一个
瞳孔id
,因此我们可以使用它来连接每个表中的正确记录

SELECT
  d.detail_pupil_id AS pupil_id,
  SUM(d.details_cost) AS cost,
  SUM(p.payment_amount) AS amount
FROM `edinners_details` d
INNER JOIN `edinners_payments` p ON d.detail_pupil_id = p.payment_pupil_id
GROUP BY pupil_id;
您可以通过执行到
users
表的联接,并在一个查询中返回所需的所有数据来进一步实现这一点

SELECT
  users.id,
  users.name,
  payment.cost,
  payment.amount
FROM `users`
INNER JOIN (
  SELECT
    d.detail_pupil_id AS pupil_id,
    SUM(d.details_cost) AS cost,
    SUM(p.payment_amount) AS amount
  FROM `edinners_details` d
  INNER JOIN `edinners_payments` p ON d.detail_pupil_id = p.payment_pupil_id
  GROUP BY pupil_id
) payment ON payment.pupil_id = users.id
ORDER BY users.id ASC;

我手头只有PostgreSQL可用,这就是我想到的:

SELECT coalesce(costs.pupil_id, amounts.pupil_id) as pupil_id,
       coalesce(amount_sum, 0) as amount_sum,
       coalesce(cost_sum, 0) as cost_sum,
       coalesce(amount_sum, 0) - coalesce(cost_sum, 0) as debit
FROM (
       SELECT details_pupil_id AS pupil_id,
              sum(details_cost) AS cost_sum
       FROM edinners_details
       GROUP BY details_pupil_id
     ) costs
     FULL OUTER JOIN 
     (
       SELECT payment_pupil_id AS pupil_id,
              sum(payment_amount) AS amount_sum
       FROM edinners_payments
       GROUP BY payment_pupil_id
     ) amounts ON costs.pupil_id = amounts.pupil_id;
它是按学生id对每个表中的记录进行分组,以正确计算总数,然后将它们合并以获得差额。当有人没有任何付款(但有晚餐)或没有任何晚餐(但有付款)时,可以使用完全外部联接来处理这种情况

据我所知,MySQL不支持完全外部连接(bump…),因此您必须使用UNION来模拟它:

SELECT coalesce(costs.pupil_id, amounts.pupil_id) AS pupil_id,
       coalesce(amount_sum, 0) as amount_sum,
       coalesce(cost_sum, 0) as cost_sum,
       coalesce(amount_sum, 0) - coalesce(cost_sum, 0) AS debit
FROM (
       SELECT details_pupil_id AS pupil_id,
              sum(details_cost) AS cost_sum
       FROM edinners_details
       GROUP BY details_pupil_id
     ) costs
     LEFT OUTER JOIN 
     (
       SELECT payment_pupil_id AS pupil_id,
              sum(payment_amount) AS amount_sum
       FROM edinners_payments
       GROUP BY payment_pupil_id
     ) amounts ON costs.pupil_id = amounts.pupil_id
UNION
SELECT coalesce(costs.pupil_id, amounts.pupil_id) AS pupil_id,
       coalesce(amount_sum, 0) as amount_sum,
       coalesce(cost_sum, 0) as cost_sum,
       coalesce(amount_sum, 0) - coalesce(cost_sum, 0) AS debit
FROM (
       SELECT details_pupil_id AS pupil_id,
              sum(details_cost) AS cost_sum
       FROM edinners_details
       GROUP BY details_pupil_id
     ) costs
     RIGHT OUTER JOIN 
     (
       SELECT payment_pupil_id AS pupil_id,
              sum(payment_amount) AS amount_sum
       FROM edinners_payments
       GROUP BY payment_pupil_id
     ) amounts ON costs.pupil_id = amounts.pupil_id;

以下内容适合我,尽管看起来很难看。在MySQL数据库中:

SELECT
    t1.p_id, t1.cost, t2.amount
FROM
    (SELECT
        details_pupil_id AS p_id, SUM(details_cost) AS cost
     FROM
        edinners_details
     GROUP BY
        details_pupil_id) t1,
    (SELECT
        payment_pupil_id AS p_id, SUM(payment_amount) AS amount
     FROM
        edinners_payments
     GROUP BY
        payments_pupil_id) t2
WHERE
    t1.p_id = t2.p_id

/* Getting pupils with dinners but no payment */
UNION
    SELECT
        details_pupil_id, SUM(details_cost) cost, 0
    FROM
        edinners_details
    WHERE
        details_pupil_id NOT IN (SELECT DISTINCT payment_pupil_id FROM edinners_payments)
    GROUP BY
        details_pupil_id

/* Getting pupils with payment but no dinners */
UNION
    SELECT
        payment_pupil_id, 0, SUM(payment_amount)
    FROM
        edinners_payments
    WHERE
        payment_pupil_id NOT IN (SELECT DISTINCT details_pupil_id FROM edinners_details)
    GROUP BY
        payment_pupil_id

你可以尝试以下类似的方法,它应该返回你债务最大的学生的借记和支付金额(如果一个学生多付了他的债务将是负数):

因此,如果您有以下情况:

mysql> select * from edinners_details;
+------------+------------------+--------------+
| details_id | details_pupil_id | details_cost |
+------------+------------------+--------------+
|          1 |            18343 |           25 |
|          2 |            18344 |           17 |
|          3 |            18343 |           11 |
|          4 |            18344 |            2 |
|          5 |            18344 |            7 |
|          6 |            18343 |           12 |
|          7 |            18343 |           12 |
|          8 |            18343 |           35 |
|          9 |            18344 |           30 |
+------------+------------------+--------------+

mysql> select * from edinners_payments;
+------------+------------------+----------------+
| payment_id | payment_pupil_id | payment_amount |
+------------+------------------+----------------+
|          1 |            18343 |             20 |
|          2 |            18344 |             25 |
|          3 |            18343 |             12 |
|          4 |            18344 |             25 |
|          5 |            18343 |             22 |
|          6 |            18344 |             11 |
|          7 |            18343 |              8 |
|          8 |            18344 |              2 |
+------------+------------------+----------------+
运行上述查询时,您应该得到:

+-------+--------------+
| id    | max(t.debit) |
+-------+--------------+
| 18343 |           33 |
+-------+--------------+
如果您想要每个学生的借项列表,您可以运行:

select details_pupil_id as id, (sum(details_cost) - (select sum(payment_amount) from edinners_payments where payment_pupil_id = details_pupil_id)) as debit from edinners_details group by details_pupil_id;
这将使您获得以下结果:

+-------+-------+
| id    | debit |
+-------+-------+
| 18343 |    33 |
| 18344 |    -7 |
+-------+-------+

我希望这能有所帮助。

你好,Gary,谢谢你的回复,我已经将你提供的第一个查询直接运行到我的测试表上,但我似乎仍然遇到同样的问题-表1中的每一行都连接到表2中的每一行。令人烦恼的是,我没有空间在这个评论中粘贴查询结果,但它非常相似回复到原始帖子中的那个。有什么想法吗?谢谢。我建议使用上面Furgas的答案。我已经对一个测试数据库运行了他的查询,它返回了您要查找的结果:。祝您好运!感谢您链接到SQLFiddle,我以前没有看到过它,它将来可能会有用。谢谢您的帮助。您将不会看到SQLFiddle没有任何付款(但有晚餐),学生没有晚餐(但有付款)。您好,非常感谢您,这正是我要找的。我稍微修改了它,将债务计算添加到其中,只检索负债的人,这给我留下了。再次感谢。(还有:为什么我的新行不在这里工作?我在做双空格…)你好,Furgas,谢谢你的回复。出于某种原因,你的查询结果与@e.alhajri的查询结果非常不同。我将对我拥有的数据进行手动清点,看看哪一个是正确的。再次感谢。啊,不,我错了;只是正/负相反。你的数据确实给了我正确的数据,谢谢你的帮助。遗憾的是,我不能给两个人打上正确的标记,也不能给他们报应,但请放心,如果我可以的话,我会的。