我有一个MySQL表,用户对是/否投票问题的回答。看起来有点像这样:
| user_id | poll_id | response |
|------------|----------|-----------|
| 111 | 1 | 'yes' |
| 111 | 2 | 'no' |
| 111 | 3 | 'no' |
| 222 | 1 | 'yes' |
| 222 | 2 | 'yes' |
| 222 | 3 | 'yes' |
| 333 | 1 | 'no' |
| 333 | 2 | 'no' |
| 333 | 3 | 'no' |
我想计算每个用户的回复与每个其他用户的回复之间的相似性。因此,用户111和用户222是相似的0.333(因为它们具有3个相同的响应中的1个),并且用户111和用户333是0.666相似的(因为它们具有3个相同响应中的2个)。
我已经编写了一个查询,它会为我提供两个指定用户的相同响应数:
SELECT COUNT(*) AS same_count
FROM (
SELECT response
FROM results
WHERE user_id = 111
) AS t1
, (
SELECT response
FROM results
WHERE user_id = 222
) AS t2
WHERE t1.response = t2.response
现在我试图想办法让所有用户获得该信息,以产生如下结果:
| user_1 | user_2 | same_count |
|---------|----------|--------------|
| 111 | 222 | 0.333 |
| 111 | 333 | 0.666 |
| 222 | 111 | 0.333 |
| 222 | 333 | 0 |
| 333 | 111 | 0.666 |
| 333 | 222 | 0 |
或者,如果可能,没有冗余信息:
| user_1 | user_2 | same_count |
|---------|----------|--------------|
| 111 | 222 | 0.333 |
| 111 | 333 | 0.666 |
| 222 | 333 | 0 |
我的直觉告诉我,有一种方法可以将其作为一个可怕的MySQL查询,而不必通过PHP中的循环执行一堆查询。有人能指出我正确的方向吗?
答案 0 :(得分:3)
您必须使用* poll_id *和* user_id *列对同一个表执行完全外连接。结果将显示两次,以避免我们需要以这样的方式指定条件:只有 alias1 表的user_id
值小于 alias2 table的user_id
值仅包含在结果集中。
Click here to view the demo in SQL Fiddle.
脚本:
CREATE TABLE poll
(
user_id INT NOT NULL
, poll_id INT NOT NULL
, response VARCHAR(10) NOT NULL
);
INSERT INTO poll (user_id, poll_id, response) VALUES
(111, 1, 'yes'),
(111, 2, 'no'),
(111, 3, 'no'),
(222, 1, 'yes'),
(222, 2, 'yes'),
(222, 3, 'yes'),
(333, 1, 'no'),
(333, 2, 'no'),
(333, 3, 'no');
SELECT p1.user_id AS user_1
, p2.user_id AS user_2,
AVG(CASE
WHEN p1.response = p2.response THEN 1
ELSE 0
END) Average_Response
FROM poll p1
, poll p2
WHERE p1.poll_id = p2.poll_id
AND p1.user_id < p2.user_id
GROUP BY p1.user_id
, p2.user_id;
输出:
USER_1 USER_2 AVERAGE_RESPONSE
------ ------ ----------------
111 222 0.3333
111 333 0.6667
222 333 0
答案 1 :(得分:1)
这可以得到你想要的结果:
SELECT
t1.user_id AS user_1,
t2.user_id AS user_2,
SUM(CASE WHEN t1.response = t2.response THEN 1 ELSE 0 END) / COUNT(1)
AS same_count
FROM t t1
JOIN t t2 ON ( t2.user_id > t1.user_id AND t2.poll_id = t1.poll_id )
GROUP BY t1.user_id, t2.user_id
ORDER BY user_1, user_2
我的测试结果:
111 222 0.333333333333333
111 333 0.666666666666667
222 333 0
CASE
部分可以在MySQL中更容易编写为(t1.response = t2.response
),我的版本也适用于其他类型的数据库。
这一部分通过计算所有匹配的条目,并将计数除以条目数来完成主要技巧。
t2.user_id > t1.user_id
将删除重复项(111 - 222,222 - 111)。