これは、ほとんどのMySQLプログラマーが直面する古典的なハードルです。
- 列
ticket_id
があります これがGROUP BY
への引数です 。この列の個別の値は、グループを定義します。 - 列があります
incoming_time
これがMAX()
への引数です 。各グループの行に対するこの列の最大値は、MAX()
の値として返されます。 。 - テーブル記事の他のすべての列があります。 これらの列に返される値は任意であり、
MAX()
と同じ行からではありません。 値が発生します。
データベースは、最大値が発生するのと同じ行から値が必要であることを推測できません。
次の場合について考えてください。
-
同じ最大値が発生する複数の行があります。
article.*
の列を表示するために使用する行 ? -
MIN()
の両方を返すクエリを記述します およびMAX()
。これは合法ですが、どの行をarticle.*
にする必要があります 表示しますか?SELECT article.* , MIN(article.incoming_time), MAX(article.incoming_time) FROM ticket, article WHERE ticket.id = article.ticket_id AND ticket.queue_id = 1 GROUP BY article.ticket_id
-
AVG()
などの集計関数を使用します またはSUM()
、その値を持つ行はありません。データベースはどの行を表示するかをどのように推測しますか?SELECT article.* , AVG(article.incoming_time) FROM ticket, article WHERE ticket.id = article.ticket_id AND ticket.queue_id = 1 GROUP BY article.ticket_id
ほとんどのブランドのデータベース(およびSQL標準自体)では、許可されていません あいまいさのために、このようなクエリを作成します。集計関数内にない、またはGROUP BY
で名前が付けられている列を、選択リストに含めることはできません。 条項。
MySQLはより寛容です。これを行うことができ、あいまいさのないクエリを作成するのはあなたに任されています。あいまいな場合は、グループ内で物理的に最初の行から値を選択します(ただし、これはストレージエンジン次第です)。
価値があるので、SQLiteにもこの動作がありますが、最後を選択します あいまいさを解決するためにグループ内の行。図に行きます。 SQL標準で何をすべきかが規定されていない場合は、ベンダーの実装次第です。
問題を解決できるクエリは次のとおりです。
SELECT a1.* , a1.incoming_time AS maxtime
FROM ticket t JOIN article a1 ON (t.id = a1.ticket_id)
LEFT OUTER JOIN article a2 ON (t.id = a2.ticket_id
AND a1.incoming_time < a2.incoming_time)
WHERE t.queue_id = 1
AND a2.ticket_id IS NULL;
つまり、行を探します(a1
)他の行がない(a2
)同じticket_id
を使用 そしてより大きなincoming_time
。これ以上incoming_time
がない場合 が見つかった場合、LEFTOUTERJOINは一致ではなくNULLを返します。