MySQL中的排行榜 - 多个"最佳"为每个用户返回结果

时间:2018-03-30 15:32:29

标签: mysql sql

我在MySQL的排行榜实施中遇到了特定情况的问题。

我有一个用户和帖子表,每个帖子都有获奖点数。帖子可以分为多个类别( activityUid activityType )。排行榜根据每个类别的每个用户发布的最佳帖子进行排名。

由于获奖积分不是唯一的(Y类中用户X的多个帖子可能会获得相同数量的积分),我遇到的情况是我的查询不再返回每个用户的最佳帖子,但多个帖子具有相同的最大点数。

如果点数重复,我希望将结果范围缩小到每位用户的最近帖子( dateCreated )。

查询:

SELECT main.*, @curRank := @curRank + 1 AS rank
FROM (
    SELECT users.userUid, posts.postUid, posts.points, posts.dateCreated 
    FROM users 
    INNER JOIN posts ON users.userUid = posts.userUid 
    INNER JOIN (
        SELECT userUid, max(points) AS maxPoints 
        FROM posts 
        WHERE isLift = 1 AND verified = 1 AND activityUid = 'OP0iEbpmP36fkJdMTL2S' AND activityType = 'MAX_WEIGHT' 
        GROUP BY userUid 
        ORDER BY maxPoints DESC
    ) AS maxPerUser ON users.userUid = maxPerUser.userUid AND posts.points = maxPerUser.maxPoints 
    WHERE isLift = 1 AND verified= 1 AND activityUid = 'OP0iEbpmP36fkJdMTL2S' AND activityType = 'MAX_WEIGHT' 
    ORDER BY maxPerUser.maxPoints DESC, posts.dateCreated DESC
) AS main 
JOIN (SELECT @curRank:= 0) r 
ORDER BY rank ASC;

输出:

+------------------------------+--------------------------------------+--------+---------------------+------+
|           userUid            |               postUid                | points |     dateCreated     | rank |
+------------------------------+--------------------------------------+--------+---------------------+------+
| RRyUFdaXsEO6DJOJDL8u7gu1aZ13 | cf6f54d0-336a-11e8-847c-2f396385505a |    303 | 2018-03-29 16:04:21 |    1 |
| jkLbDkRkaoUG4A851VjiEdWnNN32 | 8ada4110-3336-11e8-baaa-1755b4dadd4d |    302 | 2018-03-29 09:50:12 |    2 |
| jkLbDkRkaoUG4A851VjiEdWnNN32 | 4bee45d0-31ad-11e8-8072-2b86c9f79738 |    302 | 2018-03-27 10:55:06 |    3 |
| jkLbDkRkaoUG4A851VjiEdWnNN32 | 2fec75e0-31a9-11e8-8072-2b86c9f79738 |    302 | 2018-03-27 10:25:40 |    4 |
+------------------------------+--------------------------------------+--------+---------------------+------+

期望的结果:

+------------------------------+--------------------------------------+--------+---------------------+------+
|           userUid            |               postUid                | points |     dateCreated     | rank |
+------------------------------+--------------------------------------+--------+---------------------+------+
| RRyUFdaXsEO6DJOJDL8u7gu1aZ13 | cf6f54d0-336a-11e8-847c-2f396385505a |    303 | 2018-03-29 16:04:21 |    1 |
| jkLbDkRkaoUG4A851VjiEdWnNN32 | 8ada4110-3336-11e8-baaa-1755b4dadd4d |    302 | 2018-03-29 09:50:12 |    2 |
+------------------------------+--------------------------------------+--------+---------------------+------+

有谁知道是否有可能实现所描述的功能?谢谢!

表架构(简化):

