我有一个数据集,其中包含已找到的某些序列。
序列可以是数组:
{1288,122,1288,127}
{286,286,260,260}
或者只是包含user,id,site_id的行
A | 252 | 1288
A | 253 | 122
A | 254 | 1288
A | 255 | 127
我试图根据site_id-s的模式找到,如果数组或行的方式是圆形的。
所以第一个例子是A-B-A-C。第二个不是站点是A-A-B-B。这里的诀窍是序列之间可能有多个站点,我甚至还没有为简单的A-B-A找到解决方案
我试过找一些材料,但是一切都是指字符串模式匹配或者数组中所有其他类型的循环查找,这些都不适合我的问题。
如果该序列中有一个循环,我只希望基本上得到一个真或假。获得骑自行车的网站ID将是一个奖励。
你可以unnest()
数组WITH ORDINALITY
并检查在集合中的两行是否存在具有相同的值但是至少相隔两个的常数。
WITH
cte
AS
(
SELECT *
FROM unnest('{1288,122,1288,127}'::integer[]) WITH ORDINALITY un(v, o)
)
SELECT EXISTS (SELECT *
FROM cte c1
WHERE EXISTS (SELECT *
FROM cte c2
WHERE c2.v = c1.v
AND c2.o > c1.o + 1));
对于基于集合的问题,您需要按列排序。但那时基本上是一样的。如果要排序的列不允许直接在其上实现逻辑,例如因为它是一个字符串,其中+ 1不能正常工作,你可以使用row_number()
来产生合适的序数。
要获得循环中的“终端”数字(可能不止一个),只需删除外部EXISTS
并投影该值。
WITH
cte
AS
(
SELECT *
FROM unnest('{1288,122,1288,127}'::integer[]) WITH ORDINALITY un(v, o)
)
SELECT v
FROM cte c1
WHERE EXISTS (SELECT *
FROM cte c2
WHERE c2.v = c1.v
AND c2.o > c1.o + 1);