一.写在前面的话

时间是我们每个人都特别熟悉的,但是到底它是什么,用什么来衡量,可能很多人会愣在那里。时间可以见证一切,也可以消磨一切,那些过往的点点滴滴可思可忆。回想往年清明节过后,在家乡的晚上总能听见阵阵的青蛙叫声,那是清脆的叫声,那是家乡的味道。时间一转眼,貌似那些日子已离我远去好久,在城市的喧嚣浮华中,找寻不到那种内心的宁静。感叹时间流逝的同时,怀念过去的点点滴滴。我想在繁华的都市中寻找一种安定的心情来学习,或许是一种不错的方式。学习才会让我们认清自己,找回自我,做内心的强者,不骄不躁,积极进取,阳光自信。努力的人最幸运!Just do it!

从今以后,别再过你应该过的人生,去过你想过的人生吧!——梭罗

二.派生表

派生表也就是特殊的子查询,用在from之后的子查询,同时这里注意一点:派生表必须起别名。

例如:加入我们要查询,顾客信息,以及每个国家所拥有的顾客数量。那么我们可以这样写:

  SELECT * FROM
(
SELECT custid,COUNT(*) OVER(PARTITION BY country) AS N'顾客数量'
FROM Sales.Customers
) t

括号里面的子句就相当于一个派生表,假如我们在这里不给 COUNT(*) OVER(PARTITION BY country) 起别名,那么select * 就不知道取出哪一列,所以会报错。

同时有另一种起别名的方法,也就是在外面其别名,同样可以达到效果,写法如下:

  SELECT * FROM
(
SELECT custid,COUNT(*) OVER(PARTITION BY country)
FROM Sales.Customers
) t(custid,顾客数量)

三.CTE(公用表表达式)

(1)常见CTE用法

如何使用CTE,在这里必须先定义,并且命名。定义形式如下:

  WITH USE_Customers
AS
(
SELECT companyname,country
FROM Sales.Customers
WHERE country='USA'
)

那么我们要使用CTE,只要查询对应的CTE名称即可。

  WITH USE_Customers
AS
(
SELECT companyname,country
FROM Sales.Customers
WHERE country='USA'
) SELECT * FROM USE_Customers

结果如图所示:

但是要注意的一点是:使用CTE时,外部查询一旦完成,那么CTE的生命期就结束了,如果需要在查询这个CTE,此时失效。

同时也可以给CTE每列其别名,其中也存在在表达式内部和外部起别名,看个人喜欢哪种方式。

  WITH USE_Customers
AS
(
SELECT companyname AS N'公司名',country AS N'国家名'
FROM Sales.Customers
WHERE country='USA'
) SELECT * FROM USE_Customers
  WITH USE_Customers(公司名,国家名)
AS
(
SELECT companyname ,country
FROM Sales.Customers
WHERE country='USA'
) SELECT * FROM USE_Customers

其查询结果都为:

(2)有参数的CTE

使用有参数的CTE可以多次使用,只需要改变参数的传递值即可。

例如:查询每个国家的顾客信息,国家存在USA,UK........,多个国家,此时我们将国家作为一个变量,类似于C#中的参数。声明CTE如下:

  DECLARE @country NVARCHAR();
SET @country='USA';
WITH USE_Customers(公司名,国家名)
AS
(
SELECT companyname ,country
FROM Sales.Customers
WHERE country=@country
) SELECT * FROM USE_Customers

假如要查询UK国家的一些顾客信息,那么只需要改变set @country=‘UK’就可以查询了,不需要改变CTE的结构。

  DECLARE @country NVARCHAR();
SET @country='UK';
WITH USE_Customers(公司名,国家名)
AS
(
SELECT companyname ,country
FROM Sales.Customers
WHERE country=@country
) SELECT * FROM USE_Customers

(3)复杂的CTE使用

【1】在这里,假如我们要查询年度订单数量在10以上的顾客信息。按照一般的思维,我们可以讲订单按照年度分组,然后用聚合函数count统计每个顾客下的订单数量,接着找出大于订单数量大于10的顾客信息。所以我们可以下sql如下:

查询结果如图所示:

【2】那么同时可以使用子查询,即派生表依次来出来问题。

第一步,先查询订单的年份,顾客的信息

  SELECT  YEAR(orderdate) AS orderyear,custid
FROM Sales.Orders

