MySql对于时间段交集的处理和通用实现方式(MyBatis-Plus)

问题:一般传统时间筛选是在[ 开始时间 → 结束时间 ]这个区间内的子集,也就是全包含查询方式,这种只会筛选一种情况。如果场景需要是开展一个活动,需要活动时间检索应该但凡包含就返回,也就是需要查询这个时间段有涉及的都需要筛选出来,即返回产生交集的数据

§ 1.数据分析​

上图是4 - 5月份中开展活动7种时间段,如果以V1的启止时间作为筛选条件,会遇到6种情况

V2:数据位于查询左侧,不产生交集

        V2结束时间 ≥ V1开始时间

V3:数据交集查询左侧区域,产生交集

        V1开始时间 ≤ V3结束时间 ≤ V1结束时间,

V4:数据位于查询的子集内,产生交集

        V4结束时间 ≥ V1结束时间,V4开始时间 ≤ V1开始时间

V5:数据交集查询右侧区域,产生交集

        V1开始时间 ≤ V5开始时间 ≤ V1结束时间

V6:数据位于查询右侧,不产生交集

        V1结束时间 ≤ V6开始时间

V7:数据的部分子集数据位于查询全集区域,产生交集

        V7开始时间 ≥ V1开始时间,V1结束时间 ≤ V7结束时间,

        这 6 种情况,产生交集的只有 4 种,也就是需要把这4种情况的时间段筛选出来,可以归纳为三类场景

查询时间以 [ startTime, endTime ] 作为筛选条件,开始时间和结束时间为某一个时间段的代称

        1. 全部包含(子集)和左边包含V3V4startTime ≥ 结束时间  ≥ endTime

        2. 右边包含V5startTime ≥ 开始时间  ≥ endTime

        3. 全部包含(被子集)V7)开始时间 ≥ startTimeendTime  ≥ 结束时间

§ 2.MySql查询尝试

创建一个活动表,补充活动开始时间和结束时间,并填充6种情况数据数据

CREATE TABLE `activity` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `activity_start_time` datetime DEFAULT NULL COMMENT '活动开始时间',
  `activity_end_time` datetime DEFAULT NULL COMMENT '活动结束时间',
  PRIMARY KEY (`id`)
) ENGINE = InnoDB AUTO_INCREMENT = 0 DEFAULT CHARSET = utf8 COMMENT = '活动';

MySql对于时间段交集的处理和通用实现方式(MyBatis-Plus)_第1张图片

我们需要查询的时间段是 [ "2022-04-28 00:00:00" , "2022-05-04 00:00:00" ] 涉及的数据

SELECT * from activity where
# 全部包含(子集)和左边包含
("2022-04-28 00:00:00" <=activity_end_time and activity_end_time <="2022-05-04 00:00:00")
# 右边包含
or ("2022-04-28 00:00:00"<=activity_start_time and activity_start_time <="2022-05-04 00:00:00")
# 全部包含(被子集)
or (activity_start_time <= "2022-04-28 00:00:00" and "2022-05-04 00:00:00" <= activity_end_time)


§ 3.通用方法

Mysql通用模板

SELECT * from activity where
# 全部包含(子集)和左边包含
("开始时间" <=activity_end_time and activity_end_time <="结束时间")
# 右边包含
or ("开始时间"<=activity_start_time and activity_start_time <="结束时间")
# 全部包含(被子集)
or (activity_start_time <= "开始时间" and "结束时间" <= activity_end_time)

MyBatis-plus通用功能

    /**
     * 时间交集,与当前时间有交集筛选
     *
     * @param beginColumn 指定开始列
     * @param endColumn   指定结束列
     * @param startTime   开始时间
     * @param endTime     结束时间
     * @param          类型
     * @param          列类型
     * @return
     */
    public  Consumer> timeIntersection(
            SFunction beginColumn, SFunction endColumn, Date startTime, Date endTime) {
        return wrapper -> {
            //全部包含(子集)和左边包含
            wrapper.and(x -> x.ge(endColumn, startTime).le(endColumn, endTime))
                    //右边包含
                    .or(x -> x.ge(beginColumn, startTime).le(beginColumn, endTime))
                    //全部包含(被子集)
                    .or(x -> x.le(beginColumn, startTime).ge(endColumn, endTime));
        };
    }

使用方式


    @Test
    public void testTime() throws Exception{
        //数据准备
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date startTime =sdf.parse("2022-04-28 00:00:00");
        Date endTime =sdf.parse("2022-05-04 00:00:00");

        //使用方式
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper()
                .func(startTime != null && endTime != null, timeIntersection(
                        Activity::getActivityStartTime, Activity::getActivityEndTime, startTime, startTime));
    }

    /**
     * 时间交集,与当前时间有交合条件
     *
     * @param beginColumn 指定开始列
     * @param endColumn   指定结束列
     * @param beginTime   开始时间
     * @param endTime     结束时间
     * @param          类型
     * @param          列类型
     * @return
     */
    public static   Consumer> timeIntersection(
            SFunction beginColumn, SFunction endColumn, Date beginTime, Date endTime) {
        return wrapper -> {
            //全部包含(子集)和左边包含
            wrapper.and(x -> x.ge(endColumn, beginTime).le(endColumn, endTime))
                    //右边包含
                    .or(x -> x.ge(beginColumn, beginTime).le(beginColumn, endTime))
                    //全部包含(被子集)
                    .or(x -> x.le(beginColumn, beginTime).ge(endColumn, endTime));
        };
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Activity{
        /** 主键 */
        private Long id;
        /** 开始时间 */
        private Date activityStartTime;
        /** 结束时间 */
        private Date activityEndTime;
    }

你可能感兴趣的:(后思小记,mysql,java,spring,数据库,后端)