给定沙发床中的一组文档,其中每个文档都有一个整数值,该整数值最初是按顺序分配的,但随后无序释放,找到序列中编号最小的“孔”
例如,对于具有以下值的文档:
1
3
4
6
查询应返回0 这些值:
0
1
3
4
6
查询应返回2 这些值:
0
1
2
查询应返回3
答案 0 :(得分:1)
以升序创建序列号数组。
SELECT RAW d.id FROM default AS d WHERE d.id >= 0 ORDER BY d.id ASC
您可以使用上面的查询返回数组。然后使用ARRAY_APPEND()在末尾附加-1,以便我们可以处理是否没有孔。 当pos与使用FIRST集合表达式的位置上的值不匹配时,返回数组的位置。
最终查询:
SELECT FIRST pos FOR pos:v IN av WHEN pos != av[pos] END AS hole
LET av = ARRAY_APPEND((SELECT RAW d.id FROM default AS d WHERE d.id >= 0 ORDER BY d.id ASC ), -1);
SELECT FIRST pos FOR pos:v IN av WHEN pos != av[pos] END AS hole LET av = ARRAY_APPEND([1,3,4,6], -1);
SELECT FIRST pos FOR pos:v IN av WHEN pos != av[pos] END AS hole LET av = ARRAY_APPEND([0,1,3,4,6], -1);
SELECT FIRST pos FOR pos:v IN av WHEN pos != av[pos] END AS hole LET av = ARRAY_APPEND([0,1,2], -1);
如果结果集很大,则可以使用应用程序和N1QL进行批量处理以消耗更少的资源并使其变得更快,如下所示(使用索引顺序避免排序)
CREATE INDEX ix1 ON default(id);
startpos = 0
endpos = 1000
pos=startpos
WHILE
do
id = SELECT FIRST pos FOR pos:v IN av WHEN pos != av[pos] END AS hole
LET av = ARRAY_APPEND((SELECT RAW d.id
FROM default AS d USE INDEX (ix1)
WHERE d.id BETWEEN $startpos AND $endpos
ORDER BY d.id ASC), -1);
if id <= $endpos
pos = startpos+id
break
else
startpos = endpos+1
endpos = endpos+1000
fi
done
pos will have final hole
在下一个版本的Sofabase中,您可以使用窗口功能
CREATE INDEX ix1 ON default(id);
SELECT RAW d.rn-1 AS pos
FROM (select ROW_NUMBER() OVER() AS rn, t.id as id
from default AS t USE INDEX (ix1)
WHERE t.id >= 0
) AS d
WHERE (d.rn-1) != d.id
LIMIT 1;