クエリが機能しない理由
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
そのグループ内でその価格を持つ商品の を見つけます。
重要:グループ内で複数の商品の最低価格が等しい場合、このクエリはそれらすべてを返します。グループごとに1 つの結果のみが必要な場合は、タイブレーカーを指定する必要があります。次に例を示します。
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
この最後のクエリは、「外部」レベルで 2 つの結合を実行します。
goodId
「各グループの最安価格」テーブルを使用してグループを結合し、最安goodId
価格を取得します
- 次に、商品テーブルと結合して、これで商品の名前を取得します
goodId
複数の商品が最安値で並んでいても、グループごとに 1 つの商品のみが生産されます。