概要
SQLにargmax
やargmin
は無いです。
なのでmax
をSELECT
するサブクエリとINNER JOIN
することによってがんばります。
argmax
やargmin
ってなぁに
argmax
というのは、何か値を最大にするものを得るときに使うものです。
max
は最大でいくつになるかを得るときに使う点で異なります。
逆にargmin
というのは、何か値を最小にするものを得るときに使うものです。
これもmin
は最小でいくつになるかを得るときに使う点で異なります。
たとえば、記事がたくさんあったとき、「いいねの一番多い記事」はargmax
ですが、その「一番多くついたいいねの数」はmax
です。
やってみる
今回は記事の著者ごとに一番いいねの多い記事をSELECT
しようと思います。
面倒なのでSQLite3で試してみます。
お試し用データ
BEGIN EXCLUSIVE TRANSACTION;
CREATE TABLE IF NOT EXISTS `articles` (`id` INTEGER PRIMARY KEY AUTOINCREMENT,`author_id` INTEGER NOT NULL,`likes` INTEGER DEFAULT 0);
INSERT INTO `articles` (`author_id`,`likes`) VALUES (1,120);
INSERT INTO `articles` (`author_id`,`likes`) VALUES (1,120);
INSERT INTO `articles` (`author_id`,`likes`) VALUES (1,100);
INSERT INTO `articles` (`author_id`,`likes`) VALUES (2,100);
INSERT INTO `articles` (`author_id`,`likes`) VALUES (2,80);
INSERT INTO `articles` (`author_id`,`likes`) VALUES (2,80);
INSERT INTO `articles` (`author_id`,`likes`) VALUES (3,100);
INSERT INTO `articles` (`author_id`,`likes`) VALUES (4,120);
COMMIT;
ふつうに全部SELECT
するとこんな感じです。
id author_id likes
-- --------- -----
1 1 120
2 1 120
3 1 100
4 2 100
5 2 80
6 2 80
7 3 100
8 4 120
今回の結論です。
SELECT `a`.* FROM `articles` AS `a` INNER JOIN (
SELECT `author_id`,max(`likes`) AS `likes` FROM `articles` GROUP BY `author_id`
) AS `b` ON `a`.`author_id`=`b`.`author_id` WHERE `a`.`likes`=`b`.`likes`;
では試してみます。
id author_id likes
-- --------- -----
1 1 120
2 1 120
4 2 100
7 3 100
8 4 120
ちゃんとauthor_id
ごとにlikes
が最大のものがすべて得られましたしました🎉
author_id=1
のものもちゃんと2つあります🎉
結論
サブクエリでmax
をGROUP BY
して、それとINNER JOIN
するだけでした。