MySQL MAKE_SET 怎样把位掩码转换成枚举字符串
来源:17golang原创
时间:2026-10-29 15:33:04 281浏览 收藏
MySQL 的 MAKE_SET(bits, str1, str2, ...) 可以把整数位掩码转换成逗号分隔的标签字符串。最低位对应第一个标签,下一位对应第二个标签。实际使用时,先固定“权重—标签”字典,再把表达式放到查询的 SELECT 列表。
例如通知渠道用1表示站内信、2表示邮件、4表示短信,数字5就表示站内信和短信。这里的“枚举字符串”指展示文本,函数不会自动创建 ENUM 或 SET 类型字段。
MySQL 官方文档:https://dev.mysql.com/doc/refman/8.4/en/string-functions.html
固定权重字典:先约定每一位表示什么
假设业务把通知策略的渠道组合保存在 channel_mask 整数字段。报表希望把数字显示成渠道名,第一件事是确定原始整数的编码约定,不能根据页面上标签的排序猜测。
| 二进制位 | 权重 | 标签 |
|---|---|---|
| bit 0,最低位 | 1 | 站内信 |
| bit 1 | 2 | 邮件 |
| bit 2 | 4 | 短信 |
3是1与2的组合,5是1与4的组合,7是三个渠道的组合。权重4对应第三个标签,绝不是“第4项”。本文只讨论这三个标志的非负整数输入,不把这些例子扩展成负数或任意长度二进制数据的通用约定。

编写查询投影:原始数字和展示文本一起保留
下面用一组查询内数据展示表达式的放置位置,不创建业务表,也不修改已有记录。这是依据 MySQL 8.4 文档编写的原创示例,本文没有连接数据库执行。
-- 用只读查询数据表达组合,不写入业务表。
WITH samples AS (
SELECT 101 AS policy_id, 0 AS channel_mask
UNION ALL SELECT 102, 1
UNION ALL SELECT 103, 3
UNION ALL SELECT 104, 5
UNION ALL SELECT 105, 7
)
SELECT policy_id, channel_mask,
-- 参数顺序固定对应权重1、2、4。
MAKE_SET(channel_mask, '站内信', '邮件', '短信') AS channel_names
FROM samples
ORDER BY policy_id;
按字典推导,0得到空字符串,1得到站内信,3得到“站内信,邮件”,5得到“站内信,短信”,7得到三个渠道。分隔符为英文逗号,不会自动补空格。这些是规则推导的预期值,不是执行截图或测试记录。
真实报表也建议保留 channel_mask 原始列,channel_names 只是派生展示列。这样显示异常时,可以区分是整数值异常、标签顺序错误还是文案改变,避免把展示文本当成事实来源。
处理缺失和未知位:不要让空白掩盖数据状态
业务中的0可能表示“明确未选择”,NULL可能表示“尚未配置”,两者不能随意合并。另一个容易忽略的情况是掩码中出现了字典之外的位;已知标签的显示无法完整描述这个整数。
-- 本例只有权重1、2、4,已知掩码为7。
WITH samples AS (
SELECT 201 AS policy_id, 0 AS channel_mask
UNION ALL SELECT 202, NULL
UNION ALL SELECT 203, 13
)
SELECT policy_id, channel_mask,
-- 显式区分未配置与未选择,不依赖页面对空白的处理。
CASE
WHEN channel_mask IS NULL THEN '未配置'
WHEN channel_mask = 0 THEN '未选择'
ELSE MAKE_SET(channel_mask, '站内信', '邮件', '短信')
END AS channel_names,
-- 对本例非负整数,检查是否包含已知集合之外的位。
CASE
WHEN channel_mask IS NULL THEN NULL
ELSE (channel_mask & 7) channel_mask
END AS has_unknown_bits
FROM samples
ORDER BY policy_id;
13包含权重1、4、8,其中8没有对应标签。它的已知标签部分仍可显示“站内信,短信”,但这个文本没有表达权重8。has_unknown_bits 单独标记这一差异,避免把13误认为5。遇到未知位,应按业务契约决定拒绝、兼容或提示未知项;不要直接清掉未知位再覆盖原数据。
还要区别“掩码缺失”与“标签参数缺失”。官方规则说明,标签参数中的 SQL NULL 不追加到结果,但不会让后续参数的位置前移:
-- 邮件的位置仍属于权重2;NULL占位不会改变短信对应的权重4。 SELECT MAKE_SET(7, '站内信', NULL, '短信') AS channel_names;
这个表达式预期得到“站内信,短信”。如果直接删去第二个标签参数,短信就变成第二项,历史整数的含义也随之改变。NULL占位有助于解释行为;长期字典还应记录废弃项及编码版本,不能只依赖临时SQL。

保持展示契约稳定:标签顺序也属于数据定义
给标签按拼音重新排序,或把新渠道插在参数列表中间,都会改变旧数字的解释。新增标志应分配新的位,并同步维护写入端、读取端和文档。不要只改一条报表SQL,就认为完成了编码升级。
MAKE_SET 的结果适合阅读,不宜作为无损的集合交换格式。标签本身含逗号时,接收方按逗号拆分会产生歧义。跨服务接口可以保留掩码与字典版本,或者由应用生成明确的数组结构;不要依靠该函数自动完成CSV转义。
如果只是判断短信渠道是否启用,应直接表达整数位条件,不必先转标签再搜索字符串:
-- notification_policy是示例业务表名,权重4固定代表短信。 SELECT policy_id, channel_mask FROM notification_policy WHERE (channel_mask & 4) = 4;
需要把示例表名替换成实际业务表。这里没有承诺按位条件一定使用索引,也没有性能测试结论;存储结构是否适合长期查询,应结合实际条件另行判断。
落地顺序与速查表
推荐先约定输入类型、位定义与NULL语义,再在查询投影中增加MAKE_SET表达式,接着补齐0值和未知位状态,最后明确接收方是否只用于展示。发布字典变更时,把编码与解码两端纳入同一变更范围。
| 情况 | 处理方式 |
|---|---|
| 5需要显示两个渠道 | 使用权重1和4对应的第一、第三项 |
| 0显示为空白 | 按业务约定显示“未选择” |
| NULL代表未配置 | 用CASE保留区别 |
| 掩码含未定义位 | 保留原值,另加状态字段 |
| 中间标签废弃 | 保留原位定义,避免参数移位 |
| 标签需要供接口消费 | 使用明确的结构化契约 |
MAKE_SET会自动修改字段类型吗?
不会。SELECT中的表达式只生成展示值,不会改变表结构或增加字段约束。
为什么换了两个标签的位置,旧记录显示就变了?
函数按参数位置解释位,原始整数没有改变。恢复原字典顺序,再通过明确迁移处理真正需要的编码变化。
为什么不同整数显示相同标签?
可能包含未定义位,或对应标签被设为NULL。相同展示文字不证明原始值等价,因此应保留整数和状态信息。
规则依据:MySQL MAKE_SET官方说明。通知渠道场景、字典与SQL组织为原创示例。
-
374 收藏
-
499 收藏
-
384 收藏
-
184 收藏
-
265 收藏
-
492 收藏
-
443 收藏
-
454 收藏
-
143 收藏
-
209 收藏
-
369 收藏
-
400 收藏
-
393 收藏
-
164 收藏
-
257 收藏
-
369 收藏
-
191 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习