简体   繁体   中英

How to sum A row columns when left joining multiple B rows on A rows

I believe this question has been here for several times but I haven't found a straightforward solution in answers here on Stack.

My question is when I have 1:n relationship and using LEFT JOIN on A table rows where there can be multiple B rows for one A row, how to get sum of values in A?

Let's say I have A table orders and B table transactions for orders . There can be multiple transactions for one order. Here's an example query:

CREATE TABLE `orders` (
  `id` int(11) NOT NULL,
  `price` decimal(10,2) DEFAULT '0.00'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE `transactions` (
  `id` int(11) NOT NULL,
  `order_id` int(11) DEFAULT NULL,
  `amount` decimal(10,2) DEFAULT '0.00'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

INSERT INTO `orders` (`id`, `price`)
VALUES
    (1, 330.00),
    (2, 800.00);

INSERT INTO `transactions` (`id`, `order_id`, `amount`)
VALUES
    (1, 1, 330.00),
    (2, 2, 200.00),
    (3, 2, 200.00),
    (4, 2, 200.00);

Then when I try to sum up price of orders:

SELECT o.id, sum(o.price) from orders o
LEFT JOIN transactions tr ON o.id = tr.order_id

The result for sum(o.price) is 2730 . It should be 1130 (330+800). Instead, as there are three transactions for order(2) , there are 3 transaction rows for that order made by LEFT JOIN in the result and therefore the calculation is 330+800*3 . I tried using GROUP BY o.id but the sum is probably calculated before the GROUP BY ( http://sqlfiddle.com/#!9/82bd8/8/0 )

How can I make the sum to show the correct value but preserve the LEFT JOIN?

Do the sum before the join . Your query is a bit non-sensical because it has no information from transactions . But the idea is:

select o.*, t. . . .
from orders o
     (select t.order_id, . . .
      from transactions t
      group by t.order_id
     ) t
     on o.id = t.order_id;

You're getting 2730 because your join isn't linear to your main data set. While my suggested answer is not the most efficient way to do this I believe it handles your situation.

SELECT 
    orders.id,
    (SELECT SUM(price) FROM orders) AS 'price'
FROM 
    orders
LEFT JOIN
    transactions ON
        transactions.order_id = orders.id

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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