SQL, чтобы получить аналогичные результаты «совпадения» по проценту

StackOverflow https://stackoverflow.com/questions/19824298

  •  05-07-2022
  •  | 
  •  

Вопрос

В этой таблице хранится голоса пользователей между пользовательскими совпадами. Всегда есть один победитель, один неудачник и избиратель.

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');

Я работаю над вопросом, который получает похожие профили. Профиль аналогичен, когда процент голосования (Wins Vs проигрывает) составляет +/- 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

В настоящее время он возвращает нормы, и их не должно быть там. Что еще нужно оптимизировать (и не могу поставить на это пальцем):

  1. Принесите пользователей, похожие на пользователей только ABC
  2. Укажите условие, которое определяет, кто похож на пользователь, например, идентификатор пользователя = 6 (где аналогичные пользователи имеют разницу +/- 10% в процентах с идентификатором пользователя 6)

Любая помощь будет оценена. Спасибо!

Это было полезно?

Решение

Чтобы рассчитать победы и убытки каждого пользователя без необходимости присоединения к таблице к себе и использовать внешние соединения, можно просто выбрать победы и убытки отдельно и сделать союз между ними, но с дополнительной информацией, если данный строк представляет собой победу для пользователь или потеря.

Затем легко рассчитать все победы и убытки для каждого пользователя. Хитрое было включить вариант для указания того, какого пользователя вы хотели бы сравнить профили. Я сделал это с переменной, которая устанавливается на значение percentage пользователя с данным user_id, что вы можете изменить от постоянной на переменную.

Вот мое предложение (по сравнению с пользователем с 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: Соответствующие профили - пример

Не могли бы вы предоставить некоторую отзыв, если бы вы искали, и, если нет, какой вывод вы ожидаете?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top