今天偶尔看到sql中也有with关键字,好歹也写了几年的sql语句,居然第一次接触,无知啊。看了一位博主的文章,自己添加了一些内容,做了简单的总结,这个语句还是第一次见到,学习了。我从简单到复杂地写,希望高手们不要见笑。下面的sql语句设计到三个表,表的内容我用txt文件复制进去,这里不妨使用上一个随笔介绍的建立端到端的package的方法将这些表导入到数据库中,具体的就不说了。

从这里下载文件employees.txt,customers.txt,orders.txt

参考文章:http://www.cnblogs.com/wwan/archive/2011/02/24/1964279.html

使用package导入数据:http://www.cnblogs.com/tylerdonet/archive/2011/04/17/2017471.html

简单的聚合

从orders表中选择各个年份共有共有多少客户订购了商品

第一种写法,我们可以写成这样
1select YEAR(o.orderdate) orderyear,COUNT(distinct(custid)) numCusts
2from Sales.Orders o
3group by YEAR(o.orderdate)
4go
要注意的是如果把group by YEAR(o.orderdata)换成group by orderyear就会出错,这里涉及到sql语句的执行顺序问题,有时间再了解一下          
第二种写法,
1select orderyear,COUNT(distinct(custid))numCusts
2from (select YEAR(orderdate) as orderyear,custid from sales.orders) as D
3group by orderyear
4go
在from语句中先得到orderyear,然后再select语句中就不会出现没有这个字段的错误了
第三种写法,
1select orderyear,COUNT(distinct(custid)) numCusts
2from (select YEAR(orderdate),custid from sales.orders) as D(orderyear,custid)
3group by orderyear
4go
在as D后面加上选择出的字段,是不是更加的清楚明了呢!
第四种写法,with出场了
1with c as(
2select YEAR(orderdate) orderyear, custid from sales.orders)
3select orderyear,COUNT(distinct(custid)) numCusts from c group by orderyear
4go
with可以使语句更加的经凑,下面是权威解释。  
    
指定临时命名的结果集,这些结果集称为公用表表达式 (CTE)。该表达式源自简单查询,并且在单条 SELECT、INSERT、UPDATE、MERGE 或 DELETE 语句的执行范围内定义。该子句也可用在 CREATE VIEW 语句中,作为该语句的 SELECT 定义语句的一部分。公用表表达式可以包括对自身的引用。这种表达式称为递归公用表达式。               
                                                ----MSDN

第五种写法,也可以借鉴第三种写法,这样使语句更加清楚明了,便于维护
1 with c(orderyear,custid) as(
2 select YEAR(orderdate),custid from sales.orders)
3 select orderyear,COUNT(distinct(custid)) numCusts from c group by c.orderyear
4 go
上面5中写法都得到相同的结果,如下图1:图1
添加计算

现在要求要求计算出订单表中每年比上一年增加的客户数目,这个稍微复杂
复制代码
1 with yearcount as(
2 select YEAR(orderdate) orderyear,COUNT(distinct(custid)) numCusts from sales.orders group by YEAR(orderdate))
3 select cur.orderyear curyear,cur.numCusts curNumCusts,prv.orderyear prvyear,prv.numCusts prvNumCusts,cur.numCusts-prv.numCusts growth
4 from yearcount cur left join yearcount prv on cur.orderyear=prv.orderyear+1
5 go
复制代码
这里两次使用到with结果集。查询得到的结果如下图2

图2
复杂的计算

查找客户id,这些客户和所有来自美国的雇员至少有一笔交易记录,查询语句如下
复制代码
1 with TheseEmployees as(
2 select empid from hr.employees where country='USA'),
3 CharacteristicFunctions as(
4 select custid,
5 case when custid in (select custid from sales.orders as o where o.empid=e.empid) then 1 else 0 end as charfun
6 from sales.customers as c cross join TheseEmployees as e)
7 select custid,min(charfun) from CharacteristicFunctions group by custid having min(charfun)=1
8 go
复制代码
这里嵌套with语句,第with语句查找美国雇员的id,第二个语句使用这个结果和拥有客户的客户id和拥有关系标识做笛卡尔积运算。最后从这个笛卡尔积中通过标识找到最终的custid。
结果如下图3

