mysql:列类型之enum、set

2023-10-27

环境:

  • window10
  • vs2022
  • .net 6
  • mysql 8.0.25
  • DBeaver

参考:
《mysql:11.3.5 The ENUM Type》

注意;在mysql中定义enum和set应该使用英文字母,本文使用汉字是为了方便阅读。

1. enum类型

mysql支持枚举类型,即:只能从其中选择一个值插入到数据库。
用法如下:

create table test(
	t_enum set('刘备','刘禅','张飞')
)
insert into test(t_enum) values('刘备')

mysql中的enum和c#中的枚举很相似,但它也有自己的特点:

  • mysql的enum实际存储的是数字,占用1到2个字节,可表示的数字范围是0-65535;
  • mysql的enum的有效值是从1开始,比如上面示例插入的’刘备’,相当于插入了1;
  • mysql的enum支持字符串和数字操作:
    • 当存储字符串到mysql时,mysql自动将其翻译成数字存储;
    • 当存储数字的时候,mysql则直接插入;
    • 当从mysql读取数据时,mysql自动将其转为字符串输出;
  • mysql在非严格模式下可以插入数字0或空字符串'',建议开启mysql的严格模式;
  • mysql中以枚举列排序的时候,是以其数字形式排序的;

下面是一个使用示例:

create table test(
	t_enum enum('刘备','刘禅','张飞')
)

select * from test

-- 插入
insert into test(t_enum) values('刘备')
insert into test(t_enum) values('刘禅')
insert into test(t_enum) values('张飞')
insert into test(t_enum) values('关羽') -- 报错: Data truncated for column
insert into test(t_enum) values('') -- 严格模式报错:  Data truncated for column
insert into test(t_enum) values(0) -- 严格模式报错:  Data truncated for column

-- 查询
select * from test where t_enum =1 -- 和 where t_enum ='刘备' 一个意思
select * from test where t_enum ='刘备'
select * from test where t_enum >1 -- 得到刘禅、张飞
select * from test order by t_enum desc -- 按枚举倒序排列 张飞、刘禅、刘备

insert into test(t_enum) values(null) -- 依然可以插入null,因为 t_enum 并没指定 not null 

那么在c#中应该怎么表示呢?

  • 首先,在c#中定义的枚举建议从数字1开始,不要使用默认的0;
  • 其次,mysql和c#中都应该使用英文的枚举项,而不是上面示例的中文(比如:上面定义枚举应该是 enum(LiuBei,LiuShan,ZhangFei));

看个示例:

create table test(
	t_enum enum('LiuBei','LiuShan','ZhangFei')
)
public enum EnumTest
{
    LiuBei = 1,
    LiuShan = 2,
    ZhangFei = 3
}

2. set类型

set类型类似于c#中的位枚举,即:可以是枚举项的0到多个组合。
mysql实际存储set还是将其存为数字,占用1、2、4、8个字节。
但和enum不同,mysql存储set的规则和bit类型相似,即:用每一个bit位表示一个枚举项的叠加。
以类型t_set set('刘备','刘禅','张飞')为列,mysql存储如下:
在这里插入图片描述
因为,mysql规定set类型最多占用8个字节(64个bit位),所以set类型最多表示64个枚举项的叠加状态。

set类型和enum类型有一个易混淆的地方:
严格模式下:enum类型不可插入0,不可插入’‘,但set类型在严格模式下也是可以插入0、插入’'的(可以理解为:set类型本身就是为表示叠加状态的,当它为0的时候表示没有任何枚举项叠加,这本身也是叠加状态的一种)。

下面是使用示例:

create table test(
	t_set set('刘备','刘禅','张飞')
)

select * from test

insert into test(t_set) values
	(0),(1),(2),(3),(4),(5),(6),(7);

insert into test(t_set) values
	(''),('刘备'),('刘禅'),('刘备,刘禅'),('张飞'),('刘备,张飞'),('刘禅,张飞'),('刘备,刘禅,张飞');
-- 注意: insert或更新多项的话,中间不能带空格,比如:'刘备, 张飞'会报错,而'刘备,张飞'则不会。
-- 关于空格,mysql真的是处理的不好,datetime带时区的'2022-03-29 01:00:00 +08:00' 因为带空格也会报错(+08:00前面不能有空格),而'2022-03-29 01:00:00 +08:00'则正常。


-- 精确查询
select * from test where t_set='刘备'
select * from test where t_set='刘备,刘禅'
select * from test where t_set=''

select * from test where t_set = 0
select * from test where t_set = 1
select * from test where t_set = 2
select * from test where t_set = 3

-- 模糊查询,相当于是将值转成字符串后进行like
select * from test where t_set like '%刘%'
-- 模糊查询,查询包含枚举项'刘备'的
select * from test where (t_set like '刘备,%' or t_set like '%,刘备,%' or t_set like '%,刘备' or t_set='刘备')
-- 内置函数查询
select * from test where FIND_IN_SET('刘备',t_set)>0 -- 建议写法
-- 使用位运算查询
select * from test where t_set&1 -- 包含刘备的(其中"1"最好不要使用静态数据,应该从枚举项转换过来)
select * from test where t_set&4 and t_set &1 -- 包含刘备和张飞的
select * from test where t_set&5 -- 包含刘备或张飞的(注意和上面的区别)

