SQL进阶技巧:影院2人相邻的座位如何预定?

目录

[0 场景描述](#0 场景描述)

[1 数据准备](#1 数据准备)

[2 问题分析](#2 问题分析)

方法1:利用lag()及lead()分析函数求解

方法2:转换成字符串序列进行分析

方法3:自关联求解

[3 小结](#3 小结)

[如果觉得本文对你有帮助,那么不妨也可以选择去看看我的博客专栏 ,部分内容如下:](#如果觉得本文对你有帮助,那么不妨也可以选择去看看我的博客专栏 ,部分内容如下:)

数字化建设通关指南

[专栏 原价99,现在活动价39.9,十一国庆后将上升至59.9,最后一波需要的赶紧冲,最终按照阶梯式增长,直到恢复原价。](#专栏 原价99,现在活动价39.9,十一国庆后将上升至59.9,最后一波需要的赶紧冲,最终按照阶梯式增长,直到恢复原价。)


0 场景描述

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

sql 复制代码
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

查询结果集,字段顺序及命名如下:开始座位号、结束座位号

1 数据准备

sql 复制代码
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)
							 )
;

2 问题分析

方法1:利用lag()及lead()分析函数求解

第一步:利用lag()及lead()函数求出左边座位、右边座位,及左边座位状态、右边座位状态,进行辅助判断。

sql 复制代码
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_status
from t_seat

第二步:根据题设条件进行判断

过道的判断:同一排最左或最右的座位靠过道。即取lag()或lead()时值为null的,因为最左或最右的

时候,座位取值为NULL,那么判断条件即为其中lag_seat ,lead_seat 任意一个为null即满足条件。即 (lag_seat + lead_seat) is null

紧邻判断:即当前seat值 +1 = lead_seat即可

状态判断:无论获取的lag_seat还是lead_seat都必须是未被预定的,即(lag_status + lead_status) = 0

整体判断条件如下:

sql 复制代码
case
                 when (lag_seat + lead_seat) is null and (lag_status + lead_status) = 0 and seat + 1 = lead_seat
                     then 1 end flg

完整的SQL如下:

sql 复制代码
select row_num
     , seat
     , lead_seat
from (select id
           , row_num
           , seat
           , lag_seat
           , lead_seat
           , case
                 when (lag_seat + lead_seat) is null and (lag_status + lead_status) = 0 and seat + 1 = lead_seat
                     then 1 end flg
      from (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_status
            from t_seat) t
      where status = 0) t
where flg = 1;

SQL可简化为:

sql 复制代码
select row_num
     , seat
     , lead_seat
from (select
            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_status
      from t_seat) t
where
    case when (lag_seat + lead_seat) is null and (lag_status + lead_status) = 0 and seat + 1 = lead_seat then 1 end = 1

方法2:转换成字符串序列进行分析

第一步:利用collect_list()分析函数,将紧邻的空座位合并成数组

注意由于要求紧邻,此处需要用range子句进行逻辑计算

range between current row and 1 following

sql 复制代码
select row_num
           , seat
           , collect_list(seat)
                          over (partition by row_num order by seat range between current row and 1 following) seat_list
      from t_seat
      where status = 0

第二步:计算同一排座位中的最大最小 值,依此来判断是否靠近过道

sql 复制代码
select row_num
                         , min(seat) min_seat
                         , max(seat) max_seat
                    from t_seat
                    group by row_num

第三步:按照row_num 关联 步骤2 的结果,并进行条件判断

(1)两人紧邻:步骤1中结果size(seat_list) = 2

(2) 判断座位号的最大最小值其中任意一个是否在数组seat_list中,存在则满足条件。即

sql 复制代码
array_contains(seat_list, min_seat) or array_contains(seat_list, max_seat) 为true

完整的SQL如下:

sql 复制代码
select t.row_num
     , seat_list[0] start_num
     , seat_list[1] end_num
from (select row_num
           , seat
           , collect_list(seat)
                          over (partition by row_num order by seat range between current row and 1 following) seat_list
      from t_seat
      where status = 0) t
         left join (select row_num
                         , min(seat) min_seat
                         , max(seat) max_seat
                    from t_seat
                    group by row_num) t2
                   on t.row_num = t2.row_num
where size(seat_list) = 2
  and (array_contains(seat_list, min_seat) or array_contains(seat_list, max_seat))

方法3:自关联求解

具体SQL如下:

sql 复制代码
select a.row_num
     , start_num
     , end_num
from (SELECT a.row_num row_num
           , a.seat    start_num
           , b.seat    end_num
      FROM t_seat a,
           t_seat b
      where a.row_num = b.row_num
        and a.seat + 1 = b.seat
        and a.status = 0
        and b.status = 0) a
         left join
     (select row_num
           , min(seat) min_seat
           , max(seat) max_seat
      from t_seat
      group by row_num) b
     on a.row_num = b.row_num
where greatest(start_num, end_num) = max_seat
   or least(start_num, end_num) = min_seat

3 小结

本文使用三种方法给出了 影院2人相邻的座位如何预定问题的方法和技巧,主要使用了lag()/lead()分析函数作为辅助变量参与计算的技巧,序列分析法以及自关联进行行行比较的求解的方法,三种不同方法各有优势和特点,分别代表处理问题的不同思维方式。

与本文相关的文章链接如下;

SQL进阶技巧:火车票相邻座位预定一起可能情况查询算法 ?_购票安排相邻座位sql-CSDN博客

如果觉得本文对你有帮助,那么不妨也可以选择去看看我的博客专栏 ,部分内容如下:
数字化建设通关指南
专栏 原价99,现在活动价39.9,十一国庆后将上升至59.9,最后一波需要的赶紧冲,最终按照阶梯式增长,直到恢复原价。

主要内容:
(1)SQL进阶实战技巧

可以参考如下教程,具体链接如下

SQL很简单,可你却写不好?也许这才是SQL最好的教程

上面链接中的文章及技巧会不定期更新。

(2)数仓建模实战技巧和个人心得

1)新人入职新公司后应如何快速了解业务?

2)以业务视角看宽表化建设?

  1. 维度建模 or 关系型建模?

4)业务模型与数据模型有什么区别?业务阶段的模型该如何建设?

5)业务指标体系该如何建设?指标体系该如何维护?指标平台应如何建设?指标体系 该由谁来搭建?

