复杂的sql查询比较数据和创建列表

时间:2013-10-27 19:13:25

标签: mysql sql

我有用户表:

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,所以任何关于如何实现这一点的建议,甚至是很少的优化提示都将非常感激。

1 个答案:

答案 0 :(得分: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

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


对查询的简单更改会为读取&gt; = 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;

演示: - &gt; 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
;


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