Postgresql 仅返回数组包含元素的第一行,可能会忽略前面看到的任何元素
给定以下数据集:Postgresql 仅返回数组包含元素的第一行,可能会忽略前面看到的任何元素,postgresql,Postgresql,给定以下数据集: | page | sentence_ids | |------|--------------| | 1 | { 1, 2, 3 } | | 2 | { 1, 2 } | | 3 | { 3, 4 } | 我想做一个查询,返回句子id最先出现的页面。最好是句子ID在数据集中只出现一次,并且页数最少。在这种情况下: | page | sentence_ids | |------|--------------| | 1 | { 1, 2,
| page | sentence_ids |
|------|--------------|
| 1 | { 1, 2, 3 } |
| 2 | { 1, 2 } |
| 3 | { 3, 4 } |
我想做一个查询,返回句子id最先出现的页面。最好是句子ID在数据集中只出现一次,并且页数最少。在这种情况下:
| page | sentence_ids |
|------|--------------|
| 1 | { 1, 2, 3 } |
| 3 | { 4 } |
这可能吗?这种关系是非规范化的,因为页面可以以10000结尾,句子可以以100000结尾
现在我们加载包含所有句子的所有页面,并在代码中进行筛选。效率极低。希望有人能帮上忙。唯一实用的方法*是首先
取消语句ID的数组,然后选择页面、句子
的组合,使后者与最低页面相匹配;您可以通过一个窗口函数对句子进行分区,并在按页面排序后找到一个秩来实现这一点。rank=1的记录是兴趣的组合。然后将结果聚合回数组:
SELECT page, array_agg(sentence)
FROM (
SELECT page, sentence, rank() OVER (PARTITION BY sentence ORDER BY page) AS rnk
FROM (
SELECT page, unnest(sentence_ids) AS sentence
FROM page_sentences) p_s
) p_s_r
WHERE rnk = 1
GROUP BY page;
考虑到数据的大小,这可能不是一个很快的解决方案,但它很可能比提取所有数据然后在代码中过滤要好
- “实用”在这里被松散地定义为“任何避免遵循克雷格建议的东西”。(对不起,克雷格…)
因此,您需要一个自定义窗口函数,该函数将集合中的所有可见元素累加起来,然后在每一行上只发出新元素,如果没有唯一元素,则在空数组中发出null/值。然后在FROM
中将该调用包装为子查询,其中外部查询过滤掉没有新句子的行。自定义窗口功能是最难的一点;我认为此时您唯一的选择是用C编写。如果您愿意稍微滥用API,您可以用PL/Python、PL/Perl等编写一个普通的非窗口函数,声明它VOLATILE
,并将设置的数据隐藏在解释器命名空间中的某个地方,在调用之间可以访问该数据。这很有意思,但这(或C级的等价物)是人们在有窗口功能之前经常做的事情。太棒了!p_s和p_s_r代表什么?FROM
子句中的子查询需要别名,即使它从未用于引用列。p_s仅仅代表(页面、句子)组合,p_s_r加上排名。