第二步,根据年份进行分组,统计每位顾客的订单数量。第一步查询出来的结果作为子查询,即派生表。

  SELECT orderyear,custid,COUNT(*) AS N'订单数量'
FROM
(
SELECT YEAR(orderdate) AS orderyear,custid
FROM Sales.Orders
) AS t1
GROUP BY orderyear,custid

第三步,找出订单数量大于10的顾客信息。

  SELECT orderyear,custid,ordercount
FROM
(
SELECT orderyear,custid,COUNT(*) AS ordercount
FROM
(
SELECT YEAR(orderdate) AS orderyear,custid
FROM Sales.Orders
) AS t1
GROUP BY orderyear,custid
) AS t2
WHERE ordercount >

是不是感觉使用子查询,一层套一层,不过分析以后,符合我们一般解决问题的思路先做哪一步,再做哪一步。在这里我们可以使用新学的CTE来解决问题。

【3】使用CTE来解决年度订单数量在10以上的顾客信息。

好处就是定义好的CTE,可以直接拿来作为一个派生表使用,那么我们可以这样定义CTE,按照上述的分析,分别定义三个CTE,最后查询出结果:

需要注意的一点事:定义多个CTE之间用逗号(,)隔开即可,不需要使用with重新定。

  WITH yearorder01
AS
(
SELECT YEAR(orderdate) AS orderyear,custid
FROM Sales.Orders
),
yearorder02
AS
(
SELECT orderyear,custid,COUNT(*) AS ordercount
FROM yearorder01
GROUP BY orderyear,custid
),
yearorder03
AS
(
SELECT orderyear,custid,ordercount
FROM yearorder02
WHERE ordercount>
) SELECT * FROM yearorder03

查询结果如图所示,跟子查询结果相同:

四.多CTE

多个CTE的使用会让我们更加方便的进行相关子查询。例如:假如我们要查询年度有多少顾客,测试该怎么处理了?我们会想到,还是根据年度分组,然后聚合count(custid)求出每年度有多少顾客,其中要注意去重,即相同的custid属于同一个顾客,所以要写成count(distinct custid)。sql如下:

  SELECT YEAR(orderdate) AS orderyear,COUNT(DISTINCT custid) AS  custcount
FROM Sales.Orders
GROUP BY YEAR(orderdate)

现在加入有一个需求,就是要做一个查询,求出当年的顾客数量以及前一年的顾客数量,同时算出两者之间顾客数量隔了多少,我们又该怎么处理了?要求前一年和当前年的差,那么就可以想到,是否可以把当前查出来的结果集做一次连接,不就可以得到前一年和当前年的嘛,所以sql如下:

  SELECT pre_orderyear,now_orderyear,pre_custcount,now_custcount,
(now_custcount-pre_custcount) AS N'顾客数量差'
FROM
(
SELECT YEAR(orderdate) AS now_orderyear,COUNT(DISTINCT custid) AS now_custcount
FROM Sales.Orders
GROUP BY YEAR(orderdate)
) AS t1
LEFT JOIN
(
SELECT YEAR(orderdate) AS pre_orderyear,COUNT(DISTINCT custid) AS pre_custcount
FROM Sales.Orders
GROUP BY YEAR(orderdate)
) AS t2
ON t1.now_orderyear=t2.pre_orderyear+;

其中就是将结果集做一个自身的连接,但是我们是不是发现这样写显得很冗余了,作为程序猿的我们就是要写出尽量简洁明了的code,Don‘t  repeat yourself !在这里我们的CTE就发挥出他的作用,定义的CTE可以在下一步中使用,作为查询条件。那么我们看看用CTE如何实现?同理,我们使用CTE之前就必须先定义CTE,这里我们定义一个CTE,查询出每年的顾客数量,其实跟上面的sql一样,只不过定义成CTE的形式。

  WITH custcount
AS
(
SELECT YEAR(orderdate) AS orderyear,COUNT(DISTINCT custid) AS custcount
FROM Sales.Orders
GROUP BY YEAR(orderdate)
) SELECT t1.orderyear AS nowYear,t2.orderyear AS preYear,t1.custcount AS nowcount,t2.custcount AS precount,
(t1.custcount-t2.custcount) AS N'顾客数量差'
FROM custcount t1
LEFT JOIN custcount t2
ON t1.orderyear=t2.orderyear+;

其结果如图所示:

