在最近的活字格项目中使用ActiveReports报表设计器设计一个报表模板时,遇到一个多级分类的难题:需要将某个部门所有销售及下属部门的销售金额汇总,因为下属级别的层次不确定,所以靠拼接子查询的方式显然是不能满足要求,经过一番实验,利用了CTE(Common Table Expression)很轻松解决了这个问题!

举例:有如下的部门表

以及员工表

如果想查询所有西北区的员工(包含西北、西安、兰州),如下图所示:

如何用CTE的方式实现呢?

Talk is cheap. Show me the code

-- 以下代码使用SQLite 3.18.0 测试通过
WITH
[depts]([dept_id]) AS(
SELECT [d].[dept_id]
FROM [dept] [d]
JOIN [employees] [e] ON [d].[dept_id] = [e].[dept_id]
WHERE [e].[emp_name] = '西北-经理'
UNION ALL
SELECT [d].[dept_id]
FROM [dept] [d]
JOIN [depts] [s] ON [d].[parent_id] = [s].[dept_id]
)
SELECT *
FROM [employees]
WHERE [dept_id] IN (SELECT [dept_id]
FROM [depts]);

可能有些同学对CTE(Common Table Expression)还不太熟悉,这里简单说一下,有兴趣的同学可以google或者百度,介绍很多(这里以SQLite举例):

我还是更喜欢称CTE(Common Table Expression)为“公用表变量”而不是“公用表达式”,因为从行为和使用场景上讲,CTE更多的时候是产生(分迭代或者不迭代)结果集,供其后的语句使用(查询、插入、删除或更新),如上述的例子就是一个典型的利用迭代遍历树形结构数据。

CTE的优点:

  • 递归的特点使得原本需要使用临时表、存储过程才能完成的逻辑,通过SQL就可以完成,尤其针对一些树或者是图的数据模型
  • 因为是会话内的临时结果集,不需要去显示的声明或销毁
  • 改写后的SQL语句可读性提高(看的明白才能修改)
  • 给数据库引擎优化执行计划的可能性(这个不是肯定的,需要根据具体CTE的实现有关),优化了执行计划,自然地性能就能上升

为了更好的说明CTE的能力,这里附上两个例子(转自SQLite官网文档)

曼德勃罗集合(Mandelbrot set)

-- 以下代码使用SQLite 3.18.0 测试通过
WITH RECURSIVE
xaxis(x) AS (VALUES(-2.0) UNION ALL SELECT x+0.05 FROM xaxis WHERE x<1.2),
yaxis(y) AS (VALUES(-1.0) UNION ALL SELECT y+0.1 FROM yaxis WHERE y<1.0),
m(iter, cx, cy, x, y) AS (
SELECT 0, x, y, 0.0, 0.0 FROM xaxis, yaxis
UNION ALL
SELECT iter+1, cx, cy, x*x-y*y + cx, 2.0*x*y + cy FROM m
WHERE (x*x + y*y) < 4.0 AND iter<28
),
m2(iter, cx, cy) AS (
SELECT max(iter), cx, cy FROM m GROUP BY cx, cy
),
a(t) AS (
SELECT group_concat( substr(' .+*#', 1+min(iter/7,4), 1), '')
FROM m2 GROUP BY cy
)
SELECT group_concat(rtrim(t),x'0a') FROM a;

运行后的结果,如下图:(使用SQLite Expert Personal 4.2 x64)

数独问题(Sudoku)

假设有类似下图的问题:

-- 以下代码使用SQLite 3.18.0 测试通过
WITH RECURSIVE
input(sud) AS (
VALUES('53..7....6..195....98....6.8...6...34..8.3..17...2...6.6....28....419..5....8..79')
),
digits(z, lp) AS (
VALUES('', 1)
UNION ALL SELECT
CAST(lp+1 AS TEXT), lp+1 FROM digits WHERE lp<9
),
x(s, ind) AS (
SELECT sud, instr(sud, '.') FROM input
UNION ALL
SELECT
substr(s, 1, ind-1) || z || substr(s, ind+1),
instr( substr(s, 1, ind-1) || z || substr(s, ind+1), '.' )
FROM x, digits AS z
WHERE ind>0
AND NOT EXISTS (
SELECT 1
FROM digits AS lp
WHERE z.z = substr(s, ((ind-1)/9)*9 + lp, 1)
OR z.z = substr(s, ((ind-1)%9) + (lp-1)*9 + 1, 1)
OR z.z = substr(s, (((ind-1)/3) % 3) * 3
+ ((ind-1)/27) * 27 + lp
+ ((lp-1) / 3) * 6, 1)
)
)
SELECT s FROM x WHERE ind=0;

执行结果(结果中的数字就是对应格子中的答案)

附:SQLite中CTE(WITH关键字)语法图解:

WITH

cte-table-name

Select-stmt:

总结

CTE是解决一些特定问题的利器,但了解和正确的使用是前提,在决定将已有的一些SQL重构为CTE之前,确保对已有语句有清晰的理解以及对CTE足够的学习!Good Luck~~~

