首页 > 数据库 >数据库sql中判断时间冲突

数据库sql中判断时间冲突

时间:2023-09-21 10:24:46浏览次数:52  
标签:24 00 数据库 跨天 冲突 sql 2.1 e1 s1

数据库现有数据其中两列: s - 开始时间, e - 结束时间. 在新插入数据s', e'之前需要判断两个时间之间是否有重合
因为使用mybatis-plus的缘故, 结论都使用s或e在符号前面.

1. s < e

比如yyyy-MM-dd HH:mm:ss格式的数据, 多用于判断预约时间和每日排班冲突.
对于冲突的情况使用列举法有

  • s' < e' < s < e: 新时间段在已有时间左边, 不包含, 情况1
  • s' < s < e' < e: 新时间段和已有时间左边有交集, 情况2
  • s < s' < e' < e: 新时间段在已有时间内, 被包含关系, 也即在已有时间段内部, 情况3
  • s < s' < e < e': 新时间段和已有时间右边有交集, 情况4
  • s' < s < e < e': 新时间和已有时间是是包含关系, 也即新时间段在已有时间段外部, 情况5
  • s < e < s' < e': 新时间段在已有时间右边, 不包含, 情况6
    除去开始和最后的不包含, 可以得到当s < e' 并且 e > s'时候两个时间端肯定有交集, 也即冲突.
    image

2. 存在s > e

比如HH:mm:ss格式的, 多用于固定早中晚班定义 / 营业时间等周期性活动的时间冲突判断.

2.1 分类逐步分析

2.1.1 s < e

  • s' < e': 同1, 判断s < e' 并且 e > s'即可
  • s' > e': 也即跨天的时候, 分成s' - 240 - e'
    • 前半段: 同1; (同下面24肯定大于s, 逻辑上可以与第一种情况写到一起)
    • 下半段: 0 < e, 只需要判断s < e'即可

2.1.2 s > e

同理拆分成s - 24 和 0 - e.

  • s' < e': 不跨天
    • 前半段: 24肯定大于s', 只需要判断s < e'
    • 后半段: 0肯定小于e', 只需要判断e > s'
  • s' > e': 跨天, 拆分成s'-24 和 0-e' (这种必有24, 答案恒真)

2.1.3 代码

对于s > e情况下, 虽然sql可以使用start_time > end_time, 但是在mybatis-plus中写不出来
所以在保存时候添加一列is_greater代表是否当条数据跨天:

// 保存跨天时候的结束时间, 将结束时间变成24:00:00
// 传过来的结束时间赋值给nextDayEndTime, 也即finalNextDayEndTime
String finalNextDayEndTime = nextDayEndTime;
List<BaseTimeConfig> existList = configService.lambdaQuery()
	.and(p -> p
		// 按照开始小于结束判断(数据也是开始小于结束)
		.and(q -> q.eq(BaseTimeConfig::getIsGreater, 0)
			.and(q1 -> q1
				.lt(BaseTimeConfig::getStartTime, endTime)
				.gt(BaseTimeConfig::getEndTime, startTime))
			// 开始大于结束时间时候(), 计算拆分出来的第二天也即0点 - endTime(复制给了nextDayEndTime)
			// 需要((开始小于结束 和 开始大于结束拆分出第一天) or (开始大于结束拆分出第二天))满足其一即可
			// 拆分出来的第二天是0开始, 结束时间肯定肯定比0大, 所以判断开始时间比nextDayEndTime小即可
			.or(!"".equals(finalNextDayEndTime), q1 -> q1.lt(BaseTimeConfig::getStartTime, finalNextDayEndTime)))
		// 按照开始小于结束判断(数据是开始大于结束的, 判断结束时间大于传入的开始时间即可,
		// 因为数据库开始时间应该算0, 0肯定比传入的开始时间小于)
		.or(q -> q.eq(BaseTimeConfig::getIsGreater, 1)
			.and(q1 -> q1
				// 后半截
				.and(q2 -> q2.gt(BaseTimeConfig::getEndTime, startTime))
				// 前半截
				.or(q2 -> q2.lt(BaseTimeConfig::getStartTime, endTime)))))
	.ne(baseTimeConfig.getId() != null && baseTimeConfig.getId() > 0,
		BaseTimeConfig::getId, baseTimeConfig.getId())
	.isNull(BaseTimeConfig::getDeletedAt)
	.list();

2.1.4 总结

总体思路清晰, 逐步分析得到, 但不巧妙

2.2 预处理

2.2.1 提出假设

在保存s和e时候, 如果是跨天的拆分成s,24,0,e; 不跨天的话使用s,e,s,e, 对应字段s,e,s1,e1
对于s'和e'来说也是同上, 拆分出s',e',s1',e1'
分别比较s,e和s',e's1,e1和s1',e1', 两个条件使用或者连接, 也即: ((s < e' 并且 e > s') 或者 (s1 < e1' 并且 e1 > s1'))