图3
这里只有简单地介绍,没有深入,高手们不要见笑啊。

---------------------------------------------------------分界线----------------------------------------------------------

with语句和子查询的性能比较

在博友SingleCat的提醒下,对with语句做一些性能测试,这里使用的测试工具是SQL Server Profile。我选择了最后一个语句,因为这个语句比较复杂一点。开始的时候单独执行一次发现他们的差别不大,就差几个毫秒,后来想让他们多执行几次,连续执行10

次看看执行的结果。下面贴出测试用的语句。

复制代码
1 /*with查询*/
2 declare @withquery varchar(5000)
3 declare @execcount int=0
4 set @withquery='with TheseEmployees as(
5 select empid from hr.employees where country=N''USA''),
6 CharacteristicFunctions as(
7 select custid,
8 case when custid in (select custid from sales.orders as o where o.empid=e.empid) then 1 else 0 end as charfun
9 from sales.customers as c cross join TheseEmployees as e)
10 select custid from CharacteristicFunctions group by custid having min(charfun)=1 order by custid
11 '
12 while @execcount<10
13 begin
14 exec (@withquery);
15 set @execcount=@execcount+1
16 end
17
18 /*子查询*/
19 declare @subquery varchar(5000)
20 declare @execcount int=0
21 set @subquery='select custid from Sales.Orders where empid in
22 (select empid from HR.Employees where country = N''USA'') group by custid
23 having count(distinct empid)=(select count(*) from HR.Employees where country = N''USA'');
24 '
25 while @execcount<10
26 begin
27 exec (@subquery);
28 set @execcount=@execcount+1
29 end
复制代码
从SQL Server Profile中截图如下

从图中可以看到子查询语句的执行时间要少于with语句,我觉得主要是with查询中有一个cross join做了笛卡尔积的关系,于是又实验了上面的那个简单一点的,下面是测试语句。

复制代码
1 /*with语句*/
2 declare @withquery varchar(5000)
3 declare @execcount int=0
4 set @withquery='with c(orderyear,custid) as(
5 select YEAR(orderdate),custid from sales.orders)
6 select orderyear,COUNT(distinct(custid)) numCusts from c group by c.orderyear'
7 while @execcount<100
8 begin
9 exec (@withquery);
10 set @execcount=@execcount+1
11 end
12
13 /*子查询*/
14 declare @subquery varchar(5000)
15 declare @execcount int=0
16 set @subquery='select orderyear,COUNT(distinct(custid)) numCusts
17 from (select YEAR(orderdate),custid from sales.orders) as D(orderyear,custid)
18 group by orderyear'
19 while @execcount<100
20 begin
21 exec (@subquery);
22 set @execcount=@execcount+1
23 end
复制代码

这次做10次查询还是没有多大的差距,with语句用10个duration,子查询用了11个,有时候还会翻过来。于是把执行次数改成100,这次还是子查询使用的时间要少,截图如下

最终结论,子查询好比with语句效率高。

来源:http://www.cnblogs.com/tylerdonet/archive/2011/04/18/2020225.html

