Postgres with RECURSIVE CTE:按受欢迎程度对子项进行排序排序,同时保留树结构(父级始终高于子级)

postgresql

1个回答

写回答

royyyy

2025-07-01 09:25

+ 关注

PostgreSQL
PostgreSQL

使用PostgreSQL数据库中的递归公共表表达式(CTE),我们可以对树形结构的数据进行排序,同时保留其父级始终高于子级的顺序。在本文中,我们将介绍如何使用递归CTE来实现这一目标,并提供相关的代码示例。

在开始之前,让我们先来了解一下递归CTE是什么。递归CTE是一种特殊的CTE,它允许我们在CTE的定义中引用自身。这种递归的引用使得我们能够处理树形结构的数据,例如组织结构、分类层次等等。

排序树形数据的挑战

在排序树形数据时,我们面临一个挑战,即如何保持父级始终高于子级。通常情况下,我们可以使用一种深度优先搜索(DFS)的算法来遍历树,并为每个节点分配一个排序值。然而,这种方法并不适用于递归CTE,因为递归CTE是在每次迭代中处理一个节点的子级。

为了解决这个问题,我们可以使用递归CTE的特性,逐层计算每个节点的排序值。具体来说,我们可以为每个节点添加一个额外的字段,表示其所有祖先节点的排序值的组合。通过这种方式,我们可以确保父级始终高于子级。

示例场景

我们以一个简单的示例场景为例,来演示如何使用递归CTE对树形数据进行排序。假设我们有一个城市列表,其中包含城市的名称和所属国家的名称。城市之间的层次关系通过上级城市字段表示。

首先,我们需要创建一个城市表,并插入一些示例数据:

sql

CREATE TABLE cities (

id SERIAL PRIMARY KEY,

name VARCHAR(100),

country VARCHAR(100),

parent_city_id INTEGER

);

INSERT INTO cities (name, country, parent_city_id) VALUES

('New York', 'United States', NULL),

('Los Angeles', 'United States', NULL),

('San Francisco', 'United States', NULL),

('Chicago', 'United States', NULL),

('London', 'United Kingdom', NULL),

('Manchester', 'United Kingdom', NULL),

('Leeds', 'United Kingdom', NULL),

('Edinburgh', 'United Kingdom', NULL),

('San Jose', 'United States', 3),

('Oakland', 'United States', 3),

('San Diego', 'United States', 2),

('Glasgow', 'United Kingdom', 7),

('Liverpool', 'United Kingdom', 6),

('Birmingham', 'United Kingdom', 6);

现在,我们可以使用递归CTE来对城市进行排序,同时保留树形结构。以下是实现该功能的查询:

sql

WITH RECURSIVE city_tree AS (

SELECT id, name, country, parent_city_id,

ROW_NUMBER() OVER (ORDER BY name) AS sort_order,

name AS path

FROM cities

WHERE parent_city_id IS NULL

UNION ALL

SELECT c.id, c.name, c.country, c.parent_city_id,

ROW_NUMBER() OVER (PARTITION BY city_tree.sort_order ORDER BY c.name),

city_tree.path || ' -> ' || c.name

FROM cities c

JOIN city_tree ON c.parent_city_id = city_tree.id

)

SELECT id, name, country, sort_order, path

FROM city_tree

ORDER BY sort_order;

在上述查询中,我们首先选择根节点,即没有上级城市的城市。我们为根节点分配一个初始排序值,并将城市名称作为路径。

然后,我们使用递归CTE来处理子级节点。我们通过联接城市表和city_tree表,找到每个节点的子级。我们使用ROW_NUMBER()函数为每个子级节点分配一个排序值,并将它们添加到路径中。

最后,我们从city_tree表中选择所需的列,并按照排序值进行排序。

结果

运行上述查询后,我们将获得按照受欢迎程度排序的城市列表,同时保留了树形结构。以下是查询结果的示例:

id | name | country | sort_order | path

----+---------------+----------------+------------+--------------------------------

1 | New York | United States | 1 | New York

2 | Los Angeles | United States | 2 | Los Angeles

3 | San Francisco | United States | 3 | San Francisco

9 | San Jose | United States | 4 | San Francisco -> San Jose

10 | Oakland | United States | 5 | San Francisco -> Oakland

11 | San Diego | United States | 6 | Los Angeles -> San Diego

4 | Chicago | United States | 7 | Chicago

5 | London | United Kingdom | 8 | London

6 | Manchester | United Kingdom | 9 | London -> Manchester

13 | Liverpool | United Kingdom | 10 | Manchester -> Liverpool

12 | Glasgow | United Kingdom | 11 | Edinburgh -> Glasgow

7 | Leeds | United Kingdom | 12 | Leeds

8 | Edinburgh | United Kingdom | 13 | Edinburgh

14 | Birmingham | United Kingdom | 14 | Leeds -> Birmingham

通过结果可以看出,城市列表按照受欢迎程度进行了排序,同时仍保留了城市之间的层次关系。

在本文中,我们介绍了如何使用PostgreSQL的递归CTE来对树形数据进行排序,并保留其父级始终高于子级的顺序。通过递归CTE,我们可以逐层计算每个节点的排序值,并获得一个排序后的树形结构。

递归CTE是一个非常强大的工具,可以让我们处理各种树形数据的排序和遍历问题。通过使用递归CTE,我们可以轻松地处理组织结构、分类层次等等。

希望本文对你理解如何使用递归CTE对树形数据进行排序有所帮助。你可以在自己的项目中尝试这个方法,并根据实际需求进行调整和优化。

举报有用(4)分享收藏

Copyright © 2025 IZhiDa.com All Rights Reserved.

知答 版权所有 粤ICP备2023042255号