6)如何优雅设计DWS层?DWS层模型好坏该如何评价?

7)指标发生异常,该如何排查?应从哪些方面入手寻找问题点?

8) 数据架构的选择,mpp or hadoop?

9)数仓团队应如何体现自己的业务价值,讲好数据故事?

10)BI与大数据有什么关系?BI与信息化、数字化之间有什么关系?BI与报表之间的关 系?

11)数据部门如何与业务部门沟通,并规划指引业务需求?

文章不限于以上内容,有新的想法也会及时更新到该专栏。

具体专栏链接如下:

​​​​​​数字化建设通关指南_莫叫石榴姐的博客-CSDN博客

相关推荐
zskj_qcxjqr1 分钟前
七彩喜微高压氧舱:科技与体验的双重革新,重新定义家用氧疗新标杆
大数据·人工智能·科技·机器人
2501_930799242 分钟前
访答知识库#Pdf转word#人工智能#Al编辑器#访答PAG#企业知识库……
人工智能
说私域9 分钟前
基于开源AI智能名片链动2+1模式S2B2C商城小程序的公益课引流策略研究
人工智能·小程序·开源
Elastic 中国社区官方博客10 分钟前
Elasticsearch 的 JVM 基础知识:指标、内存和监控
java·大数据·elasticsearch·搜索引擎·全文检索
组合缺一14 分钟前
搭建基于 Solon AI 的 Streamable MCP 服务并部署至阿里云百炼
java·人工智能·solon·mcp
qinyia16 分钟前
Wisdom SSH 是一款集成了强大 AI 助手功能的 SSH 工具,助你高效管理服务器。
服务器·人工智能·ssh
IT_陈寒20 分钟前
SpringBoot 3.x实战:5种高并发场景下的性能优化秘籍,让你的应用快如闪电!
前端·人工智能·后端
Clownseven24 分钟前
云市场周报 (2025.09.05):解读腾讯云AI安全、阿里数据湖与KubeVela
人工智能·安全·腾讯云
君万26 分钟前
【LeetCode每日一题】94. 二叉树的中序遍历 104. 二叉树的最大深度
算法·leetcode·golang
野豹商业评论27 分钟前
AI 浪潮下阿里云“高光”乍现,但离终局胜利尚远
人工智能·阿里云·云计算