MySQLのtableのjoinについて
今日はMySQLの使い方、特にtableのjoinについてメモします。
MySQLではtableをjoinすることで、新しいエンティティを作ることができる。
例えば、topic_tableがとある。
+----+---------------+-------------+---------+
| id | name | category_id | user_id |
+----+---------------+-------------+---------+
| 1 | topic test 1 | 5 | 9 |
| 2 | topic test 2 | 6 | 10 |
| 3 | topic test 3 | 7 | 11 |
| 4 | topic test 4 | 1 | 12 |
| 5 | topic test 5 | 2 | 13 |
| 6 | topic test 6 | 3 | 14 |
| 7 | topic test 7 | 4 | 15 |
| 8 | topic test 8 | 5 | 16 |
| 9 | topic test 9 | 6 | 17 |
| 10 | topic test 10 | 7 | 18 |
| 11 | topic test 11 | 1 | 19 |
| 12 | topic test 12 | 2 | 20 |
| 13 | topic test 13 | 3 | 1 |
| 14 | topic test 14 | 4 | 2 |
| 15 | topic test 15 | 5 | 3 |
| 16 | topic test 16 | 6 | 4 |
| 17 | topic test 17 | 7 | 5 |
| 18 | topic test 18 | 1 | 6 |
| 19 | topic test 19 | 2 | 7 |
| 20 | topic test 20 | 3 | 8 |
| 21 | topic test 21 | 4 | 9 |
| 22 | topic test 22 | 5 | 10 |
| 23 | topic test 23 | 6 | 11 |
| 24 | topic test 24 | 7 | 12 |
| 25 | topic test 25 | 1 | 13 |
| 26 | topic test 26 | 2 | 14 |
| 27 | topic test 27 | 3 | 15 |
| 28 | topic test 28 | 4 | 16 |
| 29 | topic test 29 | 5 | 17 |
| 30 | topic test 30 | 6 | 18 |
| 31 | topic test 31 | 7 | 19 |
| 32 | topic test 32 | 1 | 20 |
| 33 | topic test 33 | 2 | 1 |
| 34 | topic test 34 | 3 | 2 |
| 35 | topic test 35 | 4 | 3 |
| 36 | topic test 36 | 5 | 4 |
| 37 | topic test 37 | 6 | 5 |
| 38 | topic test 38 | 7 | 6 |
| 39 | topic test 39 | 1 | 7 |
| 40 | topic test 40 | 2 | 8 |
| 41 | topic test 1 | 5 | 9 |
| 42 | topic test 2 | 6 | 10 |
| 43 | topic test 3 | 7 | 11 |
| 44 | topic test 4 | 1 | 12 |
| 45 | topic test 5 | 2 | 13 |
| 46 | topic test 6 | 3 | 14 |
| 47 | topic test 7 | 4 | 15 |
| 48 | topic test 8 | 5 | 16 |
| 49 | topic test 9 | 6 | 17 |
| 50 | topic test 10 | 7 | 18 |
| 51 | topic test 11 | 1 | 19 |
| 52 | topic test 12 | 2 | 20 |
| 53 | topic test 13 | 3 | 1 |
| 54 | topic test 14 | 4 | 2 |
| 55 | topic test 15 | 5 | 3 |
| 56 | topic test 16 | 6 | 4 |
| 57 | topic test 17 | 7 | 5 |
| 58 | topic test 18 | 1 | 6 |
| 59 | topic test 19 | 2 | 7 |
| 60 | topic test 20 | 3 | 8 |
| 61 | topic test 21 | 4 | 9 |
| 62 | topic test 22 | 5 | 10 |
| 63 | topic test 23 | 6 | 11 |
| 64 | topic test 24 | 7 | 12 |
| 65 | topic test 25 | 1 | 13 |
| 66 | topic test 26 | 2 | 14 |
| 67 | topic test 27 | 3 | 15 |
| 68 | topic test 28 | 4 | 16 |
| 69 | topic test 29 | 5 | 17 |
| 70 | topic test 30 | 6 | 18 |
| 71 | topic test 31 | 7 | 19 |
| 72 | topic test 32 | 1 | 20 |
| 73 | topic test 33 | 2 | 1 |
| 74 | topic test 34 | 3 | 2 |
| 75 | topic test 35 | 4 | 3 |
| 76 | topic test 36 | 5 | 4 |
| 77 | topic test 37 | 6 | 5 |
| 78 | topic test 38 | 7 | 6 |
| 79 | topic test 39 | 1 | 7 |
| 80 | topic test 40 | 2 | 8 |
+----+---------------+-------------+---------+
(*詳しく説明するためテストデータを必要以上に入れている。)
このでのtopicは、ユーザーがあるカテゴリーの下で作るので、"category_id"と"user_id"でどのカテゴリーにどのユーザーが作ったのかを見分けることができる。
次にユーザーテーブルを見てみる。
+----+--------------------+------------------------+
| id | name | email |
+----+--------------------+------------------------+
| 1 | usertest1 | usertest1@gmail.com |
| 2 | usertest2 | usertest2@gmail.com |
| 3 | usertest3 | usertest3@gmail.com |
| 4 | usertest4 | usertest4@gmail.com |
| 5 | usertest5 | usertest5@gmail.com |
| 6 | usertest6 | usertest6@gmail.com |
| 7 | usertest7 | usertest7@gmail.com |
| 8 | usertest8 | usertest8@gmail.com |
| 9 | usertest9 | usertest9@gmail.com |
| 10 | usertest10 | usertest10@gmail.com |
| 11 | usertest11 | usertest11@gmail.com |
| 12 | usertest12 | usertest12@gmail.com |
| 13 | usertest13 | usertest13@gmail.com |
| 14 | usertest14 | usertest14@gmail.com |
| 15 | usertest15 | usertest15@gmail.com |
| 16 | usertest16 | usertest16@gmail.com |
| 17 | usertest17 | usertest17@gmail.com |
| 18 | usertest18 | usertest18@gmail.com |
| 19 | usertest19 | usertest19@gmail.com |
| 20 | usertest20 | usertest20@gmail.com |
| 22 | usertest1 | usertest1@gmail.com |
| 23 | usertest2 | usertest2@gmail.com |
| 24 | usertest3 | usertest3@gmail.com |
| 25 | usertest4 | usertest4@gmail.com |
| 26 | usertest5 | usertest5@gmail.com |
| 27 | usertest6 | usertest6@gmail.com |
| 28 | usertest7 | usertest7@gmail.com |
| 29 | usertest8 | usertest8@gmail.com |
| 30 | usertest9 | usertest9@gmail.com |
| 31 | usertest10 | usertest10@gmail.com |
| 32 | usertest11 | usertest11@gmail.com |
| 33 | usertest12 | usertest12@gmail.com |
| 34 | usertest13 | usertest13@gmail.com |
| 35 | usertest14 | usertest14@gmail.com |
| 36 | usertest15 | usertest15@gmail.com |
| 37 | usertest16 | usertest16@gmail.com |
| 38 | usertest17 | usertest17@gmail.com |
| 39 | usertest18 | usertest18@gmail.com |
| 40 | usertest19 | usertest19@gmail.com |
| 41 | usertest20 | usertest20@gmail.com |
| 42 | usertest1 | usertest1@gmail.com |
| 43 | usertest2 | usertest2@gmail.com |
| 44 | usertest3 | usertest3@gmail.com |
| 45 | usertest4 | usertest4@gmail.com |
| 46 | usertest5 | usertest5@gmail.com |
| 47 | usertest6 | usertest6@gmail.com |
| 48 | usertest7 | usertest7@gmail.com |
| 49 | usertest8 | usertest8@gmail.com |
| 50 | usertest9 | usertest9@gmail.com |
| 51 | usertest10 | usertest10@gmail.com |
| 52 | usertest11 | usertest11@gmail.com |
| 53 | usertest12 | usertest12@gmail.com |
| 54 | usertest13 | usertest13@gmail.com |
| 55 | usertest14 | usertest14@gmail.com |
| 56 | usertest15 | usertest15@gmail.com |
| 57 | usertest16 | usertest16@gmail.com |
| 58 | usertest17 | usertest17@gmail.com |
| 59 | usertest18 | usertest18@gmail.com |
| 60 | usertest19 | usertest19@gmail.com |
| 61 | usertest20 | usertest20@gmail.com |
+----+--------------------+------------------------+
この二つのテーブルをjoinすることで、TopicAndUserのentityができる。
どういう意味かというと、このようなclassを作ることができる:
public class TopicAndUser {
private Integer topicId;
private String topicName;
private Integer categoryId;
private Integer userId;
private String userName;
//getters and setters
}
こうすることによって、mappingしたり、topicとuserの両方の情報が必要な時に一つのqueryで済むことができる。
で実際どうやるかというと、このようなSQLを使うと、
String sql = "SELECT topic.id AS topicId, topic.name AS topicName, topic.category_id AS categoryId, user.id AS userId, user.name AS userName FROM topic INNER JOIN user ON topic.user_id = user.id";
このようにテーブルをjoinしてくれる
+---------+---------------+------------+--------+------------+
| topicId | topicName | categoryId | userId | userName |
+---------+---------------+------------+--------+------------+
| 1 | topic test 1 | 5 | 9 | usertest9 |
| 2 | topic test 2 | 6 | 10 | usertest10 |
| 3 | topic test 3 | 7 | 11 | usertest11 |
| 4 | topic test 4 | 1 | 12 | usertest12 |
| 5 | topic test 5 | 2 | 13 | usertest13 |
| 6 | topic test 6 | 3 | 14 | usertest14 |
| 7 | topic test 7 | 4 | 15 | usertest15 |
| 8 | topic test 8 | 5 | 16 | usertest16 |
| 9 | topic test 9 | 6 | 17 | usertest17 |
| 10 | topic test 10 | 7 | 18 | usertest18 |
| 11 | topic test 11 | 1 | 19 | usertest19 |
| 12 | topic test 12 | 2 | 20 | usertest20 |
| 13 | topic test 13 | 3 | 1 | usertest1 |
| 14 | topic test 14 | 4 | 2 | usertest2 |
| 15 | topic test 15 | 5 | 3 | usertest3 |
| 16 | topic test 16 | 6 | 4 | usertest4 |
| 17 | topic test 17 | 7 | 5 | usertest5 |
| 18 | topic test 18 | 1 | 6 | usertest6 |
| 19 | topic test 19 | 2 | 7 | usertest7 |
| 20 | topic test 20 | 3 | 8 | usertest8 |
| 21 | topic test 21 | 4 | 9 | usertest9 |
| 22 | topic test 22 | 5 | 10 | usertest10 |
| 23 | topic test 23 | 6 | 11 | usertest11 |
| 24 | topic test 24 | 7 | 12 | usertest12 |
| 25 | topic test 25 | 1 | 13 | usertest13 |
| 26 | topic test 26 | 2 | 14 | usertest14 |
| 27 | topic test 27 | 3 | 15 | usertest15 |
| 28 | topic test 28 | 4 | 16 | usertest16 |
| 29 | topic test 29 | 5 | 17 | usertest17 |
| 30 | topic test 30 | 6 | 18 | usertest18 |
| 31 | topic test 31 | 7 | 19 | usertest19 |
| 32 | topic test 32 | 1 | 20 | usertest20 |
| 33 | topic test 33 | 2 | 1 | usertest1 |
| 34 | topic test 34 | 3 | 2 | usertest2 |
| 35 | topic test 35 | 4 | 3 | usertest3 |
| 36 | topic test 36 | 5 | 4 | usertest4 |
| 37 | topic test 37 | 6 | 5 | usertest5 |
| 38 | topic test 38 | 7 | 6 | usertest6 |
| 39 | topic test 39 | 1 | 7 | usertest7 |
| 40 | topic test 40 | 2 | 8 | usertest8 |
| 41 | topic test 1 | 5 | 9 | usertest9 |
| 42 | topic test 2 | 6 | 10 | usertest10 |
| 43 | topic test 3 | 7 | 11 | usertest11 |
| 44 | topic test 4 | 1 | 12 | usertest12 |
| 45 | topic test 5 | 2 | 13 | usertest13 |
| 46 | topic test 6 | 3 | 14 | usertest14 |
| 47 | topic test 7 | 4 | 15 | usertest15 |
| 48 | topic test 8 | 5 | 16 | usertest16 |
| 49 | topic test 9 | 6 | 17 | usertest17 |
| 50 | topic test 10 | 7 | 18 | usertest18 |
| 51 | topic test 11 | 1 | 19 | usertest19 |
| 52 | topic test 12 | 2 | 20 | usertest20 |
| 53 | topic test 13 | 3 | 1 | usertest1 |
| 54 | topic test 14 | 4 | 2 | usertest2 |
| 55 | topic test 15 | 5 | 3 | usertest3 |
| 56 | topic test 16 | 6 | 4 | usertest4 |
| 57 | topic test 17 | 7 | 5 | usertest5 |
| 58 | topic test 18 | 1 | 6 | usertest6 |
| 59 | topic test 19 | 2 | 7 | usertest7 |
| 60 | topic test 20 | 3 | 8 | usertest8 |
| 61 | topic test 21 | 4 | 9 | usertest9 |
| 62 | topic test 22 | 5 | 10 | usertest10 |
| 63 | topic test 23 | 6 | 11 | usertest11 |
| 64 | topic test 24 | 7 | 12 | usertest12 |
| 65 | topic test 25 | 1 | 13 | usertest13 |
| 66 | topic test 26 | 2 | 14 | usertest14 |
| 67 | topic test 27 | 3 | 15 | usertest15 |
| 68 | topic test 28 | 4 | 16 | usertest16 |
| 69 | topic test 29 | 5 | 17 | usertest17 |
| 70 | topic test 30 | 6 | 18 | usertest18 |
| 71 | topic test 31 | 7 | 19 | usertest19 |
| 72 | topic test 32 | 1 | 20 | usertest20 |
| 73 | topic test 33 | 2 | 1 | usertest1 |
| 74 | topic test 34 | 3 | 2 | usertest2 |
| 75 | topic test 35 | 4 | 3 | usertest3 |
| 76 | topic test 36 | 5 | 4 | usertest4 |
| 77 | topic test 37 | 6 | 5 | usertest5 |
| 78 | topic test 38 | 7 | 6 | usertest6 |
| 79 | topic test 39 | 1 | 7 | usertest7 |
| 80 | topic test 40 | 2 | 8 | usertest8 |
+---------+---------------+------------+--------+------------+
ここではたまたまtopicIdのオーダに並べられているだけで、本来はjoinした後はorderを使うのが基本:
mysql> SELECT topic.id AS topicId, topic.name AS topicName, topic.category_id AS categoryId, user.id AS userId, user.name AS userName FROM topic INNER JOIN user ON topic.user_id = user.id ORDER BY topic.id;
+---------+---------------+------------+--------+------------+
| topicId | topicName | categoryId | userId | userName |
+---------+---------------+------------+--------+------------+
| 1 | topic test 1 | 5 | 9 | usertest9 |
| 2 | topic test 2 | 6 | 10 | usertest10 |
| 3 | topic test 3 | 7 | 11 | usertest11 |
| 4 | topic test 4 | 1 | 12 | usertest12 |
| 5 | topic test 5 | 2 | 13 | usertest13 |
| 6 | topic test 6 | 3 | 14 | usertest14 |
| 7 | topic test 7 | 4 | 15 | usertest15 |
| 8 | topic test 8 | 5 | 16 | usertest16 |
| 9 | topic test 9 | 6 | 17 | usertest17 |
| 10 | topic test 10 | 7 | 18 | usertest18 |
| 11 | topic test 11 | 1 | 19 | usertest19 |
| 12 | topic test 12 | 2 | 20 | usertest20 |
| 13 | topic test 13 | 3 | 1 | usertest1 |
| 14 | topic test 14 | 4 | 2 | usertest2 |
| 15 | topic test 15 | 5 | 3 | usertest3 |
| 16 | topic test 16 | 6 | 4 | usertest4 |
| 17 | topic test 17 | 7 | 5 | usertest5 |
| 18 | topic test 18 | 1 | 6 | usertest6 |
| 19 | topic test 19 | 2 | 7 | usertest7 |
| 20 | topic test 20 | 3 | 8 | usertest8 |
| 21 | topic test 21 | 4 | 9 | usertest9 |
| 22 | topic test 22 | 5 | 10 | usertest10 |
| 23 | topic test 23 | 6 | 11 | usertest11 |
| 24 | topic test 24 | 7 | 12 | usertest12 |
| 25 | topic test 25 | 1 | 13 | usertest13 |
| 26 | topic test 26 | 2 | 14 | usertest14 |
| 27 | topic test 27 | 3 | 15 | usertest15 |
| 28 | topic test 28 | 4 | 16 | usertest16 |
| 29 | topic test 29 | 5 | 17 | usertest17 |
| 30 | topic test 30 | 6 | 18 | usertest18 |
| 31 | topic test 31 | 7 | 19 | usertest19 |
| 32 | topic test 32 | 1 | 20 | usertest20 |
| 33 | topic test 33 | 2 | 1 | usertest1 |
| 34 | topic test 34 | 3 | 2 | usertest2 |
| 35 | topic test 35 | 4 | 3 | usertest3 |
| 36 | topic test 36 | 5 | 4 | usertest4 |
| 37 | topic test 37 | 6 | 5 | usertest5 |
| 38 | topic test 38 | 7 | 6 | usertest6 |
| 39 | topic test 39 | 1 | 7 | usertest7 |
| 40 | topic test 40 | 2 | 8 | usertest8 |
| 41 | topic test 1 | 5 | 9 | usertest9 |
| 42 | topic test 2 | 6 | 10 | usertest10 |
| 43 | topic test 3 | 7 | 11 | usertest11 |
| 44 | topic test 4 | 1 | 12 | usertest12 |
| 45 | topic test 5 | 2 | 13 | usertest13 |
| 46 | topic test 6 | 3 | 14 | usertest14 |
| 47 | topic test 7 | 4 | 15 | usertest15 |
| 48 | topic test 8 | 5 | 16 | usertest16 |
| 49 | topic test 9 | 6 | 17 | usertest17 |
| 50 | topic test 10 | 7 | 18 | usertest18 |
| 51 | topic test 11 | 1 | 19 | usertest19 |
| 52 | topic test 12 | 2 | 20 | usertest20 |
| 53 | topic test 13 | 3 | 1 | usertest1 |
| 54 | topic test 14 | 4 | 2 | usertest2 |
| 55 | topic test 15 | 5 | 3 | usertest3 |
| 56 | topic test 16 | 6 | 4 | usertest4 |
| 57 | topic test 17 | 7 | 5 | usertest5 |
| 58 | topic test 18 | 1 | 6 | usertest6 |
| 59 | topic test 19 | 2 | 7 | usertest7 |
| 60 | topic test 20 | 3 | 8 | usertest8 |
| 61 | topic test 21 | 4 | 9 | usertest9 |
| 62 | topic test 22 | 5 | 10 | usertest10 |
| 63 | topic test 23 | 6 | 11 | usertest11 |
| 64 | topic test 24 | 7 | 12 | usertest12 |
| 65 | topic test 25 | 1 | 13 | usertest13 |
| 66 | topic test 26 | 2 | 14 | usertest14 |
| 67 | topic test 27 | 3 | 15 | usertest15 |
| 68 | topic test 28 | 4 | 16 | usertest16 |
| 69 | topic test 29 | 5 | 17 | usertest17 |
| 70 | topic test 30 | 6 | 18 | usertest18 |
| 71 | topic test 31 | 7 | 19 | usertest19 |
| 72 | topic test 32 | 1 | 20 | usertest20 |
| 73 | topic test 33 | 2 | 1 | usertest1 |
| 74 | topic test 34 | 3 | 2 | usertest2 |
| 75 | topic test 35 | 4 | 3 | usertest3 |
| 76 | topic test 36 | 5 | 4 | usertest4 |
| 77 | topic test 37 | 6 | 5 | usertest5 |
| 78 | topic test 38 | 7 | 6 | usertest6 |
| 79 | topic test 39 | 1 | 7 | usertest7 |
| 80 | topic test 40 | 2 | 8 | usertest8 |
+---------+---------------+------------+--------+------------+
というわけで、ここまではjoinの基本な使い方を説明した。
これは以前ここでも紹介した:
今回はこの上でちょっと他の使い方をしてみる。
今作ってるプロジェクトでは、特定のcategoryから指定した数だけのtopicを持ってくる。例えば、ページ1ではcategory_idが1の中からtopicを順番に5個displayし、ページ2ではcategory_idが1の次の5個のtopicを表示させる。
この場合に使うのが以下:
mysql> SELECT topic.id AS topicId, topic.name AS topicName, topic.category_id AS categoryId, user.id AS userId, user.name AS userName FROM topic INNER JOIN user ON topic.user_id = user.id WHERE topic.category_id = 1 AND topic.id >= 0 ORDER BY topic.id LIMIT 5;
+---------+---------------+------------+--------+------------+
| topicId | topicName | categoryId | userId | userName |
+---------+---------------+------------+--------+------------+
| 4 | topic test 4 | 1 | 12 | usertest12 |
| 11 | topic test 11 | 1 | 19 | usertest19 |
| 18 | topic test 18 | 1 | 6 | usertest6 |
| 25 | topic test 25 | 1 | 13 | usertest13 |
| 32 | topic test 32 | 1 | 20 | usertest20 |
+---------+---------------+------------+--------+------------+
そして2ページ目ではtopic.idのスタート位置を変えるだけでいい:
mysql> SELECT topic.id AS topicId, topic.name AS topicName, topic.category_id AS categoryId, user.id AS userId, user.name AS userName FROM topic INNER JOIN user ON topic.user_id = user.id WHERE topic.category_id = 1 AND topic.id >= 33 ORDER BY topic.id LIMIT 5;
+---------+---------------+------------+--------+------------+
| topicId | topicName | categoryId | userId | userName |
+---------+---------------+------------+--------+------------+
| 39 | topic test 39 | 1 | 7 | usertest7 |
| 44 | topic test 4 | 1 | 12 | usertest12 |
| 51 | topic test 11 | 1 | 19 | usertest19 |
| 58 | topic test 18 | 1 | 6 | usertest6 |
| 65 | topic test 25 | 1 | 13 | usertest13 |
+---------+---------------+------------+--------+------------+
こうすれば、一つのqueryでこのcategoryにあるtopicとuser情報を取得することができる。
それで今の問題は、新しい機能、"like機能を"を実装する際に、DBではどのユーザーがどのtopicに対してlikeしたかを保存する必要がある。
tableは以下のよう:
CREATE TABLE star_topic_user (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
user_id INT UNSIGNED NOT NULL,
topic_id INT UNSIGNED NOT NULL,
already_liked BOOLEAN DEFAULT FALSE,
CONSTRAINT FOREIGN KEY (user_id) REFERENCES USER (id),
CONSTRAINT FOREIGN KEY (topic_id) REFERENCES topic (id),
PRIMARY KEY (id)
);
ためしにテストデータを入れてみる:
mysql> INSERT INTO star_topic_user (user_id, topic_id, already_liked) VALUES (3, 11, true);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO star_topic_user (user_id, topic_id, already_liked) VALUES (3, 18, true);
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO star_topic_user (user_id, topic_id, already_liked) VALUES (3, 31, true);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO star_topic_user (user_id, topic_id, already_liked) VALUES (4, 1, true);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO star_topic_user (user_id, topic_id, already_liked) VALUES (4, 11, true);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO star_topic_user (user_id, topic_id, already_liked) VALUES (4, 32, true);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO star_topic_user (user_id, topic_id, already_liked) VALUES (5, 4, true);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO star_topic_user (user_id, topic_id, already_liked) VALUES (5, 11, true);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO star_topic_user (user_id, topic_id, already_liked) VALUES (5, 18, true);
Query OK, 1 row affected (0.00 sec)
mysql> select * from star_topic_user;
+----+---------+----------+---------------+
| id | user_id | topic_id | already_liked |
+----+---------+----------+---------------+
| 1 | 3 | 11 | 1 |
| 2 | 3 | 18 | 1 |
| 3 | 3 | 31 | 1 |
| 4 | 4 | 1 | 1 |
| 5 | 4 | 11 | 1 |
| 6 | 4 | 32 | 1 |
| 7 | 5 | 4 | 1 |
| 8 | 5 | 11 | 1 |
| 9 | 5 | 18 | 1 |
+----+---------+----------+---------------+
ここではtableに入れた全てのデータはalready_likedがtrueになっている。
そしてここでさっきみたいに、一つのcategoryの下でtopicとuserとこの新しいstarテーブルをjoinさせて、もしユーザーが常にlikeをしていたらもちろんalready_likedはtrueで、もまだしていなかったらNULLを返すようにしたい。(*注意点:topicAndUserテーブルのuser_idはこのtopicを作ったユーザーのidで、このstar_topic_userテーブルのuser_idはそのtopicをlikeしたユーザーのID、違うユーザーID)結果としては、例えばlikeしたユーザーのidが3場合、:
+---------+---------------+------------+-----------+--------+------------+--------------+
| topicId | topicName | categoryId | topicStar | userId | userName | alreadyLiked |
+---------+---------------+------------+-----------+--------+------------+--------------+
| 4 | topic test 4 | 1 | 0 | 12 | usertest12 | NULL |
| 11 | topic test 11 | 1 | 0 | 19 | usertest19 | 1 |
| 18 | topic test 18 | 1 | 0 | 6 | usertest6 | 1 |
| 25 | topic test 25 | 1 | 0 | 13 | usertest13 | NULL |
| 32 | topic test 32 | 1 | 0 | 20 | usertest20 | NULL |
+---------+---------------+------------+-----------+--------+------------+--------------+
これなら一つのqueryでcategoryの下にあるtopic、user、starを全部取得することができる。問題はどうやって?
もちろんjoinを使うので、inner joinをしてみた:
mysql> SELECT topic.id AS topicId, topic.name AS topicName, topic.category_id AS categoryId, topic.topic_star AS topicStar, user.id AS userId, user.name AS userName, star_topic_user.already_liked AS alreadyLiked FROM topic INNER JOIN user ON topic.user_id = user.id INNER JOIN star_topic_user ON topic.id = star_topic_user.topic_id WHERE topic.category_id = 1 AND topic.id >= 0 ORDER BY topic.id LIMIT 5;
+---------+---------------+------------+-----------+--------+------------+--------------+
| topicId | topicName | categoryId | topicStar | userId | userName | alreadyLiked |
+---------+---------------+------------+-----------+--------+------------+--------------+
| 4 | topic test 4 | 1 | 0 | 12 | usertest12 | 1 |
| 11 | topic test 11 | 1 | 0 | 19 | usertest19 | 1 |
| 11 | topic test 11 | 1 | 0 | 19 | usertest19 | 1 |
| 11 | topic test 11 | 1 | 0 | 19 | usertest19 | 1 |
| 18 | topic test 18 | 1 | 0 | 6 | usertest6 | 1 |
+---------+---------------+------------+-----------+--------+------------+--------------+
これはおかしい。。。どうして全く同じrowが三つもあるんだ?
調べたら、LEFT JOINというのがあった。これだったら大丈夫だろう:
mysql> SELECT topic.id AS topicId, topic.name AS topicName, topic.category_id AS categoryId, topic.topic_star AS topicStar, user.id AS userId, user.name AS userName, star_topic_user.already_liked AS alreadyLiked FROM topic INNER JOIN user ON topic.user_id = user.id LEFT JOIN star_topic_user ON topic.id = star_topic_user.topic_id WHERE topic.category_id = 1 AND topic.id >= 0 ORDER BY topic.id LIMIT 5;
+---------+---------------+------------+-----------+--------+------------+--------------+
| topicId | topicName | categoryId | topicStar | userId | userName | alreadyLiked |
+---------+---------------+------------+-----------+--------+------------+--------------+
| 4 | topic test 4 | 1 | 0 | 12 | usertest12 | 1 |
| 11 | topic test 11 | 1 | 0 | 19 | usertest19 | 1 |
| 11 | topic test 11 | 1 | 0 | 19 | usertest19 | 1 |
| 11 | topic test 11 | 1 | 0 | 19 | usertest19 | 1 |
| 18 | topic test 18 | 1 | 0 | 6 | usertest6 | 1 |
+---------+---------------+------------+-----------+--------+------------+--------------+
全く同じだ。。。何かがおかしい
ここでの問題点は、topicIdが11のtopicに対し、これをlikeしたuserIdは3,4,5と三つある。
実際にこれを打ってみるとわかる:
mysql> SELECT topic.id AS topicId, topic.name AS topicName, topic.category_id AS categoryId, topic.topic_star AS topicStar, user.id AS userId, user.name AS userName, star_topic_user.already_liked AS alreadyLiked, star_topic_user.user_id AS likedUserId FROM topic INNER JOIN user ON topic.user_id = user.id LEFT JOIN star_topic_user ON topic.id = star_topic_user.topic_id WHERE topic.category_id = 1 AND topic.id >= 0 ORDER BY topic.id LIMIT 5;
+---------+---------------+------------+-----------+--------+------------+--------------+-------------+
| topicId | topicName | categoryId | topicStar | userId | userName | alreadyLiked | likedUserId |
+---------+---------------+------------+-----------+--------+------------+--------------+-------------+
| 4 | topic test 4 | 1 | 0 | 12 | usertest12 | 1 | 5 |
| 11 | topic test 11 | 1 | 0 | 19 | usertest19 | 1 | 3 |
| 11 | topic test 11 | 1 | 0 | 19 | usertest19 | 1 | 4 |
| 11 | topic test 11 | 1 | 0 | 19 | usertest19 | 1 | 5 |
| 18 | topic test 18 | 1 | 0 | 6 | usertest6 | 1 | 3 |
+---------+---------------+------------+-----------+--------+------------+--------------+-------------+
topicIdが11の時、likedUserIdが3,4,5となっている。
これをどう回避するかというと、実はすごく簡単で、WHEREのところに条件を入れる:
mysql> SELECT topic.id AS topicId, topic.name AS topicName, topic.category_id AS categoryId, topic.topic_star AS topicStar, user.id AS userId, user.name AS userName, star_topic_user.already_liked AS alreadyLiked FROM topic INNER JOIN user ON topic.user_id = user.id LEFT JOIN star_topic_user ON (topic.id = star_topic_user.topic_id && star_topic_user.user_id = 3) WHERE topic.category_id = 1 AND topic.id >= 0 ORDER BY topic.id LIMIT 5;
+---------+---------------+------------+-----------+--------+------------+--------------+
| topicId | topicName | categoryId | topicStar | userId | userName | alreadyLiked |
+---------+---------------+------------+-----------+--------+------------+--------------+
| 4 | topic test 4 | 1 | 0 | 12 | usertest12 | NULL |
| 11 | topic test 11 | 1 | 0 | 19 | usertest19 | 1 |
| 18 | topic test 18 | 1 | 0 | 6 | usertest6 | 1 |
| 25 | topic test 25 | 1 | 0 | 13 | usertest13 | NULL |
| 32 | topic test 32 | 1 | 0 | 20 | usertest20 | NULL |
+---------+---------------+------------+-----------+--------+------------+--------------+
これで解決!