Как сравнить поля (возможно, массивы) в запросах SQL неупорядоченным способом? - PullRequest
0 голосов
/ 06 февраля 2019

Допустим, у вас есть база данных с данными об игре с командами из 2 игроков.Есть таблица team с полями player_id и полем win (0 для проигрыша, 1 для выигрыша) и таблица player с полем id и weapon.

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

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

Вы также можете использовать поле массива players в таблице команд, но такой подход, по-моему, вызывает ту же проблему.

В идеале я хотел бы написать что-то вроде этого:

SELECT AVG(t.win) AS win_fraction, weapon1, weapon2
FROM team t
JOIN player p1 ON t.player_id1 = p1.id
JOIN player p2 ON t.player_id2 = p2.id
GROUP BY UNORDERED(p1.weapon, p2.weapon) AS (weapon1, weapon2)

Очевидно, что ключевое слово UNORDERED не является частью SQL, но я думаю, что синтаксис здесь делает достаточно ясным, что это желаемый результат:

| win_fraction | weapon1 | weapon2 |
|--------------|---------|---------|
| 0.63         | AK_47   | P90     |
| 0.75         | AK_47   | AK_47   |
| 0.22         | P90     | P90     |

Обратите внимание, что не должно быть строки с P90 как weapon1 и AK_47 как weapon2, если только он не возвращает точно такой же win_fraction как строка с этим оружиемв обратном порядке (таким образом, порядок расположения оружия не должен влиять на рассчитанную win_fraction).

Кто-нибудь сталкивался с такой же проблемой?И если да, то как вам удалось ее решить?

Спасибо за вашу помощь, очень признателен!

РЕДАКТИРОВАТЬ:

Решение необходимобыть достаточно общим, чтобы иметь X игроков.Конкретное решение проблемы с 2 игроками, например использование LEAST и GREATEST, не работает в случае с проблемой с 3 игроками, так как нам также необходимо иметь ключевое слово MIDDLE:

SELECT AVG(t.win) AS win_fraction
FROM team t
JOIN player p1 ON t.player_id1 = p1.id
JOIN player p2 ON t.player_id2 = p2.id
JOIN player p3 ON t.player_id3 = p3.id
GROUP BY
    LEAST(p1.weapon, p2.weapon, p3.weapon),
    MIDDLE(p1.weapon, p2.weapon, p3.weapon),
    GREATEST(p1.weapon, p2.weapon, p3.weapon);`

1 Ответ

0 голосов
/ 06 февраля 2019

Вы можете агрегировать, используя скалярные функции LEAST и GREATEST:

SELECT AVG(t.win) AS win_fraction
FROM team t
INNER JOIN player p1
    ON t.player_id1 = p1.id
INNER JOIN player p2
    ON t.player_id2 = p2.id
GROUP BY
    LEAST(p1.weapon, p2.weapon),
    GREATEST(p1.weapon, p2.weapon);

Обратите внимание, что вы можете также включить в свой выбор предложение GROUP BY, в зависимости от ожидаемого результата.

Для группировки из трех видов оружия мы можем попробовать:

SELECT AVG(t.win) AS win_fraction
FROM team t
INNER JOIN player p1
    ON t.player_id1 = p1.id
INNER JOIN player p2
    ON t.player_id2 = p2.id
GROUP BY
    LEAST(p1.weapon, p2.weapon, p3.weapon),
    CASE WHEN p1.weapon <> LEAST(p1.weapon, p2.weapon, p3.weapon) AND
              p1.weapon <> GREATEST(p1.weapon, p2.weapon, p3.weapon)
         THEN p1.weapon
         WHEN p2.weapon <> LEAST(p1.weapon, p2.weapon, p3.weapon) AND
              p2.weapon <> GREATEST(p1.weapon, p2.weapon, p3.weapon)
         THEN p2.weapon
         ELSE p3.weapon END,
    GREATEST(p1.weapon, p2.weapon, p3.weapon);
...