如何颠倒Postgres中SETOF的顺序?

时间:2017-06-01 10:32:47

标签: sql postgresql recursive-query

我有一个复杂的PSQL函数返回表记录的SETOF(树中叶子记录的祖先路径,yikes),通常一次只有几个记录 - 祖先 - 这适合于完美的应用程序的其余部分。

例如,给定记录:

id: 5, parent_id: null
id: 1, parent_id: 5
id: 3, parent_id: 1

该函数应该被调用为get_ancestry(3)我希望它按照这个确切的顺序返回包含SETOF的{​​{1}}条记录 - 而且顺序很明显很重要。

然而,有一个一个小小的重要位置我需要以完全相反的顺序迭代3, 1, 5的记录,在之前的例子中,预期的结果将是是SETOF

或者换句话说给定一个返回SETOF的函数,如何编写一个以相反的顺序返回相同SETOF的函数?

  • 没有5, 1, 3我可以帮助自己 - 我可以轻松地计算它,但是如何将它添加到属于表的记录对象?
  • 我想过将ORDER BY转换成数组然后反转数组,但没有发现任何谷歌搜索 - 不是关于反转数组,也不是将SETOF转换为数组
  • 我想添加SETOF属性,如果记录是顶级的,则等于0,记录'孩子会有level等,但是为超级忙添加另一列必须以某种方式更好地工作的这一个查询的不断更新的表似乎是错误的
  • 重写复杂的函数,以完全相同的方式完成相当棘手的逻辑,但递归不同的路径看起来像维护/错误修复噩梦

怎么办?

2 个答案:

答案 0 :(得分:1)

  

我想添加一个关卡属性

您不必将其添加到表中,您可以在查询中动态计算。

这样的事情:

with recursive tree (id, parent_id, level) as (
  select id, parent_id, 1 as level
  from the_table
  where parent_id is null
  union all
  select c.id, c.parent_id, p.level + 1
  from the_table c
    join data p on p.id = c.parent_id
)
select *
from tree;

如果要将树从树叶移动到父级,则需要更改递归查询:

with recursive tree (id, parent_id, level) as (
  select id, parent_id, 1 as level
  from the_table
  where id = 42
  union all
  select x.id, x.parent_id, p.level + 1
  from the_table x
    join data p on x.id = p.parent_id
)
select *
from tree;

请注意,在这种情况下,级别列的“含义”是相反的。它基本上定义了每一行与起点的距离。它不是整个层次结构中的整体级别。

以上内容可以放入函数中:

create function get_tree(p_start_with integer) 
   returns table(id integer, parent_id integer, level integer)
as
$$
  ... the query from above using the p_start_with parameter
$$
language sql;

然后你可以使用

select *
from get_tree(42)
order by level desc;

如果对您来说很重要,您还应该添加另一列来定义同一级别的子级顺序。或者只使用order by level desc, id desc之类的内容来获得同一级别所有元素的一致顺序。

答案 1 :(得分:0)

要反转返回的订单,您可以执行子查询并按原始行号排序。重要的是要强调row_number()over()正在使用行"因为它们来了"所以你的get_ancestry()函数必须控制这个顺序,否则你会冒不一致的结果。

select * from 
 (select  a.*, 
          row_number() over() as sortID
 from get_ancestry(3) a) b
order by sortID desc;