MySQL 如何实现一个只有一行数据的表
文章目录
大家好,我是只谈技术不剪发的 Tony 老师。我们在之前的文章中介绍了如何在 PostgreSQL 中实现一个只能存储一行数据的表。今天我们来看看如何在 MySQL 中实现相同的功能。
只有一行数据的表通常被用于某些特定的功能,例如存储系统的版本或者配置信息,全局计数器,心跳表等。假如我们有一个表 t_visit,用于记录网页的访问量:
create table t_visit( hits bigint not null, update_at datetime not null );
在部署程序时需要生成一条记录,将访问量初始化为 0;以后每次用户访问时需要加 1;为了前端页面能够正确显示,不允许用户删除该记录。这种需求该如何实现?
MySQL 5.6 实现
对于 MySQL 5.6 以及之前的版本,可以通过增加一个 ENUM 枚举字段和唯一约束限制表中只能存储一行数据:
alter table t_visit add only_one_row enum('Y') not null default 'Y'; alter table t_visit add constraint uk_visit unique key (only_one_row);
新增加的字段 only_one_row 非空且取值只能为 Y,同时基于该字段创建了一个唯一约束,因此整个表中只能存储一行数据。
初始化时插入数据如下:
insert into t_visit(hits, update_at) values (0, now()); select * from t_visit; hits|update_at |only_one_row| ----|-------------------|------------| 0|2020-07-07 08:05:03|Y |
如果数据已经存在,再次插入数据将会返回错误:
insert into t_visit(hits, update_at) values (1, now()); ERROR 1062 (23000): Duplicate entry 'Y' for key 't_visit.uk_visit'
实际上此时应该进行更新操作:
update t_visit set hits=hits+1, update_at= now() where only_one_row = 'Y';
或者,可以使用
INSERT ... ON DUPLICATE KEY UPDATE语句进行统一操作:
-- 清空数据 truncate table t_visit; -- 第一次插入数据 insert into t_visit(hits, update_at) values (1, now()) on duplicate key update hits=ifnull(hits,0)+1, update_at= now(); select * from t_visit; hits|update_at |only_one_row| ----|-------------------|------------| 1|2020-07-07 08:22:32|Y | -- 第 N 次插入数据 insert into t_visit(hits, update_at) values (1, now()) on duplicate key update hits=ifnull(hits,0)+1, update_at= now(); select * from t_visit; hits|update_at |only_one_row| ----|-------------------|------------| 2|2020-07-07 08:22:59|Y |
为了防止表中的数据被误删除,需要通过一个触发器来实现禁止删除操作:
delimiter $$ create trigger tri_disable_visit_del before delete on t_visit for each row begin signal sqlstate '45000' set message_text = '禁止删除访问信息!'; end$$ delimiter ;
该触发器是一个针对删除操作的 BEFORE 触发器,在任何删除操作之前返回错误信息。创建触发器之后,当我们尝试删除表中的记录:
delete from t_visit where only_one_row = 'Y'; ERROR 1644 (45000): 禁止删除访问信息! select * from t_visit; hits|update_at |only_one_row| ----|-------------------|------------| 2|2020-07-07 08:22:59|Y |
删除语句返回了错误信息,表中的数据仍然存在。不过,TRUNCATE TABLE 语句仍然可以清除表中的数据,因为它不会触发 DML 触发器。
MySQL 5.7 实现
MySQL 5.7 除了使用前面的方法之外,还可以利用新增加的计算列(Generated Column)加唯一约束的方式。例如:
-- 删除 t_visit 表 drop table t_visit; create table t_visit( hits bigint not null, update_at datetime not null, only_one_row int as (1) unique );
其中,字段 only_one_row 是一个虚拟的计算列,同时具有唯一性。插入数据的结果如下:
insert into t_visit(hits, update_at) values (0, now()); select * from t_visit; hits|update_at |only_one_row| ----|-------------------|------------| 0|2020-07-07 09:22:13| 1| insert into t_visit(hits, update_at) values (1, now()); ERROR 1062 (23000): Duplicate entry '1' for key 't_visit.only_one_row'
同样,我们也可以使用
INSERT ... ON DUPLICATE KEY UPDATE语句进行统一操作,具体参考上文中的 MySQL 5.6 实现。
利用触发器可以防止表中的数据被误删除,具体参考上文中的 MySQL 5.6 实现。
MySQL 8.0 实现
MySQL 8.0.13 之后除了可以使用上面介绍的两种方法之外,还可以通过函数索引实现相同的功能。例如:
create table t_visit( hits bigint not null, update_at datetime not null ); create unique index uk_visit on t_visit( (1) );
其中,索引 uk_visit 是一个基于常量 1 的函数索引,并且具有唯一性。函数索引实际上是虚拟列索引的扩展,因此两者非常相似。
插入数据的结果如下:
insert into t_visit(hits, update_at) values (0, now()); select * from t_visit; hits|update_at |only_one_row| ----|-------------------|------------| 0|2020-07-07 09:22:13| 1| insert into t_visit(hits, update_at) values (1, now()); ERROR 1062 (23000): Duplicate entry '1' for key 't_visit.uk_visit'
同样,我们也可以使用
INSERT ... ON DUPLICATE KEY UPDATE语句进行统一操作,具体参考上文中的 MySQL 5.6 实现。
利用触发器可以防止表中的数据被误删除,具体参考上文中的 MySQL 5.6 实现。
总结
在 MySQL 中为了实现一个只有一行数据的表,可以创建一个数值为常量的字段,并且基于该字段创建唯一索引。ENUM 枚举数据类型和计算列都可以用于实现该功能,MySQL 8.0 新增的函数索引甚至不需要创建额外的字段就可以实现相同的功能。
除了本文使用的方法之外,你还有没有其他的实现方法?欢迎关注❤️、评论📝、点赞👍
- mysql插入一行数据,其中一个值为当前该列的最大值,怎么实现?
- C# winform datagridview中如何实现鼠标右键点击一行数据出现一个带有删除的菜单,并能执行删除操作?
- 一个通用的单元测试框架的思考和设计06-实现篇-自动管理测试数据-如何临时关闭数据外键约束
- 一个通用的单元测试框架的思考和设计06-实现篇-自动管理测试数据-如何临时关闭数据外键约束
- mysql中根据一个字段相同记录写递增序号,如序号结果,如何实现?
- 一个简单的php实现的MySQL数据浏览器
- mysql随机取数据,如何实现高效率?
- MySQL实现把两行数据合并为一行
- 编程实现: 一组数据中只有一个数字出现了一次。其他所有数字都是成对出现的。 请找出这个数字。(使用位运算)
- Linux系统中,有两个文件file1和file2,每个文件的每一行都是#UUID,其中的每一UUID表示一个号。要找出在file1中有而在file2中没有的UUID,使用cat,sort,uniq三个命令如何实现
- mysql update 两个表关联{两个关联表如何更新其中一个表的数据}
- mysql实现搜索多行数据合并成一行
- 如何将用分号分开的一行数据保存到一个二维矩阵中?
- 如何把mysql的列修改成行显示数据简单实现
- mysql 复制一个表中数据到另一个表实现方法
- mysql 如何在一个字段内存取多个数据
- ASP.NET中如何实现同一时间只有一人能够修改系统数据
- [原创]如何实现MySQL表数据随机读取
- 在mysql中如何使用一个表中的数据去更新另外一个表的数据
- MySql中把一个表的数据插入到另一个表中的实现代码