Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Postgresql 对于每个组,在0处重新启动的类似行数的方法_Postgresql - Fatal编程技术网

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。我更新了预期的输出,你是对的,缺少一行。至于距离,我试着在预期输出之后解释一下。这是一个很好的选择,我会记住它,以防我不得不设计类似的东西。