【问题标题】:MySQL query for multi-column distinct plus an ancillary column conditionMySQL查询多列不同加上辅助列条件
【发布时间】:2020-11-20 22:43:07
【问题描述】:

想象一个平桌,它跟踪比赛,每场比赛有三个参与者:攻击者、防御者和投注玩家 1 和 2 之间战斗结果的投注者。该表格包括玩家的姓名以及每场比赛的投注者,以及比赛日期、每位球员的得分、比赛场地和裁判姓名。我在下面包含了一些示例数据的 CREATE sql。

DROP TABLE IF EXISTS `game`;

CREATE TABLE `game` (
  `game_date` text,
  `player_1` text,
  `player_2` text,
  `bettor` text,
  `p1_score` double DEFAULT NULL,
  `p2_score` double DEFAULT NULL,
  `result` double DEFAULT NULL,
  `venue` text,
  `referee` text
) 

INSERT INTO `game` VALUES ('2020-04-05','Bob','Kelly','Kevin',100,78,0.2,'TS1','Richard'),('2020-03-06','Jim','Bob','Dave',100,97,1.2,'TS2','Mike'),('2020-02-05','Jim','Bob','Kevin',100,86,0.9,'TS2','Mike'),('2020-01-06','Kelly','Bob','Jim',100,92,1.3,'TS2','Richard'),('2019-12-07','Kelly','Bob','Jim',100,98,1.7,'TS1','Mike'),('2019-11-07','Kelly','Bob','Kevin',78,100,2.1,'TS2','Mike'),('2019-10-08','Kelly','Bob','Kevin',97,100,1.5,'TS1','Mike'),('2019-09-08','Kelly','Jim','Dave',86,100,2.4,'TS1','Richard'),('2019-08-09','Kelly','Jim','Dave',92,100,2.8,'TS2','Mike'),('2019-07-10','Kelly','Jim','Dave',98,100,2.2,'TS2','Mike'),('2019-06-10','Kelly','Jim','Dave',100,78,1.9,'TS2','Richard'),('2019-05-11','Sarah','Jim','Kevin',100,97,2.1,'TS1','Mike'),('2019-04-11','Sarah','Jim','Kevin',100,86,2.1,'TS2','Mike'),('2019-03-12','Sarah','Jim','Kevin',100,92,2.8,'TS1','Mike'),('2019-02-10','Sarah','Jim','Kevin',100,98,1.8,'TS1','Richard');

我需要一个查询来返回每个唯一的比赛参与者组合的比赛信息......但仅限于三个参与者一起参加的第一场比赛,即所有三个参加的比赛中最早的 game_date在。

例如,Bob 是玩家 1、Kelly 是玩家 2、Kevin 是下注者的游戏将构成一个独特的三人组。在数据中,这个三人组只有一个这样的配对,所以查询会为那个匹配返回一行。

如果 Sarah 作为玩家 1,Jim 作为玩家 2,Kevin 作为投注者,该三人组有四场比赛,因此查询将只返回最早比赛的信息,即 2019 年 2 月 10 日的那一场.

请注意,在示例数据中,有两个匹配三人组“Kelly”、“Bob”、“Jim”。还有另外两场与三人组“Kelly”、“Jim”、“Bob”的比赛。这些不一样,因为 Bob 和 Jim 交换位置有玩家 2 和下注者。因此,查询将为它们中的每一个返回一行,即日期分别为 '12/072019' 和 '08/09/2019' 的匹配项。

使用 DISTINCT,我可以返回所有唯一玩家分组的列表。

SELECT DISTINCT player_1, player_2, bettor FROM games;

使用 GROUP BY,我可以返回该小组参加的所有比赛的所有比赛信息。

SELECT * FROM games GROUP BY player_1, player_2, bettor;

但我不知道如何返回所有游戏信息,但只能返回所有三个参与者一起玩并且在游戏中扮演不同角色的最早游戏。

我已经尝试使用 MIN() 对 game_date 进行子查询,但这是一个失败者。我怀疑可能有一个 INNER JOIN 解决方案,但我还没有找到它。

感谢您提供的任何指导。

【问题讨论】:

  • 样本数据和期望的结果真的很有帮助。如果玩家 1/2/3 玩一场游戏,而 3/1/2 玩另一场,那是“相同”的玩家吗?
  • 谢谢@GordonLinoff,这是一个非常好的和重要的问题,我没有澄清。我将编辑这个问题来解决这个问题。简而言之,是的,每个玩家作为 player_1、player_2 或 player_3 的位置确实很重要。可以将其想象为玩家 1 被认为是攻击者,玩家 2 被认为是防御者,而玩家 3 是对攻击者和防御者之间的结果下注的投注者。
  • 你的MySql是什么版本的?
  • @forpas -- MySQL 版本:8.0.11

标签: mysql sql inner-join distinct


【解决方案1】:

一种规范的方法使用子查询的连接来识别每个三人组最早的游戏:

SELECT g1.*
FROM games g1
INNER JOIN
(
    SELECT player_1_name, player_2_name, player_3_name,
           MIN(game_date) AS min_game_date
    FROM games
    GROUP BY player_1_name, player_2_name, player_3_name
) g2
    ON g2.player_1_name = g1.player_1_name AND
       g2.player_2_name = g1.player_2_name AND
       g2.player_3_name = g1.player_3_name AND
       g2.min_game_date = g1.game_date;

如果您运行的是 MySQL 8+,那么ROW_NUMBER 解析函数提供了另一种选择:

WITH cte AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY player_1_name, player_2_name,
                                              player_3_name
                                 ORDER BY game_date) rn
    FROM games
)

SELECT *
FROM cte
WHERE rn = 1;

【讨论】:

  • 谢谢,@tim-biegeleisen!这真的很有趣。当我运行查询时,我得到看起来像整个表的笛卡尔积的结果,其中查询为每个唯一的三人组返回的行数等于匹配数乘以表中的记录总数。有游戏记录,因此结果集超过 2,000,000 行。顺便说一句,MySQL Workbench 对查询大喊大叫,因为 g1.game_date 不包含在基本查询中,并且比较 g2.min_game_date = g1.game_date;失败的。所以我在第一个 JOIN 查询中添加了 game_date。
  • 使用示例数据设置演示并将链接粘贴到此处。使用 dbfiddle.uk.co 作为演示站点。
  • 问题中有样本数据。
  • 蒂姆,我很遗憾我第一次发布问题时没有这样做。但是,正如@barmar 所提到的,我在问题中添加了示例数据。
  • 如果每个玩家的位置都很重要,即(1, 2, 3)(1, 3, 2)相同,那么我的回答应该已经对你有用了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-12
  • 1970-01-01
  • 2021-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多