web-dev-qa-db-ja.com

サブクエリでMIN()を使用する代わりに?

次のfooテーブルがあります。

+----+--------+-------+
| id |  name  |  qty  |
+----+--------+-------+
| 1  |  John  |   3   |
| 2  |  John  |   1   |
| 3  |  Mary  |   5   |
| 4  |  Mary  |   2   |
| 5  |  Gary  |   3   |
| 6  |  Gary  |   4   |
| 7  |  Gary  |   5   |
+----+--------+-------+

idでグループ化された最小限のnameQtynameのみを選択したいのですが、次のような結果になります。

+----+--------+
| id |  name  |
+----+--------+
| 2  |  John  |
| 4  |  Mary  |
| 5  |  Gary  |
+----+--------+

私がこれを行うことができた唯一の方法は、次の操作によるものでした:

SELECT id, name FROM (SELECT id, name, MIN(qty) FROM foo GROUP BY name) AS a;

それを行うためのより「美しい」(または冗長性が低い)方法はありますか?

3
LucasBr

あなたが述べるように、これは副選択なしでは実行できません。
2つのステップが含まれます。
1。名前ごとに、MIN(qty)のレコードを見つけます。
2。そのレコードのIDを返します。

他のアプローチもありますが、2つのステップが残ります。

投稿したクエリに不足している情報があるようです。これで全部です。

    SELECT id, name 
FROM (
    SELECT name, MIN(qty) minqty
    FROM foo fs
    GROUP BY name
) AS a
    JOIN foo f
        ON f.name = fs.name
        AND f.qty = fs.minqty
5
Shooter McGavin

クエリは部分グループを使用します。これは、MySQLの古いバージョン(デフォルト設定)で許可されており、おそらく長年にわたって多くの苦痛と不可解なバグを引き起こしています。これが発生する理由を確認します。考慮してください:

select id, name, min(qty) from foo group by name;
+----+------+----------+
| id | name | min(qty) |
+----+------+----------+
|  1 | John |        1 |
|  3 | Mary |        2 |
+----+------+----------+

数量に関連しないIDが結果に表示されるように、なぜですか?名前だけでグループ化しているため、名前ごとに2つのIDを選択できます。 MySQLはこれらのグループからJohnとMaryのIDをランダムに選択します。結果は正しい場合もあれば、正しくない場合もあります。あなたがする必要があるのは、各名前の最小数量を選択し、その数量と名前を使用して、それに関連付けられているIDを見つけることです。 @Kondybasと@ Shooter-McGavinの両方が、回答でこれを行う方法を示しています。

5
Lennart

すばらしいですが、クエリが間違った結果を返します。返された行のidは、最小限のqtyを含む行に関連付けられていません。しかし、あなたはそのような方法で望ましい結果を得ることができます:

SELECT w.id, w.name 
  FROM foo AS w
  JOIN ( SELECT name, MIN(qty) AS qty
           FROM foo 
           GROUP BY name
       ) AS z ON  z.name = w.name
              AND z.qty = w.qty
;
4
Kondybas