一个有趣的SQL Server 层级汇总数据问题
NULL 2 Andrew 200
2 1 Nancy 100
2 3 Janet 120
3 4 Michael 80
1 5 Robert 50
每个员工的总销售额=自己的销售额+其下级员工的总销售额,
比如:
Andrew = 200_100_120_80_50=550
Nancy = 100+50=150
Janet = 120+80=200
Michael = 80
Robert = 50
这个用SQL怎样可以查询得到,请教一下大家???

IF OBJECT_ID(N'dbo.MyEmp', N'U') IS NOT NULL
BEGIN
DROP TABLE dbo.MyEmp;
END
GO CREATE TABLE dbo.MyEmp (
MyEmpID INT NOT NULL,
ParentID INT NULL,
MyEmpName NVARCHAR(20) NOT NULL,
HoursSalary INT NOT NULL
);
GO IF OBJECT_ID(N'PK_U_CL_MyEmp_MyEmpID', N'PK') IS NULL
BEGIN
ALTER TABLE [dbo].[MyEmp] ADD CONSTRAINT [PK_U_CL_MyEmp_MyEmpID] PRIMARY KEY CLUSTERED
(
[MyEmpID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90)
ON [PRIMARY];
END
GO IF OBJECT_ID(N'FK_MyEmp_MyEmp_ParentID', N'F') IS NULL
BEGIN
ALTER TABLE dbo.MyEmp ADD CONSTRAINT FK_MyEmp_MyEmp_ParentID FOREIGN KEY (ParentID) REFERENCES dbo.MyEmp (MyEmpID);
END
GO -- Insert Test Data
INSERT INTO dbo.MyEmp (MyEmpID, ParentID, MyEmpName, HoursSalary) VALUES
(1, NULL, N'Andrew', 200),
(2, 1, N'Nancy', 100),
(3, 1, N'Janet', 120),
(4, 3, N'Michael', 80),
(5, 2, N'Robert', 50)
GO ;WITH tData (MyEmpID, MyEmpName, ParentID, ParentName, HoursSalary, ParentHierarchyIndex, HierarchyIndex, LevelID, HierarchyName, HierarchyName2) AS (
-- 基准点查询
SELECT MyEmpID /*雇员ID*/
,MyEmpName /*雇员名称*/
,ISNULL(ParentID, 0) AS ParentID /*父雇员ID*/
,CAST(N'' AS NVARCHAR(20)) AS ParentName /*父雇员名称*/
,HoursSalary /*小时薪水*/
,CAST(CONCAT(',', ISNULL(ParentID, 0), ',') AS VARCHAR(300)) AS ParentHierarchyIndex /*父层级索引字符串*/
,CAST(CONCAT(',', ISNULL(ParentID, 0), ',', MyEmpID, ',') AS VARCHAR(300)) AS HierarchyIndex /*层级索引字符串串,包含当前层级*/
,CAST(1 AS INT) AS LevelID /*层级ID,根层级为1,层级越深则数字越大*/
,CAST(MyEmpName AS NVARCHAR(800)) AS HierarchyName /*层级名称,树形结构显示*/
,CAST(MyEmpName AS NVARCHAR(80)) AS HierarchyName2 /*层级名称2,水平结构显示*/
FROM dbo.MyEmp
WHERE ParentID IS NULL
-- 递归查询
UNION ALL
SELECT T.MyEmpID
,T.MyEmpName
,T.ParentID
,T2.MyEmpName
,T.HoursSalary
,CAST(CONCAT(T2.ParentHierarchyIndex, T.ParentID, ',') AS VARCHAR(300)) AS ParentHierarchyIndex
,CAST(CONCAT(T2.HierarchyIndex, T.MyEmpID, ',') AS VARCHAR(300)) AS HierarchyIndex
,T2.LevelID + 1 AS LevelID
,CAST(CONCAT(REPLICATE(N'| ', T2.LevelID), T.MyEmpName) AS NVARCHAR(800)) AS HierarchyName
,CAST(CONCAT(T2.HierarchyName2, '->', T.MyEmpName) AS NVARCHAR(80)) AS HierarchyName2
FROM dbo.MyEmp AS T
INNER JOIN tData AS T2
ON T.ParentID = T2.MyEmpID
) -- 使用HierarchyIndex来实现 -- CROSS APPLY
SELECT T.*, T2.TotalSalary AS TotalSalary
FROM tData AS T
CROSS APPLY (SELECT SUM(tData.HoursSalary) AS TotalSalary
FROM tData
WHERE HierarchyIndex LIKE CONCAT(T.HierarchyIndex, '%')) AS T2
ORDER BY T.HierarchyIndex ASC; -- SELECT + 子查询
--SELECT T.*, TotalSalary = ( SELECT SUM(tData.HoursSalary) FROM tData WHERE tData.HierarchyIndex LIKE CONCAT(T.HierarchyIndex, '%'))
--FROM tData AS T
--ORDER BY T.HierarchyIndex ASC; -- 使用ParentHierarchyIndex
-- CROSS APPLY
--SELECT T.*, T.HoursSalary + T2.DownMemberTotalHoursSalary AS TotalSalary
--FROM tData AS T
-- CROSS APPLY (
-- SELECT ISNULL(SUM(tData.HoursSalary), 0) AS DownMemberTotalHoursSalary
-- FROM tData
-- WHERE tData.ParentHierarchyIndex LIKE CONCAT(T.ParentHierarchyIndex, T.MyEmpID, '%')
-- ) AS T2
--ORDER BY T.HierarchyIndex ASC; -- SELECT + 子查询
--SELECT T.*, T.HoursSalary + (SELECT ISNULL(SUM(tData.HoursSalary), 0) AS DownMemberTotalHoursSalary
-- FROM tData
-- WHERE tData.ParentHierarchyIndex LIKE CONCAT(T.ParentHierarchyIndex, T.MyEmpID, '%')) AS TotalSalary
--FROM tData AS T
--ORDER BY T.HierarchyIndex ASC;
GO
以上解决方案是在不修改数据结构的情况下来实现的,从以上解决方案中,我们可以从数据表的设计入手,将虚拟出来的父层级索引字符串列增加到数据表中,将该列创建为聚集索引, 便于提高查询性能。
IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE OBJECT_ID = OBJECT_ID(N'dbo.MyEmp', N'U') AND name = N'HierarchyIndex')
BEGIN
ALTER TABLE dbo.MyEmp ADD HierarchyIndex VARCHAR(800) NOT NULL CONSTRAINT DF_MyEmp_HierarchyIndex DEFAULT '';
END
GO
如果该列创建为聚集且唯一,则相应的T-SQL脚本如下:
-- 删除外键
IF OBJECT_ID(N'FK_MyEmp_MyEmp_ParentID', N'F') IS NOT NULL
BEGIN
ALTER TABLE dbo.MyEmp DROP CONSTRAINT FK_MyEmp_MyEmp_ParentID;
END
GO -- 删除主键
IF OBJECT_ID(N'PK_U_CL_MyEmp_MyEmpID', N'PF') IS NULL
BEGIN
ALTER TABLE dbo.MyEmp DROP CONSTRAINT PK_U_CL_MyEmp_MyEmpID;
END
GO -- 创建(唯一:语义分析得到的,没有使用创建UNIQUE关键字)聚集索引
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE OBJECT_ID = OBJECT_ID(N'dbo.MyEmp', N'U') AND name = N'IX_U_CL_MyEmp_HierarchyIndex')
BEGIN
CREATE CLUSTERED INDEX IX_U_CL_MyEmp_HierarchyIndex ON dbo.MyEmp
(
HierarchyIndex ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90)
END
GO -- 创建主键且非聚集索引
IF OBJECT_ID(N'PK_U_CL_MyEmp_MyEmpID', N'PK') IS NULL
BEGIN
ALTER TABLE [dbo].[MyEmp] ADD CONSTRAINT [PK_U_NCL_MyEmp_MyEmpID] PRIMARY KEY NONCLUSTERED
(
[MyEmpID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90)
ON [PRIMARY];
END
GO -- 创建外键
IF OBJECT_ID(N'FK_MyEmp_MyEmp_ParentID', N'F') IS NULL
BEGIN
ALTER TABLE dbo.MyEmp ADD CONSTRAINT FK_MyEmp_MyEmp_ParentID FOREIGN KEY (ParentID) REFERENCES dbo.MyEmp (MyEmpID);
END
GO
同步HierarchyIndex字段列值的T-SQL如下:
;WITH tData (MyEmpID, HierarchyIndex) AS (
-- 基准点查询
SELECT MyEmpID, CAST(CONCAT(',', ISNULL(ParentID, 0), ',', MyEmpID, ',') AS VARCHAR(300)) AS HierarchyIndex
FROM dbo.MyEmp
WHERE ParentID IS NULL
-- 递归查询
UNION ALL
SELECT T.MyEmpID, CAST(CONCAT(T2.HierarchyIndex, T.MyEmpID, ',') AS VARCHAR(300)) AS HierarchyIndex
FROM dbo.MyEmp AS T /*子表*/
INNER JOIN tData AS T2 /*父表*/
ON T.ParentID = T2.MyEmpID
) --SELECT T.*
UPDATE T2
SET T2.HierarchyIndex = T.HierarchyIndex
FROM tData AS T
INNER JOIN dbo.MyEmp AS T2
ON T.MyEmpID = T2.MyEmpID
WHERE T2.HierarchyIndex = '';
GO
使用以下T-SQL验证数据是否已经修改:
1 SELECT MyEmpID, ParentID, MyEmpName, HoursSalary, HierarchyIndex
2 FROM dbo.MyEmp;
3 GO
解决该问题的解决方案的T-SQL语句如下:
SELECT T.MyEmpID, T.ParentID, T.MyEmpName, T.HoursSalary, T.HierarchyIndex, T2.TotalSalary AS TotalSalary
FROM dbo.MyEmp AS T
CROSS APPLY (SELECT SUM(HoursSalary) AS TotalSalary FROM dbo.MyEmp WHERE HierarchyIndex LIKE CONCAT(T.HierarchyIndex, '%')) AS T2;
GO
一个有趣的SQL Server 层级汇总数据问题的更多相关文章
- Sql Server系列:数据表操作
表是用来存储数据和操作数据的逻辑结构,用来组织和存储数据,关系数据库中的所有数据都表现为表的形式,数据表由行和列组成.SQL Server中的数据表分为临时表和永久表,临时表存储在tempdb系统数据 ...
- sql server 随机读取数据
--sql server 随机读取数据 * FROM [tablename] ORDER BY NEWID() pk from [tablename] ORDER BY NEWID()) --这两个方 ...
- sql server 与oracle数据互导的一种思路--sql server链接服务器
思路:通过在sql server数据库中添加链接服务器,可以远程查询oracle数据库的表环境准备,安装sql server数据库,并安装好oracle驱动,在配置好tnsname文件中配置好orac ...
- 最简单删除SQL Server中所有数据的方法
最简单删除SQL Server中所有数据的方法 编写人:CC阿爸 2014-3-14 其实删除数据库中数据的方法并不复杂,为什么我还要多此一举呢,一是我这里介绍的是删除数据库的所有数据,因为数据之间 ...
- 一个有趣的 SQL 查询(查询7天连续登陆)
一个有趣的 SQL 查询 一个朋友有这样一个SQL查询需求: 有一个登录表(tmp_test),包含用户ID(uid)和登录时间(login_time).表结构如下: . row ********** ...
- ASP.NET用SQL Server中的数据来生成JSON字符串
原文引自: 作者: 缺水的海豚 来源: 博客园 发布时间: 2010-09-21 21:47 阅读: 6136 次 推荐: 0 原文链接 [收藏] 摘要:ExtJs用到的数据内容基本 ...
- SQL Server :理解数据记录结构
原文:SQL Server :理解数据记录结构 在SQL Server :理解数据页结构我们提到每条记录都有7 bytes的系统行开销,那这个7 bytes行开销到底是一个什么样的结构,我们一起来看下 ...
- SQL Server :理解数据页结构
原文:SQL Server :理解数据页结构 我们都很清楚SQL Server用8KB 的页来存储数据,并且在SQL Server里磁盘 I/O 操作在页级执行.也就是说,SQL Server 读取或 ...
- 01. SQL Server 如何读写数据
原文:01. SQL Server 如何读写数据 一. 数据读写流程简要SQL Server作为一个关系型数据库,自然也维持了事务的ACID特性,数据库的读写冲突由事务隔离级别控制.无论有没有显示开启 ...
随机推荐
- HDU 4283---You Are the One(区间DP)
题目链接 http://acm.split.hdu.edu.cn/showproblem.php?pid=4283 Problem Description The TV shows such as Y ...
- Scalaz(3)- 基础篇:函数概括化-Generalizing Functions
Scalaz是个通用的函数式编程组件库.它提供的类型.函数组件都必须具有高度的概括性才能同时支持不同数据类型的操作.可以说,scalaz提供了一整套所有编程人员都需要的具有高度概括性的通用函数,它是通 ...
- android 歌词解析
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.F ...
- Lucene.net站内搜索—1、SEO优化
目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...
- Python的sorted函数应用
sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序 L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88) ...
- Servlet获取request的变量方法.
1.String localAddr = request.getLocalAddr(); // 获取本地IP,即服务器 IP 2.setAttribute(String name,Object ...
- 使用React并做一个简单的to-do-list
1. 前言 说到React,我从一年之前就开始试着了解并且看了相关的入门教程,而且还买过一本<React:引领未来的用户界面开发框架 >拜读.React的轻量组件化的思想及其virtual ...
- 3种不同的ContextMenu右键菜单演示
简单使用的右键菜单,希望能帮助大家.下面是截图和实例代码 实例预览 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional/ ...
- pagePiling.js - 创建漂亮的全屏滚动效果
全屏滚动效果是最近非常流行的网页设计形式,带给用户良好的视觉和交互体验.pagePiling.js 这款 jQuery 插件可以帮助前端开发人员轻松实现这种效果.支持所有的主流浏览器,包括IE8+,支 ...
- Charted – 自动化的可视化数据生成工具
Charted 是一个让数据自动生成可视化图表的工具.只需要提供一个数据文件的链接,它就能返回一个美丽的,可共享的图表.Charted 不会存储任何数据.它只是获取和让链接提供的数据可视化. 在线演示 ...