sql :获取连续的组 'n' 行(可能介于两者之间)

sql : get consecutive group 'n' rows (could be inbetween)

下面是我的影院table:

create table theater
(
   srno integer, 
   seatno integer, 
   available boolean
);

insert into theater
values
(1, 100,true),
(2, 200,true),
(3, 300,true),
(4, 400,false),
(5, 500,true),
(6, 600,true),
(7, 700,true),
(8, 800,true);

我想要一个 sql,它应该将输入作为 'n' 和 returns 我第一个 'n' 个连续可用的座位,比如

注意:我正在尝试为 postgres 9.3 构建查询

SQL-Server中,您可以按以下方式进行:

DECLARE @num INT = 4

;WITH cte AS
(
SELECT *,COUNT(1) OVER(PARTITION BY cnt) pt  FROM
(
    SELECT tt.*
        ,(SELECT COUNT(srno) FROM theater t WHERE available <> 'true' and srno < tt.srno) AS cnt
    FROM  theater tt
    WHERE available = 'true'
) t1
)
SELECT TOP (SELECT @num) srno, seatno, available
FROM cte
WHERE pt >= @num

输出

srno    seatno  available
5       500 true
6       600 true
7       700 true
8       800 true

这将找到可用的座位。为 sqlserver 2008+ 编写:

DECLARE @num INT = 4

;WITH CTE as
(
  SELECT 
    srno-row_number() over (partition by available order by srno) grp, 
    srno, seatno, available
  FROM theater
), CTE2 as
(
  SELECT grp, count(*) over (partition by grp) cnt,
    srno, seatno, available 
  FROM CTE
    WHERE available = 'true'

)
SELECT top(@num)
  srno, seatno, available
FROM CTE2
WHERE cnt >= @num
ORDER BY srno

结果:

srno  seatno  available
5     500     1
6     600     1
7     700     1
8     800     1

谢谢大家,但我已经做到了,如下所示,

select srno, seatno from (
select *, count(0) over (order by grp) grp1 from (
  select t1.*,  
          sum(group_flag) over (order by srno) as grp
  from (
      select *,
             case
                when lag(available) over (order by srno) = available then null
                else 1
              end as group_flag
      from theater
  ) t1 ) tx ) tr where tr.available=true and tr.grp1 >= 2 limit 2 
        -- naive solution without window using functions
        -- [the funny +-100 constants are caused by
        -- "consecutive" seats being 100 apart]
        -- -------------------------------------------
WITH    bot AS ( -- start of an island --
        SELECT seatno FROM theater t
        WHERE  t.available
        AND NOT EXISTS (select * from theater x
                where x.available AND x.seatno = t.seatno -100)
        )
,       top AS ( -- end of an island --
        SELECT seatno FROM theater t
        WHERE t.available
        AND NOT EXISTS (select * from theater x
                where x.available AND x.seatno = t.seatno +100)
        )
,       mid AS ( -- [start,end] without intervening gaps --
        SELECT l.seatno AS bot, h.seatno AS top
        FROM bot l
        JOIN top h ON h.seatno >= l.seatno
                AND NOT EXISTS (
                SELECT * FROM theater x
                WHERE NOT x.available
                AND x.seatno >= l.seatno AND x.seatno <= h.seatno)
        )
        -- all the consecutive ranges
        -- [ the end query should select from this
        -- , using "cnt >= xxx" ]
SELECT bot, top
        , 1+(top-bot)/100 AS cnt
FROM mid;

结果:

 bot | top | cnt 
-----+-----+-----
 100 | 300 |   3
 500 | 800 |   4
(2 rows)