Postgresql 对于每个组,在0处重新启动的类似行数的方法
假设有一个存储如下层次结构的表:Postgresql 对于每个组,在0处重新启动的类似行数的方法,postgresql,Postgresql,假设有一个存储如下层次结构的表: item_id | hierarchical_id --------+----------------- 1 | ;1; 2 | ;1;2; 3 | ;1;2;3; 4 | ;1;2;4; 5 | ;1;2;4;5; parent_id | item_id | hierarchical_id | distance ----------+---------+-----------------+----
item_id | hierarchical_id
--------+-----------------
1 | ;1;
2 | ;1;2;
3 | ;1;2;3;
4 | ;1;2;4;
5 | ;1;2;4;5;
parent_id | item_id | hierarchical_id | distance
----------+---------+-----------------+---------
1 | 1 | ;1; | 0
1 | 2 | ;1;2; | 1
2 | 2 | ;1;2; | 0
1 | 3 | ;1;2;3; | 2
2 | 3 | ;1;2;3; | 1
3 | 3 | ;1;2;3; | 0
1 | 4 | ;1;2;4; | 2
2 | 4 | ;1;2;4; | 1
4 | 4 | ;1;2;4; | 0
1 | 5 | ;1;2;4;5; | 3
2 | 5 | ;1;2;4;5; | 2
4 | 5 | ;1;2;4;5; | 1
5 | 5 | ;1;2;4;5; | 0
这里存储的层次结构是1作为根,2是1的子级,3和4是2的子级,5是4的子级
询问
SELECT
-- the substr is used to remove the first and last semicolumns
regexp_split_to_table(substr(hierarchical_id, 2, length(hierarchical_id) - 2)
, E';'
) as parent_id,
item_id,
hierarchical_id
FROM
table
返回
parent_id | item_id | hierarchical_id
----------+---------+-----------------
1 | 1 | ;1;
1 | 2 | ;1;2;
2 | 2 | ;1;2;
1 | 3 | ;1;2;3;
3 | 3 | ;1;2;3;
1 | 4 | ;1;2;3;
2 | 4 | ;1;2;4;
4 | 4 | ;1;2;4;
1 | 5 | ;1;2;4;5;
2 | 5 | ;1;2;4;5;
4 | 5 | ;1;2;4;5;
5 | 5 | ;1;2;4;5;
如何修改查询以获得如下第四列:
item_id | hierarchical_id
--------+-----------------
1 | ;1;
2 | ;1;2;
3 | ;1;2;3;
4 | ;1;2;4;
5 | ;1;2;4;5;
parent_id | item_id | hierarchical_id | distance
----------+---------+-----------------+---------
1 | 1 | ;1; | 0
1 | 2 | ;1;2; | 1
2 | 2 | ;1;2; | 0
1 | 3 | ;1;2;3; | 2
2 | 3 | ;1;2;3; | 1
3 | 3 | ;1;2;3; | 0
1 | 4 | ;1;2;4; | 2
2 | 4 | ;1;2;4; | 1
4 | 4 | ;1;2;4; | 0
1 | 5 | ;1;2;4;5; | 3
2 | 5 | ;1;2;4;5; | 2
4 | 5 | ;1;2;4;5; | 1
5 | 5 | ;1;2;4;5; | 0
distance
的含义是当前行上的项id
和父项id之间的距离。例如:节点与其自身之间的距离为0,节点与其父节点之间的距离为1,节点与其父节点之间的距离为2,等等。它不必从0开始
row\u number
如果我能让它在0处为每组相等的item\u id
s重新启动,就可以了,因为hierarchical\u id
中的id是有序的
有什么建议吗?窗口功能给你很多控制;看 您需要的关键是:
row_number() OVER (PARTITON BY item_id ORDER BY hierarchical_id)
给定数据:
create table t ( item_id integer, hierarchical_id text );
insert into t (item_id, hierarchical_id) values
(1,';1;'),
(2,';1;2;'),
(3,';1;2;3;'),
(4,';1;2;4;'),
(5,';1;2;4;5;');
查询:
WITH x AS (
SELECT regexp_split_to_table(substr(hierarchical_id, 2, length(hierarchical_id) - 2), E';') as parent_id,
item_id,
hierarchical_id
FROM t
)
SELECT
*,
row_number() OVER (PARTITION BY item_id ORDER BY parent_id DESC) - 1 AS distance
FROM x
ORDER BY item_id, parent_id;
产生:
parent_id | item_id | hierarchical_id | distance
-----------+---------+-----------------+----------
1 | 1 | ;1; | 0
1 | 2 | ;1;2; | 1
2 | 2 | ;1;2; | 0
1 | 3 | ;1;2;3; | 2
2 | 3 | ;1;2;3; | 1
3 | 3 | ;1;2;3; | 0
1 | 4 | ;1;2;4; | 2
2 | 4 | ;1;2;4; | 1
4 | 4 | ;1;2;4; | 0
1 | 5 | ;1;2;4;5; | 3
2 | 5 | ;1;2;4;5; | 2
4 | 5 | ;1;2;4;5; | 1
5 | 5 | ;1;2;4;5; | 0
这看起来大致正确,但由于您的预期输出似乎与我运行它时提供的查询(第9.1页)的输出不匹配,因此很难确定。现在问题更精确了,这里有一个更好地表达意图的公式,而不仅仅是结果:
CREATE EXTENSION intarray;
SELECT
exploded.*,
array_length(h_arr,1) - idx(h_arr,parent_id) AS distance
FROM (
SELECT unnest(h_arr) AS parent_id, item_id, h_arr
FROM (
SELECT
item_id,
regexp_split_to_array( trim(hierarchical_id,';'),';')::int[] as h_arr
FROM t
) h_as_intarray
) exploded;
。。。虽然由于需要所有的传球,速度有点慢。如果hierarchy_id
首先存储为整数数组,那么它可能应该是:
ALTER TABLE t ALTER COLUMN hierarchical_id TYPE int[]
USING (regexp_split_to_array( trim(hierarchical_id,';'),';')::int[]);
您将有一个更好的查询,因为您将摆脱所有可怕的regexp字符串处理:
SELECT
exploded.*,
array_length(hierarchical_id,1) - idx(hierarchical_id,parent_id) AS distance
FROM (
SELECT unnest(hierarchical_id) AS parent_id, item_id, hierarchical_id
FROM t
) exploded;
。。。在这个小数据集上,奖励积分的速度也快了3倍,并且可能会在更大的数据集上保持或扩大领先优势。我尝试过(编辑前的建议),但我在“组”第38行或附近出现语法错误:行数()超过(按项目分组id),因为我刚刚尝试了当前的建议,使用PARTITION BY item_id,我得到所有行的1。我编辑的意思是,如果我在另一个select中移动行数,它会起作用,这正是您在更新中添加的内容。如果与样本数据不匹配,则错误在样本中。谢谢大家!@索林:不用担心。请注意,这只适用于
分层_id
严格按降序排列的情况;如果您有一个的层次\u id
;5.2.1.3;代码>然后它就会完全崩溃。@Sorin现在你已经解释了如何和为什么不只是发布了什么,更好的答案。说到“为什么”-为什么要以这种扭曲的格式存储层次结构的_id,而不是整数数组?您的预期输出与您为示例输入数据提供的查询的输出不匹配。查询的输出中有三行item\u id
=3,而不是两行。还不清楚这些距离的确切含义,或者它们是如何推导的。我在答案中尝试了一下,但问题不是很清楚。OTOH,至少你提供了示例数据,即使我不得不手动将其转换为insert。我更新了预期的输出,你是对的,缺少一行。至于距离,我试着在预期输出之后解释一下。这是一个很好的选择,我会记住它,以防我不得不设计类似的东西。