postgres创建递归视图

  • 递归功能:把所有继承关系的id都放到一个新的数级字段中(当前的元素id+父id+父的父id+…)
CREATE OR REPLACE RECURSIVE VIEW VW_BUSINESS_CAPABILITY_MODEL_HIERARCHY (relation_id, sub_id, bcm_id, bcm_name, bcm_type, path) AS
	SELECT sbcm.id,
		sbcm2.id AS sub_id,
		sbcm2.bcm_id,
		sbcm2.bcm_name,
		sbcm2.bcm_type,
		ARRAY [cast(sbcm2.id as character varying)]
		FROM solaris_business_capability_model sbcm
		LEFT JOIN solaris_business_capability_model sbcm2 ON sbcm.id = sbcm2.parent_id
		WHERE sbcm.parent_id is null AND sbcm.bcm_industry_id = 'I_CROSS'
	UNION
		SELECT vw.sub_id as id,
		sbcm3.id as sub_id,
		sbcm3.bcm_id,
		sbcm3.bcm_name,
		sbcm3.bcm_type,
		vw.path || cast(sbcm3.id as character varying)
		FROM vw_business_capability_model_hierarchy vw
		JOIN solaris_business_capability_model sub ON sbcm3.parent_id = vw.sub_id
  • 把字符串 字段 放在一个数组类型的新字段 path
    • ARRAY [cast(sbcm2.id as character varying)]
  • 新数组字段添加 字符串值 元素进来
    • vw.path || cast(sbcm3.id as character varying)
