问题描述:

我们经常遇到这样一个问题,类似于面对一个树形结构的物料数据,需要将库存中每一种物料数量汇总到物料上展示出来;或者说组织机构是一棵树,我们需要统计每一个节点上的人员数量(含下级节点的累计数量)。在此将解决的核心部分抽取出来。

因为是树形结构我们需要用到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集合运算参考及案例(二):树形节点数量逐级累计汇总的更多相关文章

  1. SQL集合运算参考及案例(一):列值分组累计求和

    概述 目前企业应用系统使用的大多数据库都是关系型数据库,关系数据库依赖的理论就是针对集合运算的关系代数.关系代数是一种抽象的查询语言,是关系数据操纵语言的一种传统表达方式.不过我们在工作中发现,很多人 ...

  2. 详解SQL集合运算

    以前总是追求新东西,发现基础才是最重要的,今年主要的目标是精通SQL查询和SQL性能优化. 本系列[T-SQL基础]主要是针对T-SQL基础的总结. [T-SQL基础]01.单表查询-几道sql查询题 ...

  3. SQL集合运算 差集 并集 交

    SQL-3标准中提供了三种对检索结果进行集合运算的命令:并集UNION:交集INTERSECT:差集EXCEPT(在Oracle中叫做 MINUS).在有些数据库中对此的支持不够充分,如MySql中只 ...

  4. 7 SQL 集合运算

    7 集合运算 7-1 表的加减法 本章将会和大家一起学习“集合运算”操作.在数学领域,“集合”表示“(各种各样的)事物的总和”:在数据库领域,表示“记录的集合”.具体来说,表.视图和查询的执行结果都是 ...

  5. sql 集合运算

    UNION 并运算 UNION 操作符用于合并两个或多个 SELECT 语句的结果集. 请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列.列也必须拥有相似的数据类型.同时,每条 SE ...

  6. SQL集合运算:差集、交集、并集

    1.差集( except ) select a from t_a except select a from t_b -- 也可写作: select a from t_a where a not in ...

  7. SQL集合运算

    注:UserInfo一共29条记录 select * from UserInfo union --并集(29条记录)(相同的只出现一次) select * from UserInfo select * ...

  8. SQL Fundamentals || 多表查询(内连接,外连接(LEFT|RIGHT|FULL OUTER JOIN),自身关联,ON,USING,集合运算UNION)

    SQL Fundamentals || Oracle SQL语言 一.多表查询基本语法 在进行多表连接查询的时候,由于数据库内部的处理机制,会产生一些“无用”的数据,而这些数据就称为笛卡尔积. 多表查 ...

  9. [SQL] SQL 基础知识梳理(七)- 集合运算

    SQL 基础知识梳理(七)- 集合运算 目录 表的加减法 联结(以列为单位) 一.表的加减法 1.集合:记录的集合(表.视图和查询的执行结果). 2.UNION(并集):表的加法 -- DDL:创建表 ...

随机推荐

  1. 13、C#基础整理(枚举)

    枚举 1.概念和作用 (1)用于存放常量,只能在定义时赋值(防止编程过程中恶意篡改,并且防止对同一事物的不同赋值--统一化) (2)定义的枚举类型需要包含该类型的所有可能的值 (3)方法.类.内部都可 ...

  2. Unity3D ShaderLab 模拟精灵动画

    Unity3D ShaderLab 模拟精灵动画 在上一篇,介绍了通过Shader 模拟纹理运动,那么更深一步讲,我们也可以把帧动画的精灵纹理运动通过shader实现. 虽然大家都是在游戏脚本中做更高 ...

  3. HDU 3351

    http://acm.hdu.edu.cn/showproblem.php?pid=3351 乍一看很像经典的括号匹配问题,其实不然,因为操作并非增加括号,而是翻转括号 只需记录多余的左括号的数量即可 ...

  4. C#静态类和静态成员

    1. 静态类 1.1 简介  静态类和类成员用于创建无需创建类的实例就能够访问的数据和函数. 静态类成员可用于分离独立于任何对象标识的数据和行为:无论对象发生什么更改,这些数据和函数都不会随之变化. ...

  5. VirtualBox 设置共享文件夹自动挂载

    1.在VirtualBox中设置文件夹位置和名称,这里使用的名称是share 1.在ubuntu12.04的/etc/rc.local中加入自动挂载命令 sudo mount -t vboxsf sh ...

  6. 关于VS中更改栈和堆空间的大小

    编号:1008时间:2016年4月12日17:01:38功能:关于VS中更改栈和堆空间的大小 URL:http://blog.csdn.net/icerock2000/article/details/ ...

  7. 在双系统( Win7 + Ubuntu )环境下正常删除Ubuntu

    前言 首先切记一点:如果你和我一样使用ubuntu的目的是学习操作系统和Unix网络编程等,那么学习环境搭建好了以后切不要随意更新软件.否则系统崩溃,你又得重新配置各种环境,有多麻烦你懂的. 万一你像 ...

  8. FDR

    声明: 网上摘抄 False discovery rate (FDR) control is a statistical method used in multiple hypothesis test ...

  9. (理论篇)温故而知新_PHP入门基础教程

    简单的回顾一下基础知识 1.嵌入方法: 类似ASP的<%,PHP可以是<?php或者是<?,结束符号是?>,当然您也可以自己指定. 2.引用文件: 引用文件的方法有两种:req ...

  10. hdu 5207

    题目大意:给定一组数,取两个数,使得gcd最大.分析:先nlogn预处理出105所有数的因子,然后用cnt数组计数给定数的因子个数,再找到最大的i,满足cnt[i]>=2,复杂度为nlogn.学 ...