У меня проблема с конкретным сценарием реализации таблицы лидеров в MySQL.
У меня есть таблица пользователей и постов, где для каждого поста указано количество начисленных баллов. Сообщения могут быть в нескольких категориях (activityUid и activityType). Таблица лидеров ранжируется на основе лучшего сообщения, сделанного каждым пользователем в каждой категории.
Поскольку присуждаемые баллы не уникальны (несколько сообщений пользователя X в категории Y могут получить одинаковое количество баллов), я столкнулся с ситуацией, когда мой запрос больше не возвращал лучший пост для каждого пользователя, а несколько сообщений с одинаковым количеством макс. точки.
Я хотел бы сузить результаты до сообщения самый последний (Дата создания) для каждого пользователя в случае дублирования количества баллов.
Запрос:
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');
Вкладыши включали @RaymondNijland, спасибо за проверку.
это хороший вопрос @ K0ff33!






Замените таблицу posts запросом для извлечения самого последнего сообщения (dateCreated) каждого UserUid / Points.
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;
Хорошо известно, что INNER JOIN будет соответствовать несколько раз, если совпадение может быть выполнено. если бы вы только могли включить некоторые вставки с примерами данных, которые соответствуют вашим желаемым результатам.