我有两个表(仅列出对该问题很重要的字段):
t_groups
t_goods
现在我需要一个查询,它可以选择每个组中最便宜商品的组名和名称。试着这样做:
SELECT gr.groupId, grname, g.name
FROM t_groups AS gr
LEFT JOIN (SELECT * FROM t_goods ORDER BY PRICE ASC LIMIT 1) AS g
ON g.groupId = gr.groupId
但它不起作用 - 在g.name字段中返回NULL。可以很容易地解释:
JOIN语句中的SELECT首先选择最便宜的商品,然后尝试通过groupId“过滤”。显然,它只适用于最便宜的组织所属的组。
我该如何解决这个问题?
答案 0 :(得分:5)
SELECT gr.groupId, grname, g.name
FROM t_groups AS gr
LEFT JOIN (SELECT * FROM t_goods ORDER BY PRICE ASC LIMIT 1) AS g
ON g.groupId = gr.groupId
内部查询选择数据库中绝对最便宜的(无论组)。因此,当您LEFT JOIN
到此结果集的组时,只有实际包含普遍最便宜的商品的组才有匹配的行(该组应该正确填充g.name
列)。但是,由于LEFT JOIN
的工作方式,所有其他群组都会NULL
作为g
中所有列的值。
首先,您需要在每组中选择最便宜的价格。这很简单:
SELECT groupId, MIN(price) AS minPrice FROM t_goods GROUP BY (groupId)
然而,如果没有关联的goodId
,最便宜的价格就无用了。问题是编写类似的内容没有意义:
/* does not make sense, although MySql has historically allowed it */
SELECT goodId, groupId, MIN(price) AS minPrice FROM t_goods GROUP BY (groupId)
原因是您无法选择未分组的列(即goodId
),除非您将其包装在聚合函数(例如MIN
)中:我们不知道哪个 goodId
您希望从那些共享相同groupId
。
获得每组中最便宜货物的goodId
的正确,便携方式是
SELECT goodId, temp.groupId, temp.minPrice
FROM (SELECT groupId, MIN(price) AS minPrice FROM t_goods GROUP BY groupId) temp
JOIN t_goods ON temp.groupId = t_goods.groupId AND temp.minPrice = t_goods.price)
上述查询首先找出每组最便宜的价格,然后再次加入货物表,以查找该组中具有该价格的货物的goodId
。
重要提示:如果多个商品在组中的价格相同,则此查询将返回所有。如果您只需要每组一个结果,则必须指定决胜局,例如:
SELECT MIN(goodId), temp.groupId, MIN(temp.minPrice)
FROM (SELECT groupId, MIN(price) AS minPrice FROM t_goods GROUP BY groupId) temp
JOIN t_goods ON temp.groupId = t_goods.groupId AND temp.minPrice = t_goods.price)
GROUP BY temp.groupId
通过这个查询,您可以找到每个组中最便宜商品的名称和价格(最低goodId
将用作决胜局):
SELECT groupId, grname, gd.name, t3.minPrice
FROM t_groups AS gr
LEFT JOIN (SELECT MIN(goodId) AS goodId, t1.groupId, MIN(t1.minPrice) AS minPrice
FROM (SELECT groupId, MIN(price) AS minPrice FROM t_goods GROUP BY groupId) t1
JOIN t_goods ON t1.groupId = t_goods.groupId AND t1.minPrice = t_goods.price
) t2
) t3 ON gr.groupId = t3.groupId
LEFT JOIN t_goods gd ON t3.goodId = gd.goodId
此最终查询在其“外部”级别执行两个连接:
goodId
和每个组最便宜的价格”表格加入群组,以获得goodId
和最便宜的价格goodId
每组只生产一种商品,即使多件商品并列最便宜。
答案 1 :(得分:1)
以下是你如何做到的:
select
t_groups.grname as `name of group`,
t_goods.name as `name of good`
from (
select
groupId,
min(price) as min_price
from t_goods
group by groupId
) as mins
inner join t_goods
on mins.groupId = t_goods.groupId and mins.min_price = t_goods.price
inner join t_groups
on mins.groupId = t_groups.groupId
这是如何运作的:
mins
子查询获取每个groupId的最低价格mins
到t_goods
会将所有商品中的所有商品拉出来。请注意,如果有多个商品的最低价格t_groups
以获取群组名称您的查询可能会返回NULL,因为它是left join
只有一行的子查询。