其实我们从sql语句可以看出,CTE的简洁之处,就在于,可以将已定义的CTE重复使用进行连接,相比于子查询自身的连接,更加简洁,容易操作,加入需要的计算,我们只需要改变CTE的定义即可。

五.递归CTE

递归的CTE在递归查找中应用的非常多,其实可以看做一种层次的查找关系,比如公司一般情况下是分一级部门,二级部门,三级部门.......那么一级部门下包含多个二级部门,二级部门又包含多个三级部门等等.....,举例说明:公司内部有上下级的关系,假如我们要查找某个员工的上级是谁,一般情况下我们可以做一次自身的连接,找出上级是谁。

例如:查找所有顾客的上级信息。也就是在HR.employees里面的mgrid等于员工的empid,那么找到的那个员工几位mgrid的上司。sql如下:

  SELECT t1.empid,t1.mgrid,t1.lastname,t2.empid,t2.lastname
FROM HR.Employees t1 LEFT JOIN hr.Employees t2
ON t1.mgrid =t2.empid

因为为了确保所有的员工信息都显示,所以在这里用到饿左连接,保证左边表里面的员工都存在。其结果如图:

这里再进一步讨论,加入我们要查询某个员工下面所有的下属信息,怎么办了?比如要查询2号员工的下属信息,我们这可以这样写sql:

  SELECT * FROM
hr.Employees WHERE mgrid=

我们了可以看到2号员工下属有3号和5号,那么5号员工可能也有下属,接着查询:

  SELECT * FROM HR.Employees
WHERE mgrid in
(SELECT empid FROM
hr.Employees WHERE mgrid=
)

我们可以看到,查出的结果中有4,6,7,8,9,那么4,6,7,8,9下面是否还有下属了,是不是还需要接着查询了,这样查下去就是无止尽的,因为我们不知道有多少层,所以递归CTE就是解决这样的问题的,递归CTE可以查询出所以层级的情况,直至结束。首先递归CTE需要定义一个起点,即查询起点。然后根据定义的CTE自身做递归查询,直至找出所有的节点信息。如下:

 DECLARE @mgrid INT;
SET @mgrid=;
WITH Emplist
AS
(
--此处为起点,执行一次
SELECT empid,lastname,mgrid
FROM HR.Employees
WHERE mgrid=@mgrid
UNION ALL --递归开始 SELECT e.empid,e.lastname,e.mgrid
FROM HR.Employees e INNER JOIN Emplist m
ON e.mgrid=m.empid ) SELECT * FROM Emplist

定义一个变量,接受要查询的员工id,设为2,即查询2号员工下面所有的下属信息。

关于CTE的运用还有很多,这里只列出一些基本的用法,如有想法,可以提出,希望一起学习!

sqlserver学习笔记1:http://www.cnblogs.com/liupeng61624/p/4354983.html

sqlserver学习笔记2:http://www.cnblogs.com/liupeng61624/p/4367580.html

sqlserver学习笔记3:http://www.cnblogs.com/liupeng61624/p/4375135.html

sqlserver学习笔记4:http://www.cnblogs.com/liupeng61624/p/4388959.html

sqlserver学习笔记5:http://www.cnblogs.com/liupeng61624/p/4392746.html

希望各位大牛给出指导,不当之处虚心接受学习!谢谢!

