mysql - 徽章系统 / MySQL GROUP BY 和 ORDER BY
问题描述
我正在为我的网站创建一个徽章系统:下面的屏幕截图显示了它现在的样子。在获得 10,100 等点以执行特定操作(例如回答问题、更正 wiki)后,您将获得具有多个级别(青铜、白银……)的徽章。请注意,带有美元符号的镜子有两次,一次是银色的,一次是青铜的:
底层是两张表,一张带有徽章信息(x_badges:存储什么操作以及其中的多少点为您提供了什么样的徽章级别),一张带有哪个用户获得了哪个徽章(x_badges_earned:badgeID 和 uID)。
FK的解释:
- uID 是用户 ID,作为参数传递(使用 1 进行测试)
- xb_ID 是每个徽章类型的 auto_increment ID
- xbe_ID 是将用户 ID 与他们获得的徽章 ID 匹配的行的自动增量 ID (xb_ID -> uID)
这是我最初的查询,每个类别只给我一个徽章(但不是最高的,即如果我在一个类别中获得银牌和铜牌,它将只返回铜牌):
SELECT *
FROM x_badges_earned, x_badges
WHERE xbe_bID = xb_ID
AND xbe_uID = ?
GROUP BY xb_requirement
ORDER BY xb_requirement ASC, xb_requirement_value ASC
在对 SO 进行研究之后,我创建了这个查询来生成上面的屏幕截图。如果我将最后一个 GROUP BY 更改为 xb_requirement,我将返回查询 1 的结果:
SELECT b.*
FROM x_badges b
LEFT JOIN x_badges b2 ON b.xb_ID = b2.xb_ID
AND b.xb_requirement_value < b2.xb_requirement_value
LEFT JOIN x_badges_earned be ON be.xbe_bID = b.xb_ID
WHERE b2.xb_requirement_value IS NULL
AND be.xbe_uID = ?
GROUP BY b.xb_ID
我觉得我现在几乎在绕圈子。我想出了这个可能会起作用的方法(至少在我的脑海中),但我无法解决它:
SELECT *
FROM x_badges
WHERE xb_ID IN (
SELECT xb_ID, MAX(xb_requirement_value)
FROM x_badges_earned, x_badges
WHERE xbe_bID = xb_ID AND xbe_uID = ?
GROUP BY xb_requirement
)
任何帮助是极大的赞赏!
我附上了 MySQL 代码来创建这两个表并填充它们以供使用。此外,您可以使用 1 作为参数值,因为它是我的用户 ID。我当前的输出看起来像这样,如果没有第一行 (xb_ID 11),所需的输出将是相同的,因为它是我获得银牌的青铜徽章。
CREATE TABLE `x_badges` (
`xb_ID` int(11) NOT NULL,
`xb_requirement` varchar(40) NOT NULL,
`xb_requirement_value` int(11) NOT NULL,
`xb_text` text NOT NULL,
`xb_text_details` text NOT NULL,
`xb_icon` varchar(20) NOT NULL,
`xb_color` varchar(6) NOT NULL,
`xb_color_text` varchar(6) NOT NULL,
`xb_level_name` varchar(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `x_badges` (`xb_ID`, `xb_requirement`, `xb_requirement_value`, `xb_text`, `xb_text_details`, `xb_icon`, `xb_color`, `xb_color_text`, `xb_level_name`) VALUES
(11, 'added_interaction', 10, 'Added interactions', 'Received more than %d points adding interactions with target companies!', 'search-dollar', 'cc8e34', '', 'Bronze'),
(15, 'added_target', 10, 'Added targets', 'Received more than %s points adding target companies!', 'dollar-sign', 'cc8e34', '', 'Bronze'),
(16, 'asked_question', 10, 'Asked questions', 'Received more than %s points asking questions!', 'question', 'cc8e34', '', 'Bronze'),
(17, 'notified_colleagues_interaction', 10, 'Interactions shared with colleagues', 'Received more than %s points tagging colleagues in interactions added!', 'bullhorn', 'cc8e34', '', 'Bronze'),
(18, 'reply_accepted', 10, 'Helpful replies', 'Received more than %s points thanks to replies marked as helpful!', 'check-double', 'cc8e34', '', 'Bronze'),
(19, 'reply_question', 10, 'Replies to questions', 'Received more than %s points replying to questions!', 'comments', 'cc8e34', '', 'Bronze'),
(20, 'updated_info', 10, 'Updated target profiles', 'Received more than %s points updating profiles of targets!', 'funnel-dollar', 'cc8e34', '', 'Bronze'),
(21, 'updated_wiki', 10, 'Updated wiki', 'Received more than %s points updating profiles of Group companies!', 'pen-nib', 'cc8e34', '', 'Bronze'),
(22, 'upvote_question', 10, 'Helpful questions', 'Received more than %s points for having own questions upvoted!', 'grin-alt', 'cc8e34', '', 'Bronze'),
(23, 'added_interaction', 100, 'Added interactions', 'Received more than %s points adding interactions with target companies!', 'search-dollar', 'aaa9ad', '', 'Silver'),
(24, 'added_interaction', 500, 'Added interactions', 'Received more than %s points adding interactions with target companies!', 'search-dollar', 'ffd700', '495057', 'Gold'),
(25, 'updated_wiki', 1000, 'Updated Bertelsmann wiki', 'Received more than %s points asking questions!', 'pen-nib', 'b9f2ff', '495057', 'Diamond'),
(26, 'added_interaction', 1000, 'Added interactions', 'Received more than %s points adding interactions with target companies!', 'search-dollar', 'b9f2ff', '495057', 'Diamond'),
(27, 'added_interaction', 5000, 'Added interactions', 'Received more than %s points adding interactions with target companies!', 'search-dollar', 'e0115f', '', 'Ruby');
CREATE TABLE `x_badges_earned` (
`xbe_ID` int(11) NOT NULL,
`xbe_uID` int(11) NOT NULL,
`xbe_bID` int(11) NOT NULL,
`xbe_timestamp` timestamp NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `x_badges_earned` (`xbe_ID`, `xbe_uID`, `xbe_bID`, `xbe_timestamp`) VALUES
(19, 1, 11, '2020-03-23 15:24:54'),
(20, 1, 15, '2020-03-23 15:24:54'),
(21, 1, 16, '2020-03-23 15:24:54'),
(22, 1, 17, '2020-03-23 15:24:54'),
(23, 1, 18, '2020-03-23 15:24:54'),
(24, 1, 19, '2020-03-23 15:24:54'),
(25, 1, 23, '2020-03-23 16:00:51'),
(26, 1, 20, '2020-03-23 15:32:31'),
(27, 1, 21, '2020-03-23 15:32:31'),
(28, 1, 22, '2020-03-23 15:32:31'),
(29, 10, 25, '2020-03-23 15:37:32');
db<>在这里摆弄
解决方案
(xb_icon, xb_requirement_value)
除了值对(颜色是次要的,时间戳不保证排序)之外,我还没有找到任何明确标记的识别表达式。
所以解决方案可以是:
SELECT *
FROM x_badges xb
JOIN x_badges_earned xbe ON xb.xb_ID = xbe.xbe_bID
JOIN ( SELECT xb.xb_icon, MAX(xb.xb_requirement_value) xb_requirement_value
FROM x_badges xb
JOIN x_badges_earned xbe ON xb.xb_ID = xbe.xbe_bID
WHERE xbe.xbe_uID = @user
GROUP BY xb_icon ) max_earned ON (xb.xb_icon, xb.xb_requirement_value)
= (max_earned.xb_icon, max_earned.xb_requirement_value)
WHERE xbe.xbe_uID = @user;
作为建议 - 规范化x_badges
表,将其划分为 2 个单独的表 - 一个存储徽章类型数据,另一个存储与第一个表相关的级别相关数据。
推荐阅读
- powershell - 在 cookie 弹出更新后使用 Net.WebClient 抓取不起作用
- c - 确定一个点是否在多边形内的代码不起作用
- arrays - 包含自定义类的数组总和(Swift)
- c# - C# - 将 unicode 字符(qwerty 布局)转换为其对应的键盘(英文)字符
- typescript - 从对象推断值
- python - 用于推理的自定义激活函数
- c++ - 如何获取可调用类型的签名?
- python - 将视图流与 google-drive django api 集成
- xamarin.ios - 如何为 ios 实现 System.Reactive 调度程序
- .net-core - Serilog 将空白 CorrelationId 发送到 Seq 记录器