select * from test order by t_set -- 按照值对应的数字排序
select * from test order by cast(t_set as char) -- 按照值对应的字符串排序

再看下面简单的写法:

create table test(
    name varchar(50),
	t_set set('海归','博士','教授')
)
insert into test values
	('小明1',1),
	('小明2',2),
	('小明4',4),
	('小明1_2',3),
	('小明1_4',5),
	('小明2_4',6),
	('小明1_2_4',7);
select * from test

select * from test where t_set & 1 = 1 -- 包含 "海归" 的
select * from test where t_set & 5 = 5 -- 同时包含 "海归","教授" 的
select * from test where t_set & 5 > 0 -- 至少包含 "海归" 或 "教授" 之一的

select * from test where t_set = 5 -- 同时具有切仅具有 "海归" 和 "教授" 的

3. 修改数据库enum和set的定义

理想的情况下,我们在数据库的enum和set一直不变,但现实往往是一直在变。
比如,

  • 设计时,set类型:set('刘备','刘禅','张飞')
  • 但新的需求后变成了:set('刘备','刘禅','张飞','诸葛亮')
  • 或者变成了:set('刘备','刘禅','赵云')
  • 甚至是:set('刘备','刘禅')

现在我们思考:set类型修改后,数据是否还是正确的?

比如,原来是set('刘备','刘禅','张飞'),要修改成set('刘备','刘禅','赵云')

  • 这个只要我们保证表里没有'张飞'这项数据即可(张飞这项数据即将被删除,表里有的话肯定不行),至于其他的不用管,nysql会自动映射过去。

看示例:

drop table test
create table test(
	t_set set('刘备','刘禅','张飞')
)

insert into test(t_set) values
	('刘备'),('刘禅,刘备'),('张飞');

select * from test
select * from test where t_set=1 -- 根据set定义,此时 '刘备' 对应数字 1

alter table test modify t_set set('刘备','刘禅','赵云') -- 因为表中已有'张飞'数据,报错: Data truncated for column 't_set' at row 3

delete from test where t_set='张飞'
select * from test

alter table test modify t_set set('赵云','刘备','刘禅')

insert into test(t_set) values('刘备,赵云');

select * from test
select * from test where t_set=2 -- 根据set定义,此时 '刘备' 对应数字 2

注意:当我们修改定义后,数据会自动进行调整,我们不需要关心。
我们需要关心的是,如果我们使用 where t_set&1 -- 查询包含刘备的这种形式查询的话就危险了,因为重新定义后项对应的数字可能会发生更改,所以我们应该使用引用定义的,而不是数字。
当然,如果我们在程序中动态生成对应数字的话,就不用考虑了。

补充: enum和set的定义修改是一样的,只要我们保证现有的数据中没有要删除的定义就可以放心修改了,实验sql如下:

drop table test
create table test(
	t_enum enum('刘备','刘禅','张飞')
)

-- 插入
insert into test(t_enum) values('刘备'),('刘禅'),('张飞')

select * from test
select * from test where t_enum=1 -- 此时,'刘备'项对应数字 1

alter table test modify t_enum enum('赵云','刘备','刘禅') -- 因为表中已有 '张飞'数据,所以报错:Data truncated for column 't_enum' at row 2
 

delete from test where t_enum='张飞'

select * from test

alter table test modify t_enum enum('赵云','刘备','刘禅')

insert into test(t_enum) values('赵云')

select * from test
select * from test where t_enum =1 -- 此时,'赵云'项对应数字 1

4. c#中应该怎么使用?

那么,在c#中应该怎么表示呢?
直接看实例:

[Flags]
public enum EnumTest
{
    LiuBei = 1,
    LiuShan = 2,
    ZhangFei = 4
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

mysql:列类型之enum、set 的相关文章

随机推荐

  • UML系统分析和设计:用例图

    用例图 1 概述 1992年jacobson提出了用例的概念和可视化表示方法 用例图 作为软件项目开发和规划的一个基本模型元素 所谓用例是指系统的外部事物 活动者 设备或外部系统 与系统的交互 它表达了系统的功能 即系统所提供的服务 用例图
  • python调用百度智能云API请求(以自然语言处理——词法分析为例)

    调用API的思路 获得api的token 按官方文档发送链接 分析返回的结果 步骤一 获取API的token 如果不知道token是啥 或是不知道怎么获取token 请参考 https blog csdn net weixin 357577
  • 智能合约-ERC20接口方法详解

    官方文档 EIP 20 Token Standard 实现Demo https github com ConsenSys Tokens blob fdf687c69d998266a95f15216b1955a4965a0a6d contra
  • Java调用C语言DLL文件方法