使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比的更多相关文章

  1. SQL点滴10—使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比

    原文:SQL点滴10-使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比 今天偶尔看到sql中也有with关键字,好歹也写了几年的sql语句,居然第一次接触,无知啊.看了一位博主的文章 ...

  2. 理解SQL原理,写出高效的SQL语句

    我们做软件开发的,大部分人都离不开跟数据库打交道,特别是erp开发的,跟数据库打交道更是频繁,存储过程动不动就是上千行,如果数据量大,人员流动大,那么我们还能保证下一段时间系统还能流畅的运行吗?我们还 ...

  3. tp5 r3 一个简单的SQL语句调试实例

    tp5 r3 一个简单的SQL语句调试实例先看效果核心代码 public function index() { if (IS_AJAX && session("uid&quo ...

  4. 题目:写出一条SQL语句,查询工资高于10000,且与他所在部门的经理年龄相同的职工姓名。

    create table Emp( eid char(20) primary key, ename char(20), age integer check (age > 0), did char ...

  5. 在数据表中添加一个字段的SQL语句怎么写

    如果要在数据表中添加一个字段,应该如何表示呢?下面就为您介绍表添加字段的SQL语句的写法,希望可以让您对SQL语句有更深的认识.   通用式: alter table [表名] add [字段名] 字 ...

  6. 写了一个复杂的sql语句

    $sp_sql = "select sp_ProductNo, sp_ProductName,sp_Standard,sp_Unit,sum(sp_Amount) as amount fro ...

  7. mysql从一个表中拷贝数据到另一个表中sql语句

    这一段在找新的工作,今天面试时,要做一套题,其中遇到这么一句话,从一个表中拷贝所有的数据到另一个表中的sql是什么? 原来我很少用到,也没注意过这个问题,面试后我上网查查,回来自己亲手写了写,测试了下 ...

  8. mysql 通过慢查询日志查写得慢的sql语句

    MySQL通过慢查询日志定位那些执行效率较低的SQL 语句,用--log-slow-queries[=file_name]选项启动时,mysqld 会写一个包含所有执行时间超过long_query_t ...

  9. 子查询注意这几点, 就可以写出好的sql语句

    执行sql时子查询的语句一般优先执行 理论上多表查询效率是高于子查询(根据子查询不值一个查询语句可能会有多个from但是多表查询只产生一个from), 但是在oracle中子查询效率一般会高于多表查询

随机推荐

  1. android学习——android架构

    android架构:在了解全局的情况下进行细致化的分析才能更有效的学习android的运行原理,才能更深刻的理解android开发: 1.架构图直观 2.架构详解 2.1.Linux Kernel 2 ...

  2. Service Oriented Architecture and WCF 【转】

    http://www.codeproject.com/Articles/515253/Service-Oriented-Architecture-and-WCF Introduction This a ...

  3. ARM学习笔记5——程序状态寄存器

    当前程序状态寄存器CPSR可以在任何位处理器模式下被访问,它包含条件码标志.中断控制.当前处理器模式以及其他状态和控制信息.CPSR的结构图如下: 一.条件标志位 CPSR最高4位:N(Negativ ...

  4. HTML5 Canvas核心技术—图形、动画与游戏开发.pdf2

    事件处理: HTML5应用程序是以事件来驱动的,可以在canvas中增加一个事件监听器,当事件发生时,浏览器就会调用这个监听器 //方法一canvas.onmousedown=function(e){ ...

  5. WCF、.Net Remoting、Web Service概念及区别

    此文章主要参考http://www.cnblogs.com/weiweibtm/archive/2013/06/21/3148583.html 参考书籍<WCF全面解析上册>.<WC ...

  6. vmware10安装win8x64(亲测)

    首先,创建虚拟机,选择典型 下一步后 弄完后选择“完成”,这下就可以安装了 之后分区,之后选cdrom做启动,之后安装win8到第一分区

  7. unity3d中namespace的使用注意问题

    最近在重构游戏中的老一套逻辑,同时要加入新的功能逻辑,因为各种命名问题,就使用namespace进行控制.但是namespace在unity3d引擎中的使用与一般不同,需要注意一点:要作为Compon ...

  8. NPOI组件集锦

    关于NPOI不错的介绍:http://www.cnblogs.com/restran/p/3889479.html http://www.cnblogs.com/Irving/archive/2012 ...

  9. 【剑指Offer学习】【面试题40:数组中仅仅出现一次的数字】

    题目:一个整型数组里除了两个数字之外.其它的数字都出现了两次,请敲代码找出这两个仅仅出现一次的数字. 要求时间复杂度是O(n),空间复杂度是O(1). 举例说明 比如输入数组{2, 4, 3, 6, ...

  10. 解析xlsx与xls--使用2012poi.jar

    1.导入Jar包:poi-3.8-20120326.jar.poi-ooxml-3.8-20120326.jar.poi-ooxml-schemas-3.8-20120326.jar.xbean.ja ...