暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

SQL进阶技巧:火车票相邻座位预定一起可能情况查询算法 ?

会飞的一十六 2024-09-29
229




01


场景描述



假设是 3 个朋友一起坐高铁出去玩,希望能预定到相邻的座位。现在这趟车某个车厢里每排的座位的编号是 A、B、C、D、F,其中,A 和 F 是靠窗位置,C 和 D 之间是过道。即使隔着过道,C 和 D 仍是可以看作是相邻的座位。求三个人能预定到一起的座位情况?


seats 是座位预定表,表结构如下:


    CREATE TABLE `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

    其中,id 是主键,从 1 起连续递增。

    seats 表的数据:

       
      id row_no seat status

      1 1 A 1
      2 1 B 1
      3 1 C 0
      4 1 D 0
      5 1 F 0
      6 2 A 1
      7 2 B 0
      8 2 C 0
      9 2 D 0
      10 2 F 0
      11 3 A 0
      12 3 B 1
      13 3 C 1
      14 3 D 0
      15 3 F 0




      02


      数据准备


        create table seat as (select stack(
        15,
        1, 1, 'A', 1,
        2, 1, 'B', 1,
        3, 1, 'C', 0,
        4, 1, 'D', 0,
        5, 1, 'F', 0,
        6, 2, 'A', 1,
        7, 2, 'B', 0,
        8, 2, 'C', 0,
        9, 2, 'D', 0,
        10, 2, 'F', 0,
        11, 3, 'A', 0,
        12, 3, 'B', 1,
        13, 3, 'C', 1,
        14, 3, 'D', 0,
        15, 3, 'F', 0
        ) as (id, row_num, seat, status))
        ;



        03


        问题分析

        方法1: 利用分析函数求解

         第一步:获取相邻3个座位的各种组合情况

        (1)过滤掉已预定的座位

        (2)利用自增id进行相邻判断

        (3)找出连续相邻的三个座位并组合一起

              注意此处必须座位编号是连续的,为了找出连续的3个座位我们使用了窗口子句,此时窗口的范围应该使用range子句而不是rows,利用range进行逻辑上的计算来判断是否连续。

          select id
          , row_num
          , seat
          , status
          , collect_list(seat) over (partition by row_num order by id range between current row and 2 following) seat_str
          from seat
          where status != 1


          第二步:找出数组长度为3的组合,即为最终结果

          最终SQL如下:

            select row_num
            , concat_ws(',', seat_str) seat_str
            from (select id
            , row_num
            , seat
            , status
            , collect_list(seat)
            over (partition by row_num order by id range between current row and 2 following) seat_str
            from seat
            where status != 1) t
            where size(seat_str) = 3
            ;


            方法2:自关联求解

            步骤1:获取同一排中所有相邻的三个座位

              SELECT a.row_num row_num
              , a.seat
              , b.seat
              FROM seat a,
              seat b
              where a.row_num = b.row_num
              and a.id + 2 = b.id
              and a.status = 0
              and b.status = 0


              步骤2:将相邻的座位组合

                select row_num,
                concat_ws('~', a_seat, b_seat) seat_str
                from (SELECT a.row_num row_num
                , a.seat a_seat
                , b.seat b_seat
                FROM seat a,
                seat b
                where a.row_num = b.row_num
                and a.id + 2 = b.id
                and a.status = 0
                and b.status = 0) t

                04


                小结

                本文给出了一种火车票相邻座位预定一起可能情况查询算法 ,采用了两种思路进行求解,一种利用分析函数,采用窗口子句range进行逻辑计算相邻情况,一种利用自关联的形式,控制关联条件进行求解。


                往期推荐

                SQL进阶技巧:如何利用if语句简化where或join中的条件

                SQL进阶技巧:用户不同 WiFi 行为区间划分分析 | 断点分组问题

                SQL进阶技巧:如何实现多指标累计去重?

                SQL进阶技巧:截止当前批次前的批次量与订单量 | 移动窗口问题

                SQL进阶的技巧:如何实现某列的累计乘积?

                SQL进阶技巧:如何获取数组中前N个元素?


                文章转载自会飞的一十六,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                评论