我正在尝试在 PostgreSQL 9.0 中构建一个查询,以获取特定列的最长连续行序列。
考虑下表:
lap_id (serial), lap_no (int), car_type (enum), race_id (int FK)
每个地方lap_no
都是独一无二的(race_id, car_type)
。
我希望查询为给定的race_id
and生成最长的序列car_type
,因此它将返回一个int
最高的(或长的)。
使用以下数据:
1, 1, red, 1
2, 2, red, 1
3, 3, red, 1
4, 4, red, 1
5, 1, blue, 1
6, 5, red, 1
7, 2, blue, 1
8, 1, green, 1
因为car_type = red and race_id = 1
查询将5
作为lap_no
字段的最长序列返回。
我在这里发现了一个类似的问题,但是我的情况更简单一些。
(我也想知道car_type
所有种族的最长序列,但我打算自己解决这个问题。)
您的描述会产生如下表定义:
此类问题的通用解决方案
要获得最长的序列(1 个结果,最长的,如果有关系则任意选择):
count(*) FILTER (WHERE step)
只计算TRUE
(= 到下一组),这会为每个新组生成一个新数字。与 plpgsql相关的程序解决方案:
如果最高要求是性能,则plpgsql 函数在这种特殊情况下通常更快,因为它可以在一次扫描中计算结果。
连续数字更快
我们可以利用连续
lap_no
定义序列的事实,以获得更简单和更快的版本:连续的圈数以相同的方式结束
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
per(car_type, race_id)
必须是in sequence,我们可以只计算圈数:另一方面,如果每个race_id
car_type
可以有多个单独的序列(并且问题没有另外指定),那么 Jack 的版本将失败。对于给定的比赛/汽车类型更快
回复问题中的评论/澄清:将查询限制为给定
(race_id, car_type)
的查询将使其更快,当然:db<>fiddle here
旧SQL Fiddle
指数
最佳性能的关键是合适的索引(除了提到的使用单个顺序扫描的程序解决方案)。像这样的多列索引效果最好:
如果您的表具有
UNIQUE
我在顶部假设的约束,则在内部仅使用此(唯一)索引实现,并且您不需要创建另一个索引。