SQLServer学习笔记系列6的更多相关文章

  1. SQLServer学习笔记系列3

    一.写在前面的话 今天又是双休啦!生活依然再继续,当你停下来的时候,或许会突然显得不自在.有时候,看到一种东西,你会发现原来在这个社会上,优秀的人很多,默默 吃苦努力奋斗的人也多!星期五早上按时上班, ...

  2. SQLServer学习笔记系列2

    一.写在前面的话 继上一次SQLServer学习笔记系列1http://www.cnblogs.com/liupeng61624/p/4354983.html以后,继续学习Sqlserver,一步一步 ...

  3. SQLServer学习笔记系列5

    一.写在前面的话 转眼又是一年清明节,话说“清明时节雨纷纷”,武汉的天气伴随着这个清明节下了一场暴雨,整个城市如海一样,朋友圈渗透着清明节武汉看海的节奏.今年又没有回老家祭祖,但是心里依然是怀念着那些 ...

  4. SQLServer学习笔记系列1

    一.前言 一直自己没有学习做笔记的习惯,所以为了加强自己对知识的深入理解,决定将学习笔记写下来,希望向各位大牛们学习交流! 不当之处请斧正!在此感谢!这边就先从学习Sqlserver写起,自己本身对数 ...

  5. SQLServer学习笔记系列4

    一.写在前面的话 好多天没有记录sql学习笔记了,要坚持下去,坚信每一点的进步都是为在积蓄力量.今天看到一幅图,特此分享出来. 通过这幅图,我看到的是每人站在自己的角度看问题,感受是不一样的,就如同学 ...

  6. SQLServer学习笔记系列12

    一.写在前面的话 这个sql学习系列,今天准备告一段落,虽然短短的十几篇文章,深刻感受到将学习的东西记录下来,是需要一种坚持! 这些东西只有反复的学习吸收,最终沉淀下来的才是属于自己的知识.也是提醒自 ...

  7. SQLServer学习笔记系列11

    一.写在前面的话 身体是革命的本钱,这句放在嘴边常说的话,还是拿出来一起共勉,提醒一起奋斗的同僚们,保证睡眠,注意身体!偶尔加个班,也许不曾感觉到身体发出的讯号,长期晚睡真心扛不住!自己也制定计划,敦 ...

  8. SQLServer学习笔记系列10

    一.写在前面的话 生活的路很长,还是要坚持走下去,自己选择的生活,就该让这样的生活放射精彩!我不奢求现在的积累,在将来能够收获多少,至少在以后的日子里回忆起来,我不曾放弃过,我坚持过,我不后悔!最近跟 ...

  9. SQLServer学习笔记系列8

    一.写在前面的话 最近一直在思考一个问题,什么才能让我们不显得浮躁,真正的静下心来,用心去感受,用心去回答每个人的问题,用心去帮助别人.现实的生活,往往让我们显得精疲力尽,然后我们仔细想过没用,其实支 ...

随机推荐

  1. samba server install

    要求: create vnc service for win7 access it via vnc viewer. 1TB disk for this Centos PC is used as Sam ...

  2. MyEclipse 自带的TomCat 新增部署的时候不显示 Deploy Location

    项目总是报错,添了删,删了又添了N次以后,发现添加部署的时候,Deploy Location 没有值了,Deploy Location 没有值在自带的Tomcat上就无法用浏览器浏览(Open in ...

  3. 【转载】关于.NET里的内存泄漏

    所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中..Net 中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动被垃圾回收器从内存中清除掉.虽然.N ...

  4. static关键字作用总结

    之前讲到final关键字的作用是每次面试的时候我必问求职者的两个问题之一,另外一个问题就是文本会写到的static.final和static一样,都是一个小问题可以看到一个人的基础是否扎实以及平时是否 ...

  5. 团队项目——站立会议DAY7

    第七次站立会议记录: 参会人员:张靖颜,钟灵毓秀,何玥,赵莹,王梓萱 项目进展: 1.张靖颜:对功能模块代码进行近一步的审查和辅助,并对出错处进行修改和完善. 2.钟灵毓秀:对代码近一步的修改,将各个 ...

  6. 【读书笔记】Html5游戏开发

    一直对HMTL5做游戏饶有兴趣,而这本书刚好就是HTML5 2游戏初级入门的书.Demo简单注释详细,可以拿来练练手,一个星期左右就可以读完.若要追求酷炫高大上效果,这本书恐怕要让你失望了.但作为上手 ...

  7. 如何捕获和分析 JavaScript Error

    前端工程师都知道 JavaScript 有基本的异常处理能力.我们可以 throw new Error(),浏览器也会在我们调用 API 出错时抛出异常.但估计绝大多数前端工程师都没考虑过收集这些异常 ...

  8. 客户端GUI程序开发漫谈

    这篇文章包含了这个领域的很多开源项目的介绍,还有我多年来的心血和汗水  去年夏天的时候,我用QT做了一个小工具 后来还用QT做了流程设计器 我把程序分享给飞扬青云之后,他甚至搞出来一套QT的皮肤来 说 ...

  9. [.net 面向对象编程基础] (22) 事件

    [.net 面向对象编程基础] (22)  事件 事件(Event)是学习.net面向对象编程很重要的一部分,在学习事件之前,我们实际上已经在很多地方使用了事件,比如控件的click事件等,这些都是. ...

  10. 跟我一起云计算(4)——lucene

    了解lucene的基本概念 这一部分可以参考我以前写的博客: http://www.cnblogs.com/skyme/tag/lucene/ lucene是什么 下图是一个很好的说明: 1.luce ...