从 PostgreSQL 中的类别数组创建类别树 table
Creating a category tree table from an array of categories in PostgreSQL
如何从类别数组中生成 ID 和 parent_ids。子类别的数量或深度可以是 1-10 级之间的任何值。
示例 PostgreSQL 列。数据类型字符可变数组。
data_column
character varying[] |
----------------------------------
[root_1, child_1, childchild_1] |
[root_1, child_1, childchild_2] |
[root_2, child_2] |
我想将数组的列转换为 table,如下所示,我假设它称为邻接列表模型。我知道还有嵌套树集模型和物化路径模型。
最终输出table
id | title | parent_id
------------------------------
1 | root_1 | null
2 | root_2 | null
3 | child_1 | 1
4 | child_2 | 2
5 | childchild_1 | 3
6 | childchild_2 | 3
最终输出树层次结构
root_1
--child_1
----childchild_1
----childchild_2
root_2
--child_2
您可以使用 recursive CTE
WITH RECURSIVE cte AS
( SELECT data[1] as title, 2 as idx, null as parent, data FROM t -- 1
UNION
SELECT data[idx], idx + 1, title, data -- 2
FROM cte
WHERE idx <= cardinality(data)
)
SELECT DISTINCT -- 3
title,
parent
FROM cte
- 递归的起始查询:获取递归中需要的所有根元素和数据
- 递归部分:获取新索引的元素并增加索引
- 递归后:查询最终需要的列。
DISTINCT
删除绑定元素(例如相同的两倍 root_1
)。
现在您已经创建了层次结构。现在您需要 ID。
您可以通过多种不同的方式生成它们,例如使用 row_number()
window function:
WITH RECURSIVE cte AS (...)
SELECT
*,
row_number() OVER ()
FROM (
SELECT DISTINCT
title,
parent
FROM cte
) s
现在,每一行都有自己的 ID。订单标准可能会稍微调整一下。在这里,如果没有任何进一步的信息,我们几乎没有机会改变它。但算法保持不变。
有了每列的id,我们可以创建一个自连接,通过使用parent
title 列来连接父id。因为自连接是 select 查询的重复,所以将其封装到第二个 CTE 以避免代码复制是有意义的。最后的结果是:
WITH RECURSIVE cte AS
( SELECT data[1] as title, 2 as idx, null as parent, data FROM t
UNION
SELECT data[idx], idx + 1, title, data
FROM cte
WHERE idx <= cardinality(data)
), numbered AS (
SELECT
*,
row_number() OVER ()
FROM (
SELECT DISTINCT
title,
parent
FROM cte
) s
)
SELECT
n1.row_number as id,
n1.title,
n2.row_number as parent_id
FROM numbered n1
LEFT JOIN numbered n2 ON n1.parent = n2.title
如何从类别数组中生成 ID 和 parent_ids。子类别的数量或深度可以是 1-10 级之间的任何值。
示例 PostgreSQL 列。数据类型字符可变数组。
data_column
character varying[] |
----------------------------------
[root_1, child_1, childchild_1] |
[root_1, child_1, childchild_2] |
[root_2, child_2] |
我想将数组的列转换为 table,如下所示,我假设它称为邻接列表模型。我知道还有嵌套树集模型和物化路径模型。
最终输出table
id | title | parent_id
------------------------------
1 | root_1 | null
2 | root_2 | null
3 | child_1 | 1
4 | child_2 | 2
5 | childchild_1 | 3
6 | childchild_2 | 3
最终输出树层次结构
root_1
--child_1
----childchild_1
----childchild_2
root_2
--child_2
您可以使用 recursive CTE
WITH RECURSIVE cte AS
( SELECT data[1] as title, 2 as idx, null as parent, data FROM t -- 1
UNION
SELECT data[idx], idx + 1, title, data -- 2
FROM cte
WHERE idx <= cardinality(data)
)
SELECT DISTINCT -- 3
title,
parent
FROM cte
- 递归的起始查询:获取递归中需要的所有根元素和数据
- 递归部分:获取新索引的元素并增加索引
- 递归后:查询最终需要的列。
DISTINCT
删除绑定元素(例如相同的两倍root_1
)。
现在您已经创建了层次结构。现在您需要 ID。
您可以通过多种不同的方式生成它们,例如使用 row_number()
window function:
WITH RECURSIVE cte AS (...)
SELECT
*,
row_number() OVER ()
FROM (
SELECT DISTINCT
title,
parent
FROM cte
) s
现在,每一行都有自己的 ID。订单标准可能会稍微调整一下。在这里,如果没有任何进一步的信息,我们几乎没有机会改变它。但算法保持不变。
有了每列的id,我们可以创建一个自连接,通过使用parent
title 列来连接父id。因为自连接是 select 查询的重复,所以将其封装到第二个 CTE 以避免代码复制是有意义的。最后的结果是:
WITH RECURSIVE cte AS
( SELECT data[1] as title, 2 as idx, null as parent, data FROM t
UNION
SELECT data[idx], idx + 1, title, data
FROM cte
WHERE idx <= cardinality(data)
), numbered AS (
SELECT
*,
row_number() OVER ()
FROM (
SELECT DISTINCT
title,
parent
FROM cte
) s
)
SELECT
n1.row_number as id,
n1.title,
n2.row_number as parent_id
FROM numbered n1
LEFT JOIN numbered n2 ON n1.parent = n2.title