    有时候我们经常要在 JAVA中调用C语言DLL文件 下面我们将用一个例题来向大家介绍 JAVA调用C语言DLL文件的实现方法 一 生成C的头文件 1 编辑Main java public class Main public native s
  • 嘴说手画Spark的存储系统

    Spark本身并不存储数据 这里所说的存储系统是指计算过程中 管理内存中数据 如读到内存的源数据 缓存的RDD数据 广播数据 Shuffle文件数据的功能模块 如果没有存储管理系统 计算是无法完成的 存储系统的主要由以下组件构成 Block
  • 建立时间裕量和保持时间裕量

    前面的博客里面有讲解建立时间Tsetup和保持时间Tholdon的概念以及要满足的和时钟之间的关系 这里不再重复 在了解建立时间裕量和保持时间裕量之前我们先来了解一下触发沿Launch Edges 和锁存沿Latch Edges 一般认为L
  • Redis(四)Redis集群搭建

    Redis集群搭建 pwd命令主要用于打印当前工作目录的工作路径 Keepalived Redis服务器的高可用除了用集群和哨兵模式外 还可以用keepalived Keepalived的作用是检测服务器的状态 如果有一台web服务器宕机
  • shader学习过程3——shader编程语言

    shader language最初是由汇编语言编写 难度高 入门难 现在由三种高级语言可以编写 一 HLSL 基于DirectX的High Level Shading Language 简称HLSL DirectX简称DX 微软的产品 优点
  • stm32--USB(作为U盘)+FatFs的实现

    一 USB功能的添加 作为U盘 添加文件 将官方库中的Library文件夹中的所有有效文件添加到工程中 分为4个文件夹 usb class为硬件相关 Library Class usb driver为底层驱动 Driver usb libr
  • 如何制作多系统启动U盘

    Ventoy简介 简单来说 Ventoy是一个制作可启动U盘的开源工具 并且它有诸多优势 有了Ventoy你就无需反复地格式化U盘 你只需要把 ISO WIM IMG VHD x EFI 等类型的文件直接拷贝到U盘里面就可以启动了 无需其他
  • openssl: error while loading shared libraries: libssl.so.1.1

    在执行openssl version出现如下错误 openssl error while loading shared libraries libssl so 1 1 cannot open shared object file No su
  • HyperLPR车牌识别相关资源整理

    一 HyperLPR使用 源码分析相关资料 1 HyperLPR中文车牌识别 中给出了视频文件的处理方法 可以参考下 因为识别检测本身比较耗时 所以从画面上看 视频文件播放非常慢 这里需要根据上层应用根据自己的需要进行丢帧处理 PlateR
  • 16-Ansible常用模块-service模块

    一 概述 service 模块可以帮助我们管理远程主机上的服务 比如 启动或停止远程主机中的 nginx 服务 注意 假如想要管理远程主机中的某个服务 那么这个服务必须能被 BSD init OpenRC SysV Solaris SMF
  • 机器人教育的魅力是什么

    机器人教育指通过设计 组装 编程 运行机器人 激发学生学习兴趣 培养学生综合能力 它融合了机械原理 电子传感器 计算机软硬件及人工智能等众多先进技术 对学生能力 素质的培养有着巨大的作用 与传统的编程教育不同 机器人教育往往通过形象生动的图
  • 计算机视觉论文-2021-07-14

    本专栏是计算机视觉方向论文收集积累 时间 2021年7月14日 来源 paper digest 欢迎关注原创公众号 计算机视觉联盟 回复 西瓜书手推笔记 可获取我的机器学习纯手推笔记 直达笔记地址 机器学习手推笔记 GitHub地址 1 T
  • QT——键盘事件(捕获按键事件)

    文章目录 qt增加按键事件处理响应 qt增加按键事件处理响应 在使用qt时 当需要处理按键触发的键盘事件的时候 需要用到事件触发响应 查阅文档 QT已经实现了这一系列的键盘事件 void QWidget keyPressEvent QKey
  • 基于python的人脸识别系统设计与实现

    案例分享之基于python的人脸识别系统设计与实现 人脸识别即程序对输入的图像进行判别是否有人脸 并识别出有人脸的图像所对应的人 即我们常说的人脸识别一般包含了人脸检测和人脸识别两部分 下面对其在opencv中的相应模块进行分别介绍 在op
  • Spark kryo Jar包冲突问题排查

    错误日志 Exception in thread adaptive query stage 0 java lang NoSuchMethodError com esotericsoftware kryo Kryo setInstantiat
  • 3GPP简介及标准查找指南

    3GPP是积极倡导UMTS为主的第三代标准化组织 成立于1998年12月 是一个协作协议 3GPP最初的工作范围是第三代移动系统指定全球使用的技术规范与技术报告 第三代移动系统是基于发展的GSM核心网络和它们所支持的无线接入技术 随后3GP
  • mysql:列类型之enum、set

    环境 window10 vs2022 net 6 mysql 8 0 25 DBeaver 参考 mysql 11 3 5 The ENUM Type 注意 在mysql中定义enum和set应该使用英文字母 本文使用汉字是为了方便阅读 1