附件:用到的SQL脚本

相关阅读:

【报表福利大放送】100余套报表模板免费下载

新手逆袭!记我的第一次系统开发

菜鸟是如何在三天内完成系统开发的?

SQLite中使用CTE巧解多级分类的级联查询的更多相关文章

  1. 巧用string中的contains巧解一道题目

    题目:求0—7所能组成的奇数个数.假设最高八位数字. package edu.yuliang.lianxiti50; /* 题目:求0—7所能组成的奇数个数. *程序分析:最少也是1位数,最多能组成8 ...

  2. magento简化url多级分类去掉父目录

    在Magento模板开发中,有时候需要将多级分类的url简化,Magento的URL默认是显示多级分类的http://afish.cnblogs.com/分类1/分类2/分类3现在需要简化为:分类2的 ...

  3. EXCEL中多级分类汇总空白字段填充

    使用场景,多级分类汇总后,在汇总的字段中显示空白,这样对我们直接取值做表带来十分不更(假像有5000条记录,1000条汇总项) 相关技术,INDIRECT函数,单元格定位功能. 在数据区域外任意一个单 ...

  4. SQLServer中的CTE(Common Table Expression)通用表表达式使用详解

    概述 我们经常会编写由基本的 SELECT/FROM/WHERE 类型的语句派生而来的复杂 SQL 语句.其中一种方案是需要编写在 FROM 子句内使用派生表(也称为内联视图)的 Transact-S ...

  5. 解析SQLite中的常见问题与总结详解

    1. 创建数据如果不往数据库里面添加任何的表,这个数据库等于没有建立,不会在硬盘上产生任何文件,如果数据库已经存在,则会打开这个数据库. 2. 如何通过sqlite3.dll与sqlite3.def生 ...

  6. AngularJS select中ngOptions用法详解

    AngularJS select中ngOptions用法详解   一.用法 ngOption针对不同类型的数据源有不同的用法,主要体现在数组和对象上. 数组: label for value in a ...

  7. Android中Service(服务)详解

    http://blog.csdn.net/ryantang03/article/details/7770939 Android中Service(服务)详解 标签: serviceandroidappl ...

  8. (转)javascript中event对象详解

    原文:http://jiajiale.iteye.com/blog/195906 javascript中event对象详解          博客分类: javaScript JavaScriptCS ...

  9. 谈数据库索引和Sqlite中索引的使用

    要使用索引对数据库的数据操作进行优化,那必须明确几个问题:1.什么是索引2.索引的原理3.索引的优缺点4.什么时候需要使用索引,如何使用围绕这几个问题,来探究索引在数据库操作中所起到的作用. 1.数据 ...

随机推荐

  1. 3299: [USACO2011 Open]Corn Maze玉米迷宫

    3299: [USACO2011 Open]Corn Maze玉米迷宫 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 137  Solved: 59[ ...

  2. 九度OJ题目1443:Tr A (JAVA)

    题目描述: A为一个方阵,则Tr A表示A的迹(就是主对角线上各项的和),现要求Tr(A^k)%9973. 输入: 数据的第一行是一个T,表示有T组数据. 每组数据的第一行有n(2 <= n & ...

  3. Oracle物化视图,物化视图日志,增量刷新同步远程数据库

    1.创建DBLINK -- Drop existing database link drop public database link LQPVPUB; -- Create database link ...

  4. SQL基本用法-行转列

    /* SELECT <非透视的列>, [第一个透视的列] AS <列名称>, [第二个透视的列] AS <列名称>, ... [最后一个透视的列] AS <列 ...

  5. 10分钟精通SharePoint - SharePoint拓扑结构

    SharePoint服务器角色:前端,应用程序和数据库服务器 应用程序服务:搜索.Office文档.User Profile和App等应用服务器 数据库类型:内容数据库.应用程序数据库和配置数据库 规 ...

  6. android添加权限--eclipse

    首先进入清单文件 2.点击下面的permissions----Add 3.选择Uses permission-----OK 4.选择需要的权限 5.查看代码,,已经添加完毕

  7. python自学基础1week

    一.python老师介绍 二.为什么要学习python? 三.学习python有前途吗? 疗程1:语言基础 疗程2:网络编程 疗程3:web基础开发 疗程4:算法&设计模式 疗程5:pytho ...

  8. struts2(四) ognl表达式、值栈、actionContext之间的关系

    今天来说说ognl表达式在struts2中的运用. --wh 一.什么是Ognl? 通过百度百科查询到的解释,其中详细的说明了OGNL的作用. 下面我们就对OGNL这5个作用进行讲解 1.存取对象的任 ...

  9. Open-Falcon 监控系统监控 MySQL/Redis/MongoDB 状态监控

    背景: Open-Falcon 是小米运维部开源的一款互联网企业级监控系统解决方案,具体的安装和使用说明请见官网:http://open-falcon.org/,是一款比较全的监控.而且提供各种API ...

  10. 【2017-03-30】JS-document对象

    一.获取标记对象 1.document.getElementById("id");         根据id找,最多找到一个. 2.document.getElementsByNa ...