<think> 我们正在讨论的是PostgreSQL中的WITH子句(也称为公共表表达式,CTE)。根据用户提供的引用,我们可以总结WITH子句的关键点,并给出详细的使用方法和示例。用户引用的内容主要涉及WITH子句的基本用法、优点、缺点以及一些示例。 ### 1. **WITH子句的基本概念** WITH子句允许我们在一个查询中定义一个或多个临时结果集,这些结果集可以在后续的主查询中被引用。它类似于临时视图,但只在当前查询中有效。 ### 2. **WITH子句的语法** ```sql WITH cte_name (column_list) AS ( CTE_query_definition ) main_query; ``` - `cte_name`:临时结果集的名称。 - `column_list`:可选,指定CTE中列的别名。如果省略,则使用查询中的列名。 - `CTE_query_definition`:定义CTE的查询。 - `main_query`:使用CTE的主查询。 ### 3. **使用场景** #### a) 提高可读性(引用[1][2]) 将复杂查询拆分为多个CTE,使查询逻辑更清晰。 **示例**:引用[3]中的简单CTE ```sql WITH cte AS ( SELECT * FROM company ) SELECT * FROM cte; ``` #### b) 避免重复子查询(引用[2][5]) 当同一个子查询在多个地方被使用时,使用CTE可以避免重复计算。 **示例**:引用[4]中,用CTE计算一段时间内的充值总额,然后在主查询中与其他表连接 ```sql WITH u AS ( SELECT id, SUM(amount) AS num FROM pay WHERE pay_time >= 1493568000 AND pay_time < 1494172800 GROUP BY id ) SELECT u.id, pinfo.sid, u.num FROM u JOIN pinfo ON u.id = pinfo.id; ``` #### c) 递归查询(引用[2][5]) 递归CTE用于处理树形或层次结构数据,如组织结构、目录树等。 **递归CTE语法**: ```sql WITH RECURSIVE cte_name AS ( -- 非递归部分(初始查询) SELECT ... UNION [ALL] -- 递归部分(引用CTE自身) SELECT ... FROM cte_name ... ) SELECT ... FROM cte_name; ``` **示例**:查询员工及其所有下属(假设表employees有id, name, manager_id) ```sql WITH RECURSIVE subordinates AS ( SELECT id, name, manager_id FROM employees WHERE id = 1 -- 假设要查询id为1的员工及其所有下属 UNION SELECT e.id, e.name, e.manager_id FROM employees e INNER JOIN subordinates s ON s.id = e.manager_id ) SELECT * FROM subordinates; ``` #### d) 数据修改(引用[2][5]) 在WITH子句中可以使用INSERT、UPDATE、DELETE等数据修改语句,然后在主查询中返回修改后的数据。 **示例**:删除数据并返回被删除的行 ```sql WITH deleted_rows AS ( DELETE FROM employees WHERE salary < 3000 RETURNING * ) SELECT * FROM deleted_rows; -- 返回被删除的员工记录 ``` ### 4. **注意事项(引用[5])** - **性能开销**:CTE的结果集通常存储在内存中,对于大数据集可能导致性能下降。 - **递归深度**:递归CTE可能因递归过深而出现性能问题。 - **索引**:不能在CTE上创建索引,因此对于需要索引的场景,可能需要考虑临时表。 - **可读性**:虽然CTE能提高可读性,但过度嵌套或复杂的CTE可能使查询更难理解。 ### 5. **使用建议** - 对于复杂查询,使用多个CTE逐步构建,提高可读性。 - 避免在CTE中处理过大的数据集,尤其是递归查询。 - 在需要多次引用同一个子查询时,使用CTE可以减少重复计算。 ### 总结 WITH子句(CTE)是PostgreSQL中处理复杂查询的强大工具,它通过模块化查询逻辑、支持递归查询和数据修改操作,显著提升SQL代码的可读性和可维护性。但需注意其潜在的性能影响,合理使用。 §§相关问题§§ 1. 如何在递归CTE中避免无限循环? 2. 在哪些场景下使用CTE比使用临时表更合适? 3. 如何优化递归CTE的性能? </think> 以下是关于 PostgreSQL 中 `WITH` 子句(Common Table Expressions,CTE)的详细使用指南,结合核心功能和实际场景: --- ### 一、`WITH` 子句的核心功能 1. **简化复杂查询** 将大型查询拆分为逻辑模块(引用[1][2]): ```sql WITH regional_sales AS ( SELECT region, SUM(amount) AS total_sales FROM orders GROUP BY region ) SELECT region, total_sales FROM regional_sales WHERE total_sales > 100000; ``` 2. **支持递归查询** 处理树形结构数据(引用[2][5]): ```sql WITH RECURSIVE employee_hierarchy AS ( SELECT id, name, manager_id -- 初始查询(根节点) FROM employees WHERE manager_id IS NULL UNION ALL SELECT e.id, e.name, e.manager_id -- 递归部分 FROM employees e JOIN employee_hierarchy eh ON e.manager_id = eh.id ) SELECT * FROM employee_hierarchy; ``` 3. **数据修改操作** 在单一语句中实现增删改查(引用[5]): ```sql WITH deleted_orders AS ( DELETE FROM orders WHERE order_date < '2023-01-01' RETURNING order_id, amount -- 返回被删除的数据 ) INSERT INTO archive_orders SELECT * FROM deleted_orders; ``` --- ### 二、关键使用场景与示例 #### 场景1:数据分步处理(引用[4]) ```sql WITH user_payments AS ( SELECT user_id, SUM(amount) AS total_paid FROM payments WHERE payment_time BETWEEN '2023-05-01' AND '2023-05-08' GROUP BY user_id ) SELECT u.user_id, p.sid, u.total_paid FROM user_payments u JOIN profiles p ON u.user_id = p.user_id; ``` #### 场景2:避免重复子查询 ```sql WITH top_products AS ( SELECT product_id, AVG(rating) AS avg_rating FROM reviews GROUP BY product_id HAVING COUNT(*) > 50 -- 只统计超过50条评论的商品 ) SELECT p.name, tp.avg_rating FROM products p JOIN top_products tp ON p.id = tp.product_id; ``` --- ### 三、性能优化与注意事项 1. **优点**(引用[2][5]): - 📊 **可读性提升**:将复杂逻辑拆解为命名模块 - 🔁 **代码重用**:避免重复子查询 - ⚡ **优化器支持**:PostgreSQL 会对 CTE 进行优化 2. **缺点**(引用[5]): - ⚠️ **内存消耗**:大型结果集可能占用过多内存 - ⏱️ **递归深度风险**:深层递归可能导致性能下降 - 🔒 **无索引支持**:CTE 结果集无法创建索引 3. **性能建议**: ```sql WITH cte_materialized AS MATERIALIZED ( -- 强制物化结果(PostgreSQL 12+) SELECT * FROM large_table ) SELECT ... FROM cte_materialized; ``` --- ### 四、典型错误示例 **错误:** 在 CTE 中执行不必要的数据扫描 ```sql -- 低效写法 (全表扫描两次) WITH all_orders AS (SELECT * FROM orders) SELECT * FROM all_orders WHERE amount > 100; ``` **优化方案:** ```sql -- 高效写法 (减少扫描范围) WITH filtered_orders AS ( SELECT * FROM orders WHERE amount > 100 -- 提前过滤 ) SELECT * FROM filtered_orders; ``` --- ### 总结 `WITH` 子句是 PostgreSQL 处理复杂查询的核心工具,尤其适用于: 1. 多步骤数据加工 2. 递归层级数据处理 3. 需要数据修改的原子操作 使用时需平衡可读性与性能,对大数据集优先考虑物化策略(`MATERIALIZED`)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值