假设我有两个表:
create table parents (id integer, name varchar, child_count integer);
create table children (id integer, name varchar, parent_id integer);
假设父母:孩子的比例约为1:1000。
假设child_count
定期更新(或通过PostgreSQL中的物化视图提供),例如使用此更新语句:
update parents p set child_count = pc.count
from (select p.id id, count(c.*) count
from parents p join children c on p.id = c.parent_id
group by p.id) as pc
where p.id = pc.id;
我希望在所有孩子中找到第n个孩子,其中孩子首先按父母姓名排序,然后按孩子名称排序。基本上,我想要这个查询:
select c.*
from children c join parents p on p.id = c.parent_id
order by p.name, c.name
limit 42 offset 42;
...除了这是一个昂贵的查询需要扫描孩子,但我知道使用child_count字段可以更便宜地完成 - 冒着可能过时的风险,但我并不担心这一点。
有没有办法编写一个查询(最好是postgresql),使用父亲的child_count来选择所有父母的第n个孩子?
或者有更好的方法来构建数据吗?我会考虑使用范围(无论是postgresql本机还是使用两个单独的列),除非它们似乎很难更新。我可能想要使用不同的排序顺序选择第n个孩子(但总是使用父母,然后是孩子进行排序)。
我目前最好的想法是将所有父项缓存在内存中,并在我自己发现正确的父项后使用限制/偏移查询,但也可能有相当多的父母。
答案 0 :(得分:2)
似乎row_number
window function(以及this和this也可能正是您所需要的):
SELECT x.*
FROM ( SELECT p.id AS parent_id,
p.name AS parent_name,
c.id AS child_id,
c.name AS child_name,
row_number() OVER ( ORDER BY p.name, c.name ) AS ordinal
FROM children c
JOIN parents p ON c.parent_id = p.id
) AS x
WHERE x.ordinal = 42
ORDER BY p.name, c.name;
事实上,通过上述查询,您甚至不需要保留child_count
列(您可能因其他原因而想要这样做)。