简体   繁体   中英

Mysql Sum or Group concat base on distinct id

I'm sure somebody already ask this question somewhere but can't seems to find it.

Is it possible in mysql to do sum or group concat (AGGREGATE FUNCTION) combined with a distinct ?

Exemple: I have an order product which can have many option and many beneficiary. How is it possible in onequery (With out using subquery), to get the list of options, the sum of option price and the list of beneficiary ?

I've constructed a sample data set:

CREATE TABLE `order`
(id INT NOT NULL PRIMARY KEY);

CREATE TABLE order_product 
(id INT NOT NULL PRIMARY KEY
,order_id INT NOT NULL
);
CREATE TABLE order_product_options 
(id INT NOT NULL PRIMARY KEY
,title VARCHAR(20) NOT NULL
,price INT NOT NULL
,order_product_id INT NOT NULL
);

CREATE TABLE order_product_beneficiary 
(id INT NOT NULL PRIMARY KEY 
,name VARCHAR(20) NOT NULL
,order_product_id INT NOT NULL
);

INSERT INTO `order` (`id`) VALUES (1);
INSERT INTO `order_product` (`id`, `order_id`) VALUES (1, 1);
INSERT INTO `order_product_options` (`id`, `title`, `price`, `order_product_id`) 
VALUES  (1,'option1', 1, 1), (2, 'option2', 2, 1), (3, 'option3', 3, 1), (4, 'option3', 3, 1);

INSERT INTO `order_product_beneficiary` (`id`, `name`, `order_product_id`) 
VALUES  (1,'mark', 1), (2, 'jack', 1), (3, 'jack', 1);

http://sqlfiddle.com/#!9/37e383/2

The result I would like to have is

  1. id: 1
  2. options: option1, option2, option3, option3
  3. options price: 9
  4. beneficiaries: mark, jack, jack

Is this possible in mysql without using subqueries ? (I know it is possible in oracle) If it's possible, how would you do it ?

Thanks

Somewhat like , Do your price summation in inner query and then join with order_product table.

SELECT 
    op.id,
    MAX(opo.title) AS 'options',
    MAX(opo.price) AS 'options price',
    GROUP_CONCAT(opb.name SEPARATOR ', ') AS 'beneficiaries'
FROM
    order_product op
INNER JOIN (
    SELECT order_product_id, SUM(price) price, GROUP_CONCAT(title SEPARATOR ', ') title
    FROM order_product_options
    GROUP BY order_product_id 
) opo ON opo.order_product_id = op.id
INNER JOIN order_product_beneficiary opb ON opb.order_product_id = op.id
GROUP BY op.id

Demo

Based on your description, I think you just want DISTINCT in the GROUP_CONCAT() . However, that won't work because of the duplicates (as explained in a comment but not the question).

One solution is to include the ids in the results:

SELECT op.id,
       GROUP_CONCAT(DISTINCT opo.title, '(', opo.id, ')' SEPARATOR ', ') AS options,
       SUM(opo.price) AS options_price,
       GROUP_CONCAT(DISTINCT opb.name, '(', opb.id, ')' SEPARATOR ', ') AS 'beneficiaries'
FROM order_product op INNER JOIN
      order_product_options opo
      ON opo.order_product_id = op.id INNER JOIN
      order_product_beneficiary opb 
      ON opb.order_product_id = op.id
GROUP BY op.id;

This is not exactly your results, but it might suffice.

EDIT:

Oh, I see. You are joining along two different dimensions and getting a Cartesian product. The solution is to aggregate before joining:

SELECT op.id, opo.options, opo.options_price,
       opb.beneficiaries
FROM order_product op INNER JOIN
     (SELECT opo.order_product_id,
             GROUP_CONCAT(opo.title SEPARATOR ', ') AS options,
             SUM(opo.price) AS options_price
      FROM order_product_options opo
      GROUP BY opo.order_product_id
     ) opo
     ON opo.order_product_id = op.id INNER JOIN
     (SELECT opb.order_product_id,
             GROUP_CONCAT(opb.name SEPARATOR ', ') AS beneficiaries
      FROM order_product_beneficiary opb 
      GROUP BY opb.order_product_id
     ) opb
     ON opb.order_product_id = op.id;

Here is the SQL Fiddle.

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