
本文介绍一种基于自连接与字符串聚合的sql技巧,用于在座位表中快速定位同一排中指定数量(如2个、3个)连续可用(status=1)的座位起始位置。
本文介绍一种基于自连接与字符串聚合的sql技巧,用于在座位表中快速定位同一排中指定数量(如2个、3个)连续可用(status=1)的座位起始位置。
在构建影院、剧院或会议厅等场景的座位预订系统时,一个核心需求是:支持用户选择 N 个相邻且空闲的座位(例如“我要3个连坐”)。这要求数据库能高效识别出同一排(row 相同)中连续 N 个 status = 1 的座位序列,并返回其起始位置。
直接使用窗口函数(如 ROW_NUMBER())在 MySQL 8.0+ 中虽更直观,但若需兼容低版本(如 MySQL 5.7),推荐以下通用、可移植的解决方案:
✅ 核心思路:以每个可用座位为起点,拼接其后 N−1 个座位的状态序列
通过自连接(INNER JOIN)将每条记录 a 与同一排中 seat >= a.seat 的后续座位 b 关联,再用 GROUP_CONCAT(... ORDER BY b.seat) 构建从 a.seat 开始的连续状态序列。最后用 HAVING 匹配以 N 个 '1' 开头的模式。
? 示例 SQL(查找 3 个连续可用座位)
SET @X = 3;
SELECT
a.row,
a.seat AS start_seat,
GROUP_CONCAT(b.status ORDER BY b.seat) AS status_seq
FROM seats a
INNER JOIN seats b
ON a.row = b.row
AND a.seat <blockquote>
<p>? <strong>说明</strong>: </p>
<ul>
<li>REPEAT('1,', @X - 1) 生成 '1,1,'(当 X=3),再拼接 '1%' → '1,1,1%'; </li>
<li>status_seq LIKE '1,1,1%' 确保前三个状态均为 1,且序列长度 ≥ 3; </li>
<li>结果中每一行的 start_seat 即为一个长度为 3 的连续空闲序列的<strong>起始座位号</strong>(如 A-04 表示 A 排 04、05、06 可用)。</li>
</ul>
</blockquote><h3>⚠️ 注意事项与优化建议</h3>
- 座位编号格式:本方案假设 seat 字段按字典序可正确排序(如 '01'
-
性能提示:对 row 和 seat 建立联合索引可显著提升自连接效率:
CREATE INDEX idx_row_seat ON seats(row, seat);
- 扩展性:如需返回完整座位列表(不止起始位),可在外层查询中 JOIN 原表并限制 b.seat BETWEEN a.seat AND a.seat + @X - 1;
- 边界处理:当前逻辑自动规避跨排情况(因 ON a.row = b.row 强约束),无需额外判断。
✅ 验证效果(X=2 时部分结果)
| row | start_seat | status_seq |
|---|---|---|
| A | 01 | 1,1,0,1,1,1 |
| A | 04 | 1,1,1 |
| A | 05 | 1,1 |
| B | 01 | 1,1,1 |
| B | 02 | 1,1 |
可见:A-05 表示 A 排 05、06 连续可用;B-01 表示 B 排 01、02 连续可用——完全满足业务诉求。
该方法简洁、无依赖高级窗口函数,适用于主流 MySQL 版本,是实现“连座查询”的稳健实践方案。











