当前位置: 首页 > 面试题库 >

从邻接表将元素的祖先写入Postgres表

宋琛
2023-03-14
问题内容

我想将1到n层次结构作为邻接表存储到列出每个元素祖先的表中。我正在使用Postgres数据库(Postgres
10,但是要在其上部署代码的计算机运行Postgres 9.x)。

示例输入表(邻接表):

INSERT INTO public.test (id, name, parent_id)
VALUES (1, 't', 1),
   (11, 't1', 1),
   (12, 't2', 1),
   (13, 't3', 1),
   (111, 't11', 11),
   (112, 't12', 11),
   (121, 't21', 12),
   (14, 't4', 1),
   (141, 't41', 14),
   (142, 't42', 14)

结果,我想要一个看起来像这样的表(仅显示了几行;此外,我要解决的现实问题有七个层次级别,而不是两个):

+-----+-------+--------+--------+
| id  | level | level0 | level1 |
+-----+-------+--------+--------+
|   1 |     0 | NULL   | NULL   |
|  11 |     1 | 1      | NULL   |
|  12 |     1 | 1      | NULL   |
| 111 |     2 | 1      | 11     |
+-----+-------+--------+--------+

id是元素的ID,level是该元素在层次结构中所处的级别(0是根级别),level0/1元素在各个级别上的祖先。

我是SQL的新手,所以我没有任何可以向您显示的代码。Googling告诉我,我可能不太希望使用递归CTE来获得所需的结果并执行自联接,但是我一直无法弄清楚该怎么做。谢谢你的帮助。

编辑

到目前为止,这是我尝试过的:

WITH RECURSIVE cte AS
(
SELECT m.id AS id,
    0 AS level,
    m.parent_id AS level0,
    m.parent_id AS level1,
    m.parent_id AS parent
    FROM public.test AS m
    WHERE m.parent_id IS NULL

UNION ALL

SELECT 
    m.id,
    cte.level + 1,
    cte.parent AS level0,
    cte.parent AS level1,
    m.parent_id AS parent
    FROM public.test AS m 
        INNER JOIN cte
            ON m.parent_id = cte.id 
)
SELECT *
FROM cte;

当然,将level0和设置level1为元素的父元素并不会产生所需的结果,但是我不得不将其设置为某种东西,并且没有比这更进一步的了。


问题答案:

SQL是严格类型化的语言,它不允许a返回的列数SELECT根据所处理的数据而变化。有关讨论,请参见例如将逗号分隔的列数据拆分为其他列。

但是,PostgreSQL提供了一种数组类型,可用于将动态大小的值收集到单个列中。以下递归CTE将每一行的所有祖先收集到这样的数组中:

with recursive rec(id, level, parent_id, ancestors) as (
  select id, 0, parent_id, array[] :: int[]
  from test
  where parent_id = id
  union all
  select t.id, rec.level + 1, t.parent_id, rec.ancestors || array[t.parent_id]
  from test t
  join rec on t.parent_id = rec.id
  where t.parent_id <> t.id
)
select 
  rec.id,
  rec.level,
  rec.ancestors
from rec;

如果对级别有已知限制,则可以从数组的每列中选择元素:

select
  rec.id,
  rec.level,
  rec.ancestors[1] level1,
  rec.ancestors[2] level2,
  ...

SQL小提琴



 类似资料:
  • 这是我定义邻接列表的方式:

  • 问题内容: 有 DataFrame.to_sql 方法,但仅适用于mysql,sqlite和oracle数据库。我无法传递给此方法postgres连接或sqlalchemy引擎。 问题答案: 从pandas 0.14(2014年5月发行)开始,支持postgresql。该模块现在用于支持不同的数据库风格。您可以为PostgreSQL数据库传递sqlalchemy引擎(请参阅docs)。例如: 您是

  • 我试图编写一个流作业,它将数据流下沉到postgres表中。为了提供完整的信息,我的工作基于以下文章:https://tech.signavio.com/2017/postgres-flink-sink,这些文章建议使用JDBCoutputFormat。 所以我的问题是:我错过了什么吗?我应该将插入的行提交到某个地方吗? 向你致意,伊格内修斯

  • 问题内容: 这让我发疯: HTML: CSS: 这不是读到“选择所有祖先不是元素的元素吗?”。因此,“ Hello World!” 不应显示为红色,但仍然是。 对于上述标记,添加子组合器的工作原理是: 但是,如果它不是元素的子元素,则不会影响元素。例如: 这就是为什么我想将元素表示为元素的后代而不是子元素。任何人? 问题答案: 这不是读到“选择所有祖先不是元素的元素吗?”。 是的 但是在一个典型的

  • 问题内容: 我在Postgres中有一个包含此数据的表,并且很难将其转换为JSON对象。 我该如何转换呢? 任何建议都会有所帮助。谢谢 问题答案: 使用(https://www.postgresql.org/docs/current/static/queries- with.html )和JSON函数(https://www.postgresql.org/docs/current/static/f

  • 问题内容: Google Python类| 清单练习- 给定一个数字列表,返回一个列表,其中所有相邻的==元素都已简化为单个元素,因此[1、2、2、3]返回[1、2、3]。您可以创建一个新列表或修改传入的列表。 我使用新列表的解决方案是- 问题甚至暗示可以通过修改传入列表来完成。但是,python文档警告不要在使用for循环迭代列表时修改元素。 我想知道除了遍历列表之外还能做些什么呢?我不是在寻找