【问题标题】:selecting consecutive numbers using SQL query使用 SQL 查询选择连续数字
【发布时间】:2010-02-25 14:15:59
【问题描述】:

这是一个剧院座位预订计划。

Seat No Status
1 Booked
2 Available
3 Available
4 Available
5 Available
6 Available
7 Booked
8 Available
9 Available
10 Available

如果有人要预订6张票,他将获得2号至6号座位和8号座位 如果有人只想预订5张票,他将获得2号到6号座位

我如何使用 SQL 查询(或 PHP 代码)知道相邻的可用座位是否多于请求的座位?

按顺序选择座位是我需要实现的主要目标。

【问题讨论】:

  • 一次最多允许 80 个座位
  • 如果有人要求 3 个席位,您是给他们 8-10 个席位(为想要更大序列的人保留 2-6 个席位),还是给他们任意三个连续席位?
  • 我想给 3 个座位,从 2 到 6。顾客更喜欢前排,座位是按“先到先得”的原则分配的。
  • 在这种情况下,预订可能会被取消,状态变为“可用”。

标签: php mysql


【解决方案1】:

试试这个:

select seat, status
from seats
where seat >= (
   select a.seat
   from seats a
      left join seats b on 
         a.seat < b.seat and
         b.seat < a.seat + 4 and
         b.status = 'Available'
   where a.status = 'Available'
   group by a.seat
   having count(b.seat)+1 = 4
   )
limit 4

这设置为选择四个连续的席位。将“4”的所有实例调整为所需的座位数以获得您想要的。

【讨论】:

  • ERROR 1242 (21000): 子查询返回超过 1 行但子查询运行良好,这就是我要找的。谢谢。
【解决方案2】:

最好将 Booked/Available 表示为二进制数(例如 1-free,0-booked)。如果这样做,您可以优雅地使用聚合函数:

  select seat as n from seats where
      $num_seats = (select sum(status) from seats
         where seat between n and n + $num_seats - 1)