CREATE TABLE `users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `userUid` varchar(255) COLLATE utf8mb4_bin NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `userUid` (`userUid`)
) ENGINE=InnoDB AUTO_INCREMENT=71 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

CREATE TABLE `posts` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `postUid` varchar(255) COLLATE utf8mb4_bin NOT NULL DEFAULT '',
  `isLift` tinyint(1) NOT NULL,
  `userUid` varchar(48) COLLATE utf8mb4_bin NOT NULL DEFAULT '',
  `activityUid` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
  `activityType` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
  `points` smallint(6) unsigned DEFAULT NULL,
  `verified` tinyint(1) DEFAULT NULL,
  `dateCreated` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `postUid` (`postUid`),
  KEY `userUid` (`userUid`),
  KEY `isLift` (`isLift`),
  KEY `activityUid` (`activityUid`),
  KEY `activityType` (`activityType`),
  KEY `points` (`points`),
  KEY `dateCreated` (`dateCreated`),
  KEY `verified` (`verified`),
  CONSTRAINT `posts_ibfk_1` FOREIGN KEY (`userUid`) REFERENCES `users` (`userUid`)
) ENGINE=InnoDB AUTO_INCREMENT=862 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

示例数据集:

INSERT INTO `users` (`id`, `userUid`)
VALUES
    (1, 'jkLbDkRkaoUG4A851VjiEdWnNN32'),
    (2, 'RRyUFdaXsEO6DJOJDL8u7gu1aZ13');

INSERT INTO `posts` (`id`, `postUid`, `isLift`, `userUid`, `activityUid`, `activityType`, `points`, `verified`, `dateCreated`)
VALUES
  (1,   '4adcc1b0-1e18-11e8-abc6-2f6e24661429', 1, 'jkLbDkRkaoUG4A851VjiEdWnNN32', 'OP0iEbpmP36fkJdMTL2S', 'MAX_WEIGHT', 30, 1, '2018-03-02 12:51:44'),
  (2,   '2fec75e0-31a9-11e8-8072-2b86c9f79738', 1, 'jkLbDkRkaoUG4A851VjiEdWnNN32', 'OP0iEbpmP36fkJdMTL2S', 'MAX_WEIGHT', 302, 1, '2018-03-27 10:25:40'),
  (3,   '4bee45d0-31ad-11e8-8072-2b86c9f79738', 1, 'jkLbDkRkaoUG4A851VjiEdWnNN32', 'OP0iEbpmP36fkJdMTL2S', 'MAX_WEIGHT', 302, 1, '2018-03-27 10:55:06'),
  (4,   '61bf2ee0-3272-11e8-bc76-611e04d7551e', 1, 'jkLbDkRkaoUG4A851VjiEdWnNN32', 'OP0iEbpmP36fkJdMTL2S', 'MAX_WEIGHT', 56, 1, '2018-03-28 10:25:57'),
  (5,   '8ada4110-3336-11e8-baaa-1755b4dadd4d', 1, 'jkLbDkRkaoUG4A851VjiEdWnNN32', 'OP0iEbpmP36fkJdMTL2S', 'MAX_WEIGHT', 302, 1, '2018-03-29 09:50:12'),
  (6,   'cf6f54d0-336a-11e8-847c-2f396385505a', 1, 'RRyUFdaXsEO6DJOJDL8u7gu1aZ13', 'OP0iEbpmP36fkJdMTL2S', 'MAX_WEIGHT', 303, 1, '2018-03-29 16:04:21');

Sqlfiddle

1 个答案:

答案 0 :(得分:1)

将表posts替换为查询以提取每个UserUid / Points的最新帖子(dateCreated)。

SELECT main.*, @curRank := @curRank + 1 AS rank
FROM (
    SELECT users.userUid, posts.postUid, posts.points, posts.dateCreated 
    FROM users 
    INNER JOIN (select * from
                posts p where datecreated = (select max(datecreated)
                                             from posts where posts.userUid = p.userUid
                                                        and posts.points = p.points)
                ) posts ON users.userUid = posts.userUid 
    INNER JOIN (
        SELECT userUid, max(points) AS maxPoints 
        FROM posts 
        WHERE isLift = 1 AND verified = 1 AND activityUid = 'OP0iEbpmP36fkJdMTL2S' AND activityType = 'MAX_WEIGHT' 
        GROUP BY userUid 
        ORDER BY maxPoints DESC
    ) AS maxPerUser ON users.userUid = maxPerUser.userUid AND posts.points = maxPerUser.maxPoints 
    WHERE isLift = 1 AND verified= 1 AND activityUid = 'OP0iEbpmP36fkJdMTL2S' AND activityType = 'MAX_WEIGHT' 
    ORDER BY maxPerUser.maxPoints DESC, posts.dateCreated DESC
) AS main 
JOIN (SELECT @curRank:= 0) r 
ORDER BY rank ASC;

Sqlfiddle