SQL集合运算参考及案例(二):树形节点数量逐级累计汇总
问题描述:
我们经常遇到这样一个问题,类似于面对一个树形结构的物料数据,需要将库存中每一种物料数量汇总到物料上展示出来;或者说组织机构是一棵树,我们需要统计每一个节点上的人员数量(含下级节点的累计数量)。在此将解决的核心部分抽取出来。
因为是树形结构我们需要用到CTE的递归定义。CTE是一种十分优雅的存在,CTE所带来最大的好处是代码可读性的提升,这是良好代码的必须品质之一。使用递归CTE可以更加轻松愉快的用优雅简洁的方式实现复杂的查询。更重要的是标准的SQL是工作在DB关系运算引擎上,而游标等面向过程的代码则不是,这会体现在运行效率上。
在定义和使用递归CTE时应注意:递归 CTE 定义至少必须包含两个 CTE 查询定义,一个定位点成员和一个递归成员。可以定义多个定位点成员和递归成员;但必须将所有定位点成员查询定义置于第一个递归成员定义之前。所有 CTE 查询定义都是定位点成员,但它们引用 CTE 本身时除外。
注:最后一列是我们想要的值
Id |
ParentId |
Qty |
Qty_Sum |
1 |
0 |
1 |
15 |
2 |
1 |
2 |
11 |
3 |
1 |
3 |
3 |
4 |
2 |
4 |
9 |
5 |
4 |
5 |
5 |
--- 构造测试数据的脚本
- CREATE TABLE tMaterial
- (
- Id INT PRIMARY KEY
- , ParentId INT
- , Qty INT
- , Qty_Sum INT
- )
- INSERT INTO tMaterial
- SELECT 1, 0, 1, 0
- UNION ALL SELECT 2, 1, 2, 0
- UNION ALL SELECT 3, 1, 3, 0
- UNION ALL SELECT 4, 2, 4, 0
- UNION ALL SELECT 5, 4, 5, 0
- GO
传统解答:使用自定义函数、递归、游标
- CREATE FUNCTION fn_getQty_Sum(@Id INT)
- RETURNS INT
- AS
- BEGIN
- DECLARE @Qty_Sum INT
- SELECT @Qty_Sum = Qty FROM tMaterial WHERE Id = @Id
- DECLARE @OID INT, @Qty INT
- DECLARE cursor1 CURSOR FOR
- SELECT t.ID from tMaterial AS t WHERE t.ParentId = @Id
- OPEN cursor1
- FETCH NEXT FROM cursor1 INTO @OID
- WHILE @@FETCH_STATUS = 0
- BEGIN
- SET @Qty = dbo.fn_getQty_Sum(@OID)
- SET @Qty_Sum = @Qty_Sum + @Qty
- FETCH NEXT FROM cursor1 INTO @OID
- END
- CLOSE cursor1
- DEALLOCATE cursor1
- RETURN @Qty_Sum
- END
- UPDATE tMaterial
- SET Qty_Sum = dbo.fn_getQty_Sum(Id)
- SELECT *
- FROM tMaterial
推荐解答1:利用CTE的递归和树形结构的特点,为树形结构中的所有节点增加从根节点到当前节点的“访问路径”
- WITH tmp AS
- (
- SELECT t1.*, CAST(CAST(t1.Id AS NVARCHAR) + '.' AS NVARCHAR(100)) AS node_path
- FROM tMaterial t1
- WHERE t1.ParentId = 0
- UNION ALL
- SELECT t1.*, CAST(t2.node_path + CAST(t1.Id AS NVARCHAR) + '.' AS NVARCHAR(100))
- FROM tMaterial t1
- JOIN tmp AS t2 ON t1.ParentId = t2.Id
- )
- , T2 AS
- (
- SELECT t1.Id, t1.ParentId, t1.Qty, sum(t2.qty) AS Qty_Sum
- FROM tmp t1
- JOIN tmp t2 ON t2.node_path LIKE t1.node_path + '%'
- GROUP BY t1.Id, t1.ParentId, t1.Qty, t1.Qty_Sum
- )
- UPDATE T1
- SET T1.Qty_Sum = T2.Qty_Sum
- FROM tMaterial T1
- JOIN T2 ON T1.Id = T2.Id
- SELECT *
- FROM tMaterial
推荐解答2:这个理解起来有点费劲,需要好好联想一下递归定义与表关联
- WITH tmp AS (
- SELECT t.Id tm, * FROM tMaterial t
- UNION ALL
- SELECT t2.tm tm, t1.* FROM tMaterial t1 JOIN tmp t2 ON t1.ParentId = t2.Id
- )
- SELECT tm, sum(Qty)
- FROM tmp
- GROUP BY tm
SQL集合运算参考及案例(二):树形节点数量逐级累计汇总的更多相关文章
- SQL集合运算参考及案例(一):列值分组累计求和
概述 目前企业应用系统使用的大多数据库都是关系型数据库,关系数据库依赖的理论就是针对集合运算的关系代数.关系代数是一种抽象的查询语言,是关系数据操纵语言的一种传统表达方式.不过我们在工作中发现,很多人 ...
- 详解SQL集合运算
以前总是追求新东西,发现基础才是最重要的,今年主要的目标是精通SQL查询和SQL性能优化. 本系列[T-SQL基础]主要是针对T-SQL基础的总结. [T-SQL基础]01.单表查询-几道sql查询题 ...
- SQL集合运算 差集 并集 交
SQL-3标准中提供了三种对检索结果进行集合运算的命令:并集UNION:交集INTERSECT:差集EXCEPT(在Oracle中叫做 MINUS).在有些数据库中对此的支持不够充分,如MySql中只 ...
- 7 SQL 集合运算
7 集合运算 7-1 表的加减法 本章将会和大家一起学习“集合运算”操作.在数学领域,“集合”表示“(各种各样的)事物的总和”:在数据库领域,表示“记录的集合”.具体来说,表.视图和查询的执行结果都是 ...
- sql 集合运算
UNION 并运算 UNION 操作符用于合并两个或多个 SELECT 语句的结果集. 请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列.列也必须拥有相似的数据类型.同时,每条 SE ...
- SQL集合运算:差集、交集、并集
1.差集( except ) select a from t_a except select a from t_b -- 也可写作: select a from t_a where a not in ...
- SQL集合运算
注:UserInfo一共29条记录 select * from UserInfo union --并集(29条记录)(相同的只出现一次) select * from UserInfo select * ...
- SQL Fundamentals || 多表查询(内连接,外连接(LEFT|RIGHT|FULL OUTER JOIN),自身关联,ON,USING,集合运算UNION)
SQL Fundamentals || Oracle SQL语言 一.多表查询基本语法 在进行多表连接查询的时候,由于数据库内部的处理机制,会产生一些“无用”的数据,而这些数据就称为笛卡尔积. 多表查 ...
- [SQL] SQL 基础知识梳理(七)- 集合运算
SQL 基础知识梳理(七)- 集合运算 目录 表的加减法 联结(以列为单位) 一.表的加减法 1.集合:记录的集合(表.视图和查询的执行结果). 2.UNION(并集):表的加法 -- DDL:创建表 ...
随机推荐
- 修复Dll文件
for %1 in (%windir%\system32\*.dll) do regsvr32.exe /s %1
- Android重写getResources规避用户调整系统字体大小影响Android屏幕适配
Android屏幕适配一直是一个头疼的问题.除此之外还要考虑APP在实际应用场景中,用户千奇百怪的设置,最常见的用户设置行为就是设置手机的字体大小,比如把字体设置成超大或者超小,这对屏幕适配又带来额外 ...
- Java最近版本新特性使用介绍
本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 在阅读<Thinking in Java>的过程中,并发这一章出现不少新特性,工作中也有 ...
- Web Browser使用技巧
无论是在桌面级开发中,还是在手机端开发中,WebBrowser都是一个经常会用到的控件.Windows Phone中的WebBrowser虽然远远没有桌面版那么强大,但依然足够应付常规用途.本文就来介 ...
- LeetCode Set Matrix Zeroes(技巧+逻辑)
题意: 给一个n*m的矩阵,如果某个格子中的数字为0,则将其所在行和列全部置为0.(注:新置的0不必操作) 思路: 主要的问题是怎样区分哪些是新来的0? 方法(1):将矩阵复制多一个,根据副本来操作原 ...
- 利用HTML5云存储实现模拟对比投票效果
<!DOCTYPE HTML> <html> <head> <title>模拟对比投票效果</title> <meta name=&q ...
- TruSeq 应该指的是试剂盒名字 NEB
现在中心用的是NEB试剂盒,建库步骤更简单一些.TruSeq和NEB差不多,既可以建DNA又可以建RNA. TruSeq Technology TruSeq technology repres ...
- LCS (nlogn)
最长上升子序列的O(n*logn)算法分析如下: 先回顾经典的O(n^2)的动态规划算法,设a[t]表示序列中的第t个数,dp[t]表示从1到t这一段中以t结尾的最长上升子序列的长度,初始时设dp [ ...
- Phonegap开发的前后台数据交互
在用Phonegap开发时,需要进行前后台数据交互,在网上找资料,很多东西让人一头雾水,最后借鉴了下面的博客: http://blog.sina.com.cn/s/blog_681929ae01017 ...
- ZMMR106-批量更新PO交货日期
************************************************************************ Title : ZMMR106 ** Applicat ...