创建一个表并插入测试数据:
CREATE TABLE `ub` (
`user_id` int(11) NOT NULL,
`book_id` varchar(10) NOT NULL,
PRIMARY KEY (`user_id`,`book_id`),
UNIQUE KEY `book_id` (`book_id`,`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
insert into ub values (1, 'A'), (1, 'B'), (1, 'C');
insert into ub values (2, 'A'), (2, 'B'), (2, 'C'), (2,'D');
insert into ub values (3, 'X'), (3, 'Y'), (3, 'C'), (3,'Z');
insert into ub values (4, 'W'), (4, 'Q'), (4, 'C'), (4,'Z');
按照book_id将测试数据与其自身连接,并创建一个临时表来保存每个user_id以及它与目标user_id有多少本书相同:
create temporary table ub_rank as
select similar.user_id,count(*) rank
from ub target
join ub similar on target.book_id= similar.book_id and target.user_id != similar.user_id
where target.user_id = 1
group by similar.user_id;
select * from ub_rank;
+
| user_id | rank |
+
| 2 | 3 |
| 3 | 1 |
| 4 | 1 |
+
3 rows in set (0.00 sec)
我们可以看到user_id 与 user_id 1 有3个共同的,但是user_id 3和user_id 4每个只有1个。
接下来,选择临时表中用户拥有但与目标user_id的书籍不匹配的所有书籍,并按等级排序。注意,相同的书可能出现在不同用户的列表中,因此我们对每本书进行排名求和,以使共同的书籍获得更高的排名。
select similar.book_id, sum(ub_rank.rank) total_rank
from ub_rank
join ub similar on ub_rank.user_id = similar.user_id
left join ub target on target.user_id = 1 and target.book_id = similar.book_id
where target.book_id is null
group by similar.book_id
order by total_rank desc;
+
| book_id | total_rank |
+
| D | 3 |
| Z | 2 |
| X | 1 |
| Y | 1 |
| Q | 1 |
| W | 1 |
+
6 rows in set (0.00 sec)
书籍Z出现在两个用户的列表中,因此排名高于仅出现在一个用户列表中的X、Y、Q、W。书籍D表现最好,因为它出现在用户ID 2的列表中,该列表与目标用户ID 1有3项共同之处。