基于最小单元格值的MySQL联接表行

基于最小单元格值的MySQL联接表行,mysql,sql,left-join,greatest-n-per-group,Mysql,Sql,Left Join,Greatest N Per Group,MySQL数据库中有两个表,如下所示: product_id | product_name | supplier_id | part_no | cost -----------+---------------+---------------+------------+--------- 1 | shirt | 1 | s1p1 | 5.00 2 | pants | 2

MySQL数据库中有两个表,如下所示:

product_id | product_name  | supplier_id   |  part_no   | cost
-----------+---------------+---------------+------------+---------
1          | shirt         | 1             |  s1p1      | 5.00
2          | pants         | 2             |  s2p2      | 10.00
3          | socks         | 2             |  s3p3      | 5.00
产品:

product_id | product_name
-----------+-------------
1          |  shirt
2          |  pants
3          |  socks
产品供应商:id是主键

id  |  supplier_id  |  product_id  |  part_no  |  cost
----+---------------+--------------+-----------+--------
1   |  1            |  1           | s1p1      | 5.00
2   |  1            |  2           | s1p2      | 15.00
3   |  1            |  3           | s1p3      | 25.00
4   |  2            |  1           | s2p1      | 50.00
5   |  2            |  2           | s2p2      | 10.00
6   |  2            |  3           | s2p3      | 5.00
我的目标是一个查询,用于联接表,并为每个产品输出一行,该产品与对应供应商行中的所有字段联接,成本最低,如下所示:

product_id | product_name  | supplier_id   |  part_no   | cost
-----------+---------------+---------------+------------+---------
1          | shirt         | 1             |  s1p1      | 5.00
2          | pants         | 2             |  s2p2      | 10.00
3          | socks         | 2             |  s3p3      | 5.00
目前,我确实编写了以下查询,这似乎很有效,但我想从任何更有经验的SQL用户那里了解是否有更干净、更高效或其他更好的解决方案?或者如果我的代码有什么本质上的错误

SELECT p.product_id, p.product_name, s. supplier_id, s.part_no, s.cost
FROM product p
LEFT JOIN product_supplier s ON
   (s.id = (SELECT s2.id 
            FROM product_supplier s2
            WHERE s2.product_id = p.product_id
            ORDER BY s2.cost LIMIT 1));
我会说:

select p.product_id, p.product_name, s.supplier_id, s.part_no, s.cost
  from product p
  join product_supplier s
    on p.product_id = s.product_id
  join (select product_id, min(cost) as min_cost
          from product_supplier
         group by product_id) v
    on s.product_id = v.product_id
   and s.cost = v.min_cost
我看不出外部连接有什么意义。是否所有产品都在产品供应商表上?如果不是,则外部连接是有意义的,如果是这种情况,请将别名为v的内联视图连接更改为左连接

上面的查询可能比您的查询运行得快一点,因为子查询不是针对每一行运行的。当前子查询与产品的每一行相关

如果您想消除联系,而不想随意这样做,您可以在结果末尾添加一个随机数,将查询放入内联视图,然后为每个组选择最低/最高/etc.随机数。以下是一个例子:

select product_id, product_name, supplier_id, part_no, cost, min(rnd)
  from (select p.product_id,
               p.product_name,
               s.supplier_id,
               s.part_no,
               s.cost,
               rand() as rnd
          from product p
          join product_supplier s
            on p.product_id = s.product_id
          join (select product_id, min(cost) as min_cost
                 from product_supplier
                group by product_id) v
            on s.product_id = v.product_id
           and s.cost = v.min_cost) x
 group by product_id, product_name, supplier_id, part_no, cost

如果出于某种原因,您不希望随机数返回到输出中,您可以将上面的整个查询放入一个内联视图中,并从中选择除随机数以外的所有列。

谢谢。。这正是我所希望的。我还在学习sql和第二个连接内联视图的语法?对我来说是全新的。我很欣赏这种推动。是的,理论上,每个产品都应该至少有一个对应的供应商行——尽管在现实中很难说是否总是这样。from子句中的子查询指的是一些东西,“内联视图”是一个与oracle合作的人通常使用的术语,有些人还将其称为“子选择”或“派生表”,或仅称为子查询。基本上,如果您单独运行该查询(我将其别名为v),您将获得每个产品的最低成本,将该查询作为更大查询的一部分放入内联视图,您可以加入该查询,例如,将行限制为成本等于给定项目最低成本的行。使用join将导致任何没有供应商的产品被淘汰。如果在“产品到产品”供应商的方向上使用“左联接”,它们将不会被消除。我发现的这个查询的问题是,如果两个供应商的成本相同,它可以返回多行,而我的查询总是只返回一行。在成本相同的情况下,我不介意选择是否随意——但重要的是,结果零件号与供应商id匹配。