mysql - SQL按百分比获取相似的 "match"结果

标签 mysql left-join union ifnull

此表存储用户匹配之间的用户投票。总有一个赢家、一个输家和选民。

CREATE TABLE `user_versus` (
  `id_user_versus` int(11) NOT NULL AUTO_INCREMENT,
  `id_user_winner` int(10) unsigned NOT NULL,
  `id_user_loser` int(10) unsigned NOT NULL,
  `id_user` int(10) unsigned NOT NULL,
  `date_versus` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id_user_versus`),
  KEY `id_user_winner` (`id_user_winner`,`id_user_loser`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=17 ;

INSERT INTO `user_versus` (`id_user_versus`, `id_user_winner`, `id_user_loser`, `id_user`, `date_versus`) VALUES
(1, 6, 7, 1, '2013-10-25 23:02:57'),
(2, 6, 8, 1, '2013-10-25 23:02:57'),
(3, 6, 9, 1, '2013-10-25 23:03:04'),
(4, 6, 10, 1, '2013-10-25 23:03:04'),
(5, 6, 11, 1, '2013-10-25 23:03:10'),
(6, 6, 12, 1, '2013-10-25 23:03:10'),
(7, 6, 13, 1, '2013-10-25 23:03:18'),
(8, 6, 14, 1, '2013-10-25 23:03:18'),
(9, 7, 6, 2, '2013-10-26 04:02:57'),
(10, 8, 6, 2, '2013-10-26 04:02:57'),
(11, 9, 8, 2, '2013-10-26 04:03:04'),
(12, 9, 10, 2, '2013-10-26 04:03:04'),
(13, 9, 11, 2, '2013-10-26 04:03:10'),
(14, 9, 12, 2, '2013-10-26 04:03:10'),
(15, 9, 13, 2, '2013-10-26 04:03:18'),
(16, 9, 14, 2, '2013-10-26 04:03:18');

我正在处理一个获取相似配置文件的查询。当投票百分比(获胜与失败)为指定配置文件的 +/- 10% 时,配置文件是相似的。

SELECT id_user_winner AS id_user,
    IFNULL(wins, 0) AS wins,
    IFNULL(loses, 0) AS loses,
    IFNULL(wins, 0) + IFNULL(loses, 0) AS total,
    IFNULL(wins, 0) / (IFNULL(wins, 0) + IFNULL(loses, 0)) AS percent
FROM
(
    SELECT id_user_winner AS id_user FROM user_versus 
    UNION
    SELECT id_user_loser FROM user_versus 
) AS u
LEFT JOIN
(
    SELECT id_user_winner, COUNT(*) AS wins
    FROM user_versus
    GROUP BY id_user_winner
) AS w
ON u.id_user = id_user_winner
LEFT JOIN
(
    SELECT id_user_loser, COUNT(*) AS loses
    FROM user_versus
    GROUP BY id_user_loser
) AS l
ON u.id_user = l.id_user_loser

这是当前的结果:

mysql result

它当前返回 NULL 行,它们不应该存在。仍然需要优化的(并且不能完全指出它)是:

  1. 只带来与用户ABC相似的用户
  2. 指定定义谁是相似用户的条件,例如用户 ID = 6(相似用户与用户 ID 6 的百分比差异为 +/- 10%)

任何帮助将不胜感激。谢谢!

最佳答案

要计算每个用户的输赢而不必将表连接到自身并使用外部连接,可以只分别选择输赢并在它们之间执行 UNION ALL,但如果给定的行表示,则需要附加信息对用户来说是赢还是输。

然后,很容易计算每个用户的所有输赢。棘手的部分是合并用于指定要与哪个用户比较配置文件的选项。我用一个变量来做到这一点,该变量设置为具有给定 user_id 的用户的 percentage 值,您可以将其从常量更改为变量。

这是我的建议(与 id = 6 的用户相比):

SELECT
    player_id AS id_user,
    wins,
    losses,
    wins + losses AS total,
    wins / (wins + losses) AS percent
  FROM (
    SELECT
        player_id,
        SUM(is_a_win) wins,
        SUM(is_a_loss) losses,
        CASE
          WHEN player_id = 6
            THEN @the_user_score := SUM(is_a_win) / (SUM(is_a_win) + SUM(is_a_loss))
          ELSE NULL
         END
      FROM (
        SELECT id_user_winner AS player_id, 1 AS is_a_win, 0 AS is_a_loss FROM user_versus
        UNION ALL SELECT id_user_loser, 0, 1 FROM user_versus
      ) games
    GROUP BY player_id
  ) data
WHERE
  ABS(wins / (wins + losses) - @the_user_score) <= 0.1
;

输出:

ID_USER WINS   LOSSES  TOTAL   PERCENT
6       8       2       10      0.8
9       6       1       7       0.8571

当然,您可以通过将 player_id != 6(或者,在最终解决方案中,一些变量名称)条件添加到最外层的 WHERE 来删除其个人资料作为比较基础的用户 子句。

SQLFiddle 中的示例:Matching Profiles - Example

如果这正是您想要的,您能否提供一些反馈,如果不是,您期望得到什么结果?

关于mysql - SQL按百分比获取相似的 "match"结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19824298/

相关文章:

sql - MySQL:选择剩余行

mysql - 笛卡尔连接不匹配的行

sql - 如何从 POSTGRESQL 中的 UNION 查询中减去值?

php - phpMyAdmin 和 php 中的不同结果

php - 将每个类别获取的结果数量限制为仅 4 个,而不是显示 "See More Results"

mysql查询,左三张表用group by连接

java - 带有左连接的准备语句

Mysql如何统计多个表的数据,有多个条件

json - 我的副产品编码不明确

java - Jooq中的一对多选择