如何在子查询或分组上获取多个列

时间:2017-10-03 17:04:58

标签: mysql join group-by subquery

我在MySql上有两个表,第一个包含 ID 和某些产品的名称。我必须为每种产品获得最便宜的品牌/市场组合。所以,我在两个表中插入了一些itens:

更新:插入新产品(床),但没有' Product_Brand_Market'测试LEFT JOIN。 更新:更改了一些产品价格以便进行更好的测试。

CREATE TABLE Product(
   id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
   name VARCHAR(20) NOT NULL);  

CREATE TABLE Product_Brand_Market(
   product INT UNSIGNED,
   market INT UNSIGNED,   /*this will be a FOREIGN KEY*/
   brand INT UNSIGNED,    /*this will be a FOREIGN KEY*/
   price DECIMAL(10,2) UNSIGNED NOT NULL,
   PRIMARY KEY(product, market, brand),
   CONSTRAINT FOREIGN KEY (product) REFERENCES Product(id));

INSERT INTO Product
(name) VALUES
('Chair'),   /*will get id=1*/
('Table'),   /*will get id=2*/
('Bed');     /*will get id=3*/

INSERT INTO Product_Brand_Market
(product, market, brand, price) VALUES
(1, 1, 1, 8.00), /*cheapest chair (brand=1, market=1)*/
(1, 1, 2, 8.50),
(1, 2, 1, 9.00),
(1, 2, 2, 9.50),
(2, 1, 1, 11.50),
(2, 1, 2, 11.00),
(2, 2, 1, 10.50),
(2, 2, 2, 10.00); /*cheapest table (brand=2, market=2)*/
                  /*no entries for bed, must return null*/

并尝试使用以下代码来获取所需的值:

更新:更改了LEFT JOIN的INNER JOIN。

SELECT p.id product, MIN(pbm.price) price, pbm.brand, pbm.market
FROM Product p
LEFT JOIN Product_Brand_Market pbm
    ON p.id = pbm.product
GROUP BY p.id;

退回的价格还可以,但我得错了钥匙:

| product | price | brand | market |
|---------|-------|-------|--------|
| 1       | 8     | 1     | 1      |
| 2       | 10    | 1     | 1      |
| 3       | null  | null  | null   |

所以我能想到解决问题的唯一方法是使用子查询,但我不得不使用两个子查询来获得品牌和市场:

SELECT
p.id product,
(
    SELECT pbm.brand
    FROM Product_Brand_Market pbm
    WHERE p.id = pbm.product
    ORDER BY pbm.price
    LIMIT 1
) as brand,
(
    SELECT pbm.market
    FROM Product_Brand_Market pbm
    WHERE p.id = pbm.product
    ORDER BY pbm.price
    LIMIT 1
) as market
FROM Product p;

返回所需的表格:

| product | brand | market |
|---------|-------|--------|
| 1       | 1     | 1      |
| 2       | 2     | 2      |
| 3       | null  | null   |

但我想知道我是否真的应该使用这两个相似的子查询,或者有更好的方法在MySql上做任何想法?

1 个答案:

答案 0 :(得分:0)

在WHERE子句中使用带有LIMIT 1的相关子查询:

SELECT product, brand, market
FROM Product_Brand_Market pbm
WHERE (pbm.brand, pbm.market) = (
    SELECT pbm1.brand, pbm1.market
    FROM Product_Brand_Market pbm1
    WHERE pbm1.product = pbm.product
    ORDER BY pbm1.price ASC
    LIMIT 1
)

每个产品只会返回一行,即使其中有两个或多个具有相同的最低价格。

演示:http://rextester.com/UIC44628

更新

要获得所有产品,即使它们在Product_Brand_Market表中没有条目,您也需要LEFT JOIN。请注意,条件应移至ON子句。

SELECT p.id as product, pbm.brand, pbm.market
FROM Product p
LEFT JOIN Product_Brand_Market pbm
  ON   pbm.product = p.id
  AND (pbm.brand, pbm.market) = (
    SELECT pbm1.brand, pbm1.market
    FROM Product_Brand_Market pbm1
    WHERE pbm1.product = pbm.product
    ORDER BY pbm1.price ASC
    LIMIT 1
  );

演示:http://rextester.com/MGXN36725

以下查询可能会更好地利用您的JOIN来加入:

SELECT p.id as product, pbm.brand, pbm.market
FROM Product p
LEFT JOIN Product_Brand_Market pbm
  ON (pbm.product, pbm.market, pbm.brand) = (
    SELECT pbm1.product, pbm1.market, pbm1.brand
    FROM Product_Brand_Market pbm1
    WHERE pbm1.product = p.id
    ORDER BY pbm1.price ASC
    LIMIT 1
  );

Product_Brand_Market(product, price)上的索引也应该有助于提高子查询的性能。