【讨论】:

    【解决方案3】:

    一次通过。用你的号码代替?。在满足您的要求时为您提供第一个序列中的座位号,如果未找到序列,则为您提供NULL

    SET @FOUND = 0;
    SET @SEAT_MATCHED = NULL;
    
    SELECT
        IF(@FOUND < ?,
            @FOUND := IF(status == 'Booked', 0, @FROM + 1),
            @SEAT_MATCHED := IFNULL(@SEAT_MATCHED, seat_no)
        )
    FROM seats
    ORDER BY seat_no
    
    SELECT @SEAT_MATCHED;
    

    更多阅读:Control Flow FunctionsUser Variables

    注意!这种方法仅适用于分析区间内记录很少的情况!

    更新。也许您可以将行中预订座位的位掩码存储为整数。例如,对于 16 座排,数字 36884(二进制中的 1001000000010100)表示第 3、5、13 和 16 个座位已预订。它会减少 MySQL 的负载。然后你可以这样写代码:

    <?php
    
    header('Content-Type: text/plain');
    
    // data you get from DB
    $seats = bindec('1001000000010100');
    $num_seats = 16;
    
    // calculate consecutive free seats
    $seats_info = array();
    for ($i = 0; $i < $num_seats; $i++, $seats >>= 1) {
        if ($seats & 1) {
            if (isset($first)) {
                $seats_info[$first] = $i - $first;
                unset($first);
            }
        }
        else {
            if (!isset($first)) {
                $first = $i;
            }
        }
    }
    
    // output sequences
    var_export($seats_info);
    
    ?>
    

    这个输出:

    array (
      0 => 2,
      3 => 1,
      5 => 7,
      13 => 2,
    )
    

    0第一个席位。

    【讨论】:

    • 换句话说,如果座位不相邻,它不会给你任何回报?就像如果要求 6 个座位,但组中只有 5 个,最后一个可以从下一个组中取出,你仍然会得到 NULL?
    • 是的。但这比山塔诺问的要多。如果您愿意,也可以稍微修改此查询以满足您的要求。
    【解决方案4】:
    SELECT a.seat_no     SEAT1,
           a.seat_no + 1 SEAT2,
           a.seat_no + 2 SEAT3  
      FROM theater a
     WHERE a.availability = 'Y'
       AND seat_no + 1 = (SELECT b.seat_no 
                            FROM theater b 
                           WHERE b.seat_no = a.seat_no + 1 
                             and b.availability = 'Y')
       AND seat_no + 2 = (SELECT b.seat_no 
                            FROM theater b 
                           WHERE b.seat_no = a.seat_no + 2 
                             and b.availability = 'Y');
    

    【讨论】:

      【解决方案5】:
      select distinct S2.seat
      from (
         select a.seat
         from seats a
            left join seats b on 
               a.seat <= b.seat and
               a.seat + 3 >= b.seat and
               a.availability = 1 and b.availability = 1
         group by a.seat
         having count(b.seat) = 4
         ) as S1
         join 
         seats as S2
         on 
         S1.seat <= S2.seat and S1.seat+3 >= S2.seat
      order by S2.seat_no
      limit 4;
      

      【讨论】:

        【解决方案6】:

        我建议使用 SQL 和 PHP 的一种递归算法。你需要 X 个座位。

        1. 使用 SQL 查询选择所有可用席位,您会收到 N 个可用席位(如果 N

        2. 在 php 中分析结果并使用相邻座位组大小作为键存储它们(可能有多个相同大小的组)

          '5' => (2, 3, 4, 5, 6)

          '2' => ( 8, 9 )

        3. 尝试找到有 X 个座位的组

        4. 如果未找到,请选择大小 > X 的最近组(对于 X = 4,它是组 '5')

        5. 如果没有找到更大的组,取出最大的可用组(大小为 Y 的组),然后重复步骤 3 - 5,X = X - Y

        【讨论】:

          【解决方案7】:

          编辑:因为我误解了这里的问题,所以一个 SQL 语句将返回所有 第一个空闲座位和相邻座位的计数。更多的免费座位排在第一位。

          SELECT count(1) free,(
           CASE status
            WHEN "Booked" THEN
             @prev:=NULL
            ELSE
             @prev:=COALESCE(cast(@prev as unsigned), seat_no)
            END) first
          FROM 
           (SELECT @prev:=null) f,
           (SELECT seat_no, status FROM seats ORDER BY seat_no) seats
          GROUP BY first
          HAVING first>=0
          ORDER BY 1 DESC, 2
          

          因此对于您的示例,它将返回:

          free | first
          -----------
             5    2
             3    8
          

          如果您只对符合您要求的第一个顺序座位感兴趣,而不再只对免费座位数添加条件,那么如果您想要 3 个座位添加free&gt;=3 就可以了:

          SELECT count(1) free,(
           CASE status
            WHEN "Booked" THEN
             @prev:=NULL
            ELSE
             @prev:=COALESCE(cast(@prev as unsigned), seat_no)
            END) first
          FROM 
           (SELECT @prev:=null) f,
           (SELECT seat_no, status FROM seats ORDER BY seat_no) seats
          GROUP BY first
          HAVING first>0 AND free>=3
          LIMIT 1
          

          这将输出:

          free | first
          ------------
             5    2
          

          【讨论】:

          • 嗯,这将提供第一个可用座位,而不仅仅是相邻的座位。例如 0101010111 并且我要求 3 个座位,您的选择会给我分开的座位,我实际上想要最后 3 个彼此相邻的座位
          • 是的,我知道,在他的示例中,如果它要求 6 个座位,它也会选择第 8 个座位,因为第 7 个座位已被预订,所以这回答了他不想要的?
          • 你的结果符合他的要求只是因为他的例子是这样设置的。如果他有以下布局作为他的示例:0101010111111110 您的选择将与他想要的不匹配,这将是最后 8 个座位
          • 他的问题中没有具体说明我怎么能猜出他想要什么?如果您只有 1/2 的空闲座位,那么预期的结果是什么?规则是什么?
          • “按顺序选择座位是我需要实现的主要目标。”
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-04-18
          • 2010-10-31
          • 2021-01-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多