我正在计划一个数据库驱动的网站,根据用户如何回答问题来匹配用户。我认为最好的方法是在SELECT查询中运行匹配计算,但我不知道如何编写查询。
假设我有一个名为 user_answer 的表格,它看起来像这样:
+--------+-------------+--------+------------------+--------+
| userid | question_id | answer | preferred_answer | weight |
+--------+-------------+--------+------------------+--------+
| 1 | 20 | 3 | | 0 |
| 1 | 24 | 3 | 2, 3 | 1 |
| 1 | 36 | 2 | 2 | 10 |
| 1 | 37 | 3 | 1, 2, 3 | 50 |
| 1 | 40 | 3 | 3 | 250 |
| 2 | 20 | 3 | 3 | 10 |
| 2 | 24 | 3 | 2 | 1 |
| 2 | 25 | 2 | | 0 |
| 2 | 26 | 2 | | 0 |
| 2 | 40 | 3 | 2 | 250 |
+--------+-------------+--------+------------------+--------+
我想通过 match_percentage 进行选择和排序 - match_percentage应以这种方式计算:
我不知道这是否可行。我期待DB变得非常大,所以加载它们并在PHP中进行计算可能不是最佳选择 - 但如果我错了,请纠正我。
是否可以在查询中进行所有这些计算?
答案 0 :(得分:1)
是的,我相信所有指定的计算都可以在查询中执行。
假设(userid,questionid)是UNIQUE,我们首先找到带有“匹配”问题的userid。我们可以通过这样的查询来做到这一点:
SELECT u.answer
, u.preferred_answer
, u.weight
, m.userid AS m_userid
, m.question_id AS m_question_id
, m.answer AS m_answer
, m.preferred_answer AS m_preferred_answer
, m.weight AS m_weight
FROM user_answer u
JOIN user_answer m
ON m.question_id = u.question_id
AND m.userid <> u.userid
AND u.userid = 1
ORDER
BY m.userid
, m.question_id
一旦我们完成了这项工作,我们就可以从这些工作中获得总重量和计算结果。
假设preferred_answer
列是VARCHAR类型,并且包含逗号分隔的元素列表,没有空格,例如'2'
或'2,3,5'
,您可以使用MySQL FIND_IN_SET
函数返回列表中特定元素的索引位置。如果找不到“匹配”,那将返回0。
我相信这个查询符合规范。
SELECT m.userid AS m_userid
, SUM(u.weight) AS total_weight1
, SUM(IF(FIND_IN_SET(m.answer,u.preferred_answer),u.weight,0)) AS match1_weight
, SUM(m.weight) AS total_weight2
, SUM(IF(FIND_IN_SET(u.answer,m.preferred_answer),m.weight,0)) AS match2_weight
, SQRT(
( SUM(IF(FIND_IN_SET(m.answer,u.preferred_answer),u.weight,0)) / SUM(u.weight) )
* ( SUM(IF(FIND_IN_SET(u.answer,m.preferred_answer),m.weight,0)) / SUM(m.weight) )
) AS match_percentage
FROM user_answer u
JOIN user_answer m
ON m.question_id = u.question_id
AND m.userid <> u.userid
AND u.userid = 1
GROUP
BY m.userid
ORDER
BY match_percentage DESC
注:
这些查询仅限桌面检查。我没有设置SQL小提琴进行测试。
第4项似乎是 current_user权重的总和,但仅包括匹配的答案。如果没有匹配的答案,我们将返回0.对于第6项也是如此,但只是反过来。)
如果userid 1和其他一些userid之间没有匹配的问题,则不会为其他用户ID返回任何行。
对于大型套装,这可能会持续一段时间。合适的覆盖指数应该可以提高性能。
为了提高查询性能,您可能需要考虑将此查询的结果“缓存”到单独的表中。只有在插入,更新,删除原始表中的行时,才需要刷新“缓存”表的内容。以前计算的结果对于正常访问可能仍然“足够好”。
如果您存储了结果,那么您还希望将u.userid
作为SELECT列表和GROUP BY中的列返回。