2.2.2 分情况论证

  • 当两个都是跨天时候
    • 因为e,s1,e',s1'分别是24,0,24,0
    • 所以式子可以写为: ((s < 24 并且 24 > s') 或者 (0 < e1' 并且 e1 > 0))
    • 进一步得出: 两边都恒真, 也即两个都跨天时候肯定有重合的.
    • 0点肯定在的, 故成立. 见2.1.2下第二条
  • 当只s,e跨天时候
    • 因为e,s1,s1',e1'分别是24,0,s',e'
    • 所以式子可以写为: ((s < e' 并且 24 > s') 或者 (0 < e' 并且 e1 > s'))
    • 进一步可以得出: 只需要判断(s < e') 或者 (e1 > s')即可
    • 数据库跨天, 传入不跨, 见2.12下的第一条(e1始终是2.1中的e)
  • 当只s',e'跨天时候
    • 因为s1,e1,e',s1'分别是s,e,24,0
    • 所以式子可以写为: ((s < 24 并且 e > s') 或者 (s < e1' 并且 e > 0))
    • 进一步可以得出: 只需要判断(s < e1') 或者 (e > s')即可
    • 数据库不跨, 传入跨, 见2.1.1的第二条(e1'始终是2.1中的e')
  • 当都不跨天时候
    • 因为s1,e1,s1',e1'分别是s,e,s',e'
    • 所以式子可以写为: ((s < e' 并且 e > s') 或者 (s < e' 并且 e > s'))
    • 进一步可以得出: 只需要判断s < e' 并且 e > s'即可
    • 都不跨天, 也即都增, 见1 或 2.1.1的第一条
  • 综上, 在保存se时候, 如果保存成四个字段, 如果跨天: s,24,0,e; 如果不跨天就s,e,s,e; 同理s',e'也相同规则拆分开
    使用前面两个和前面两个比较, 后面两个与后面两个比较的结论成立.
    (一个跨天, 一个不跨天时候, 使用不跨天的必须要与跨天的两端比较, 那就不跨天时候存两遍, 这样就都比较了)

2.2.3 代码

// s', e'
String startTime = "22:00:00", endTime = "24:00:00";
// s1', e1'
String startTime1 = "00:00:00", endTime1 = "03:00:00";

// ((s < e' 并且 e > s') || (s1 < e1' 并且 e1 > s1'))
configService.lambdaQuery()
	.and(q -> q
		.lt(BaseTimeConfig1::getS, endTime)
		.gt(BaseTimeConfig1::getE, startTime))
	.or(q -> q
		.lt(BaseTimeConfig1::getS1, endTime1)
		.gt(BaseTimeConfig1::getE1, startTime1))
	.list();

2.2.4 总结

分两段存, 跨天时候24截取. 不跨天时候存两遍

标签:24,00,数据库,跨天,冲突,sql,2.1,e1,s1
From: https://www.cnblogs.com/Ddlm2wxm/p/17718564.html

相关文章

  • 数据库集群
    一、海量数据存储问题    传统的关系型数据库,因为数据存储量越来越大,已经无法满足快速查询与插入数据的需求。NoSql的出现暂时解决了这一危机。它通过降低数据的安全性,减少对事务的支持,减少对复杂查询的支持,换取性能的提升。   有的场景要求绝对要有事务与安全指标......
  • 利用sqoop将hive数据导入导出数据到mysql
    运行环境 centos5.6  hadoop hivesqoop是让hadoop技术支持的clouder公司开发的一个在关系数据库和hdfs,hive之间数据导入导出的一个工具在使用过程中可能遇到的问题:sqoop依赖zookeeper,所以必须配置ZOOKEEPER_HOME到环境变量中。sqoop-1.2.0-CDH3B4依赖hadoop-core-0.20.2-......
  • Windows10 Redis数据库的搭建
    参考:https://blog.csdn.net/qq_53381910/article/details/130383352  http://wed.xjx100.cn/news/96490.html?action=onClick......
  • 数据库为什么要索引(转)
    总结:数据库存储顺序随机,如果没有索引,每次查询都需要一行行遍历,查找出符合条件的点,复杂度O(N)数据库会按照rowid排序,并给主键建立索引,所以如果以rowid或者主键为搜索条件,复杂度可以近似看做二分查找的复杂度,即O(logN)如果没有主键,或搜索条件不是主键,可以给搜索目标增加索......
  • mysql权限控制
    1.授权数据表(database_name.table_name)所有的权限给'user'@'localhost'GRANTALLONdatabase_name.table_nameTO'user'@'localhost';ALL包含的权限类型如下:SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,RELOAD,PROCESS,REFERENCES,IND......
  • MySQL数据库管理
    MySQL数据库管理概念数据(data)描述事物的符号记录包括数字、文字图形、图像、声音、档案记录以“记录”的形势按统一的格式进行存储表将不同的记录组织在一起用来存储具体数据数据库表的集合,是存储数据的仓库以一定的组织方式存储的相互有关的数据集......
  • MySQL索引、事务与存储引擎
    MySQL索引、事务与存储引擎索引介绍1、索引的概念索引是一个排序的列表,在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址(类似于C语言的链表通过指针指向数据记录的内存地址)。使用索引后可以不用扫描全表来定位某行的数据,而是先通过索引表找到该行数据对应的......
  • MySQL备份与恢复
    MySQL备份与恢复备份的介绍数据库加载慢1服务器配置不够、2别的进程占用大部分资源;3语句累赘;4、遇到select语句查询速度慢,怎么办?先使用explain分析select查询语句,看key字段,确定select查询语句是否使用了索引或索引使用是否正确。然后再根据select查询语句使用......
  • MySQL高级SQL语句
    MySQL高级SQL语句围绕两张表Location表Store_Info表 #select选择 SELECTStore_NameFROMStore_Info; #distinct去重 selectdistinct列名from表名 #where条件查询 selectdistinct列名from表名where #and且or或 语法:SELECT"字段"FROM"表名"WHE......
  • MySQL 高级(进阶) SQL 语句——其二
    MySQL高级(进阶)SQL语句视图----CREATEVIEW----视图,可以被当作是虚拟表或存储查询。视图跟表格的不同是,表格中有实际储存数据记录,而视图是建立在表格之上的一个架构,它本身并不实际储存数据记录。临时表在用户退出或同数据库的连接断开后就自动消失了,而视图不会消失。视......