3つの異なるテーブルがあり、特定の値(COUNT(track)
)を持つ行の数を数え、tracks.id
でグループ化し、ユーザーごとに1つの結果(tracks.uid
)だけで並べ替える必要があります。
私の3つのテーブル:
`users`
+--------+-------------------+
| `idu` | `username` |
+--------+-------------------+
| 567 | 'TrainingPuppy' |
| 687 | 'BathroomMakeover'|
| 45 | 'PoshNachos' |
| 15 | 'SewingButtons' |
+--------+-------------------+
`views`
+--------+------+---------+
| `id` | `by` | `track` |
+--------+------+---------+
| 1 | 5 | 55 |
| 2 | 5 | 55 |
| 3 | 67 | 55 |
| 4 | 6 | 29 |
| 5 | 125 | 2 |
| 6 | 5 | 698 |
| 7 | 5 | 698 |
+--------+------+---------+
`tracks`
+--------+-------+-----------------------+---------------------+
| `id` | `uid` | `title` | `time` |
+--------+-------+-----------------------+---------------------+
| 2 | 15 | 'Worf is in the air' | 2016-02-11 22:57:35 |
| 29 | 567 | 'Stargold' | 2016-08-11 22:57:28 |
| 55 | 567 | 'No love liers' | 2016-10-11 22:57:51 |
| 698 | 567 | 'Lofe' | 2016-11-11 22:57:44 |
+--------+-------+-----------------------+---------------------+
だから私は試しました:
SELECT `views`.`track`, `tracks`.*, `users`.*, COUNT(`track`) as `count`
FROM `views`,`tracks`,`users`
WHERE `views`.`track` = `tracks`.`id`
AND `tracks`.`uid` = `users`.`idu`
GROUP BY `tracks`.`uid`
ORDER BY `count`
DESC LIMIT 0, 20
[〜#〜]結果[〜#〜]
+--------+-------+---------+---------------------+----------+-----------------------+---------------------+
| `id` | `uid` | `count` | `username` | `track` | `title` | `time` |
+--------+-------+---------+---------------------+----------+-----------------------+---------------------+
| 29 | 567 | 6 | 'TrainingPuppy' | 29 | 'Stargold' | 2016-10-11 22:57:51 |
| 2 | 15 | 1 | 'SewingButtons' | 2 | 'Worf is in the air' | 2016-02-11 22:57:35 |
+--------+-------+---------+---------------------+----------+-----------------------+---------------------+
代わりに、各ユーザーの1つのトラック(ビューテーブルで最もカウントされる)のみを選択する必要があります。以下のようなもの:
+--------+-------+---------+---------------------+----------+---------------------+---------------------+
| `id` | `uid` | `count` | `username` | `track` | `title` | `time` |
+--------+-------+---------+---------------------+----------+---------------------+---------------------+
| 55 | 567 | 3 | 'TrainingPuppy' | 55 | 'No love liers' | 2016-10-11 22:57:51 |
| 2 | 15 | 1 | 'SewingButtons' | 2 | 'Worf is in the air'| 2016-02-11 22:57:35 |
+--------+-------+---------+---------------------+----------+---------------------+---------------------+
どうすればこれを達成できますか?
テーブルといくつかのサンプルデータを設定します。
drop table if exists users;
drop table if exists views;
drop table if exists tracks;
create table users
(idu int
,username varchar(30));
create table views
(id int
,`by` int
,track int);
create table tracks
(id int
,uid int
,title varchar(30)
,time datetime);
insert into users values
(567,'TrainingPuppy'),
(687,'BathroomMakeover'),
( 45,'PoshNachos'),
( 15,'SewingButtons');
insert into views values
(1, 5, 55),
(2, 5, 55),
(3, 67, 55),
(4, 6, 29),
(5,125, 2),
(6, 5,698),
(7, 5,698);
insert into tracks values
( 2, 15,'Worf is in the air','2016-02-11 22:57:35'),
( 29,567,'Stargold' ,'2016-08-11 22:57:28'),
( 55,567,'No love liers' ,'2016-10-11 22:57:51'),
(698,567,'Lofe' ,'2016-11-11 22:57:44');
(ANSI標準group by
)クエリから始めて、カウントを取得します。
select tracks.id,
tracks.uid,
count(*) as ucount,
users.username,
views.track,
tracks.title,
tracks.time
from tracks
join views
on views.track = tracks.id
join users
on users.idu = tracks.uid
group by tracks.id,
tracks.uid,
users.username,
views.track,
tracks.title,
tracks.time
上記の「user_counts」を呼び出して、ucount desc
で順序付けされたusername
のランキングを生成するクエリを作成します。
select id,
uid,
ucount,
username,
track,
title,
time,
@user_rank := if(@current_username = username, @user_rank:=@user_rank+1, 1) as user_rank,
@current_username := username
from user_counts,
-- initialize our variables
join (select @user_rank := 0, @current_username := 'abcdefg') r
order by username, ucount desc
次に、これを最後のselect
でラップし、ランキングが「1」の行のみが表示されるようにします。すべてを1つのクエリにまとめて、次のようにします。
select id,
uid,
ucount as 'count',
username,
track,
title,
time
from (select id,
uid,
ucount,
username,
track,
title,
time,
@user_rank := if(@current_username = username, @user_rank:=@user_rank+1, 1) as user_rank,
@current_username := username
from (select tracks.id,
tracks.uid,
count(*) as ucount,
users.username,
views.track,
tracks.title,
tracks.time
from tracks
join views
on views.track = tracks.id
join users
on users.idu = tracks.uid
group by tracks.id,
tracks.uid,
users.username,
views.track,
tracks.title,
tracks.time) user_counts
-- initialize our variables
join (select @user_rank := 0, @current_username := 'abcdefg') r
order by username, ucount desc) dt
where user_rank = 1
order by ucount desc, username
そして結果:
id uid count username track title time
-- --- ----- ------------- ----- ------------------ -------------------
55 567 3 TrainingPuppy 55 No love liers 2016-10-11 22:57:51
2 15 1 SewingButtons 2 Worf is in the air 2016-02-11 22:57:35
いくつかのフィドル:
注:指定されたusername
が複数のトラック/タイトルに対して同じmax(count)を持つ場合、このソリューションは1つのレコードのみを表示します。複数のレコードを表示するには、それらのレコードが確実に同じランキング(つまり、user_rank = 1
)を受け取るように調整する必要があります。