
点击上方【蓝字】关注我们
场景描述
影院座位预定表 T_SEATS 记录了当前座位的预定情况。如有2个人去影院看演唱会,需满足位置紧邻且至少其中一人靠过道(同一排最左或最右的座位靠过道)的座位组合,结果集按开始座位号从小到大排序。座位示意图如下:

CREATE TABLE `t_seats` (`id` int unsigned NOT NULL AUTO_INCREMENT,`row_no` int DEFAULT NULL COMMENT '第几排',`seat` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '座位',`status` int NOT NULL COMMENT '预定状态 0-未预定 1-已预定',PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8
查询结果集,字段顺序及命名如下:开始座位号、结束座位号

数据准备
create table t_seat as (select stack(20,1, 1, 16, 0,2, 1, 17, 0,3, 1, 18, 1,4, 1, 19, 0,5, 1, 20, 1,6, 2, 11, 1,7, 2, 12, 0,8, 2, 13, 0,9, 2, 14, 1,10, 2, 15, 0,11, 3, 8, 0,12, 3, 9, 1,13, 3, 10, 0,14, 4, 5, 0,15, 4, 6, 0,16, 4, 7, 1,17, 5, 3, 0,18, 5, 4, 0,19, 6, 1, 1,20, 6, 2, 0) as (id, row_num, seat, status));
问题分析
方法1:利用lag()及lead()分析函数求解
第一步:利用lag()及lead()函数求出左边座位、右边座位,及左边座位状态、右边座位状态,进行辅助判断。
select id, row_num, seat, status, lag(seat) over (partition by row_num order by seat) lag_seat, lead(seat) over (partition by row_num order by seat) lead_seat, lag(status, 1, status) over (partition by row_num order by seat) lag_status, lead(status, 1, status) over (partition by row_num order by seat) lead_statusfrom t_seat

紧邻判断:即当前seat值 +1 = lead_seat即可 状态判断:无论获取的lag_seat还是lead_seat都必须是未被预定的,即(lag_status + lead_status) = 0
casewhen (lag_seat + lead_seat) is null and (lag_status + lead_status) = 0 and seat + 1 = lead_seatthen 1 end flg
完整的SQL如下:
select row_num, seat, lead_seatfrom (select id, row_num, seat, lag_seat, lead_seat, casewhen (lag_seat + lead_seat) is null and (lag_status + lead_status) = 0 and seat + 1 = lead_seatthen 1 end flgfrom (select id, row_num, seat, status, lag(seat) over (partition by row_num order by seat) lag_seat, lead(seat) over (partition by row_num order by seat) lead_seat, lag(status, 1, status) over (partition by row_num order by seat) lag_status, lead(status, 1, status) over (partition by row_num order by seat) lead_statusfrom t_seat) twhere status = 0) twhere flg = 1;
SQL可简化为:
select row_num, seat, lead_seatfrom (selectrow_num, seat, status, lag(seat) over (partition by row_num order by seat) lag_seat, lead(seat) over (partition by row_num order by seat) lead_seat, lag(status, 1, status) over (partition by row_num order by seat) lag_status, lead(status, 1, status) over (partition by row_num order by seat) lead_statusfrom t_seat) twherecase when (lag_seat + lead_seat) is null and (lag_status + lead_status) = 0 and seat + 1 = lead_seat then 1 end = 1

方法2:转换成字符串序列进行分析
range between current row and 1 following
select row_num, seat, collect_list(seat)over (partition by row_num order by seat range between current row and 1 following) seat_listfrom t_seatwhere status = 0

第二步:计算同一排座位中的最大最小 值,依此来判断是否靠近过道
select row_num, min(seat) min_seat, max(seat) max_seatfrom t_seatgroup by row_num

array_contains(seat_list, min_seat) or array_contains(seat_list, max_seat) 为true
完整的SQL如下:
select t.row_num, seat_list[0] start_num, seat_list[1] end_numfrom (select row_num, seat, collect_list(seat)over (partition by row_num order by seat range between current row and 1 following) seat_listfrom t_seatwhere status = 0) tleft join (select row_num, min(seat) min_seat, max(seat) max_seatfrom t_seatgroup by row_num) t2on t.row_num = t2.row_numwhere size(seat_list) = 2and (array_contains(seat_list, min_seat) or array_contains(seat_list, max_seat))

方法3:自关联求解
具体SQL如下:
select a.row_num, start_num, end_numfrom (SELECT a.row_num row_num, a.seat start_num, b.seat end_numFROM t_seat a,t_seat bwhere a.row_num = b.row_numand a.seat + 1 = b.seatand a.status = 0and b.status = 0) aleft join(select row_num, min(seat) min_seat, max(seat) max_seatfrom t_seatgroup by row_num) bon a.row_num = b.row_numwhere greatest(start_num, end_num) = max_seator least(start_num, end_num) = min_seat

小结

猜你喜欢



公众号:会飞一十六
扫码关注 了解更多内容
点个 在看 你最好看
文章转载自会飞的一十六,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。








