您的描述将导致如下表定义:
CREATE TABLE tbl (
lap_id serial PRIMARY KEY
, lap_no int NOT NULL
, car_type enum NOT NULL
, race_id int NOT NULL -- REFERENCES ...
, UNIQUE(race_id, car_type, lap_no)
);
此类问题的一般解决方案
要获得最长的序列(1个结果,最长的序列,如果有联系,则任意选择):
SELECT race_id, car_type, count(*) AS seq_len
FROM (
SELECT *, count(*) FILTER (WHERE step)
OVER (ORDER BY race_id, car_type, lap_no) AS grp
FROM (
SELECT *, (lag(lap_no) OVER (PARTITION BY race_id, car_type ORDER BY lap_no) + 1)
IS DISTINCT FROM lap_no AS step
FROM tbl
) x
) y
GROUP BY race_id, car_type, grp
ORDER BY seq_len DESC
LIMIT 1;
count(*) FILTER (WHERE step)
仅计数TRUE
(=移至下一组),这将为每个新组产生一个新数字。
关于SO的相关问题,一个使用plpgsql提供程序解决方案的答案:
如果最重要的要求是性能,则在这种特殊情况下,plpgsql函数通常会更快,因为它可以在一次扫描中计算结果。
连续数字更快
我们可以利用连续 lap_no
定义序列的事实,以获得更简单,更快速的版本:
SELECT race_id, car_type, count(*) AS seq_len
FROM (
SELECT race_id, car_type
, row_number() OVER (PARTITION BY race_id, car_type ORDER BY lap_no) - lap_no AS grp
FROM tbl
) x
GROUP BY race_id, car_type, grp
ORDER BY seq_len DESC
LIMIT 1;
连续的圈数相同grp
。每错过一圈,grp
每个分区的成绩都会降低。
这取决于(race_id, car_type, lap_no)
存在UNIQUE NOT NULL
。NULL值或重复项可能会破坏逻辑。
讨论Jack更简单的选择
@杰克的版本有效计算所有的圈(行)在先前lap_no
在此race_id
具有相同的car_type
。只要每个序列car_type
只能有一个序列,这将更加简单,快捷和正确race_id
。
但是对于一个简单的任务,查询可能会更简单。从逻辑上讲,每个lap_no
人都(car_type, race_id)
必须按顺序进行,我们可以算一下圈数:
SELECT race_id, car_type, count(*) AS seq_len
FROM tbl
GROUP BY race_id, car_type
ORDER BY seq_len DESC
LIMIT 1;
另一方面,如果每个race_idcar_type
可以有多个单独的序列(并且问题没有另外说明),则杰克的版本将失败。
对于给定的种族/汽车类型,速度更快
在回答问题中的评论/说明时:将查询限制为给定 的查询(race_id, car_type)
将使其更快,当然:
SELECT count(*) AS seq_len
FROM (
SELECT row_number() OVER (ORDER BY lap_no) - lap_no AS grp
FROM tbl
WHERE race_id = 1
AND car_type = 'red'
) x
GROUP BY grp
ORDER BY seq_len DESC
LIMIT 1;
db <> 在这里拨弄
旧的SQL 拨弄
指数
达到最佳性能的关键是合适的索引(所提到的与单个顺序扫描一起使用的过程解决方案除外)。像这样的多列索引最适合:
CREATE INDEX tbl_mult_idx ON tbl (race_id, car_type, lap_no);
如果您的表有UNIQUE
约束我认为在顶部,也就是只有这一点(唯一)的索引内部实现,你也不会需要创建另一个索引。