2

我有用户表:

CREATE TABLE `users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `email` char(255) NOT NULL DEFAULT '',
  `password` char(12) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

书桌:

CREATE TABLE `books` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `book` char(55) NOT NULL DEFAULT '',
  `user_id` int(11) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `book` (`book`),
  KEY `user_id` (`user_id`),
  CONSTRAINT `books_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE NO ACTION ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

并阅读表格:

CREATE TABLE `read` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(11) unsigned NOT NULL,
  `book_id` int(11) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `No duplicates` (`user_id`,`book_id`),
  KEY `book_id` (`book_id`),
  CONSTRAINT `connections_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `connections_ibfk_2` FOREIGN KEY (`book_id`) REFERENCES `books` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

我希望 user_id = 1,创建其他 user_id 的列表 - 匹配点是他们读过的常见书籍。因此,如果 user_id = 1 和 user_id = 2 共有 5 本书,那么 user_id 应该在该列表中。我不太擅长 sql,所以任何关于如何实现这一点的建议,即使是很少的优化技巧,都将不胜感激。

4

1 回答 1

1

可能的解决方案 - 为阅读 5 本或更多普通书籍的用户提供

SELECT r2.user_id
FROM `read` r1
JOIN `read` r2
ON r1.user_id <> r2.user_id AND r1.book_id = r2.book_id
WHERE r1.user_id = 1
GROUP BY r2.user_id
HAVING count(*) >= 5

如果用户必须恰好有 5 本书(不多也不少),HAVING则必须将带有的子句更改为:

 HAVING count(*) = 5

演示:--> http://www.sqlfiddle.com/#!2/7a9b7/1


对查询的一个简单更改给出了阅读 >= 5 普通书籍的用户对:

SELECT r1.user_id user1, r2.user_id user2
FROM `read` r1
JOIN `read` r2
ON r1.user_id < r2.user_id AND r1.book_id = r2.book_id
-- WHERE r1.user_id = 1
GROUP BY r1.user_id, r2.user_id
HAVING count(*) >= 5;

演示: --> http://www.sqlfiddle.com/#!2/7a9b7/3


---- 编辑 ----

要按匹配数对用户排序,请使用以下查询:

SELECT r1.user_id user1, r2.user_id user2, 
       count(*) number_of_matches
FROM `read` r1
JOIN `read` r2
ON r1.user_id < r2.user_id AND r1.book_id = r2.book_id
-- WHERE r1.user_id = 1
GROUP BY r1.user_id, r2.user_id
HAVING count(*) >= 5
ORDER BY number_of_matches DESC
-- you may also use:
-- ORDER BY COUNT(*) DESC
;


演示 --> http://www.sqlfiddle.com/#!2/7a9b7/8

于 2013-10-27T20:09:34.437 回答