设为首页收藏本站

EPS数据狗论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 1347|回复: 0

sql server中的cte

[复制链接]

19

主题

162

金钱

253

积分

入门用户

发表于 2019-9-24 16:16:48 | 显示全部楼层 |阅读模式

从SQL Server 2005开始,提供了CTE(Common Table Expression,公用表表达式)的语法支持。

CTE是定义在SELECT、INSERT、UPDATE或DELETE语句中的临时命名的结果集,同时CTE也可以用在视图的定义中。

在CTE中可以包括对自身的引用,因此这种表达式也被称为递归CTE。

CTE的优点

公用表表达式提供的功能其实和视图差不多,但是它不像视图一样把SQL语句保存在我们的数据库里面。

微软官方给出的使用CTE的优势:

1.可以编写一个递归查询。

2.要使用一个类似视图的功能,但是又不想把这个查询SQL语句的定义保存到数据库中。

3.要引用一个返回数据的SQL语句多次,只需要定义一次。

使用CTE可以把复杂的SQL语句按照逻辑分成简单独立的几个公用表表达式(CTE),这样的最大优势就是能够提高SQL语句的可读性和可维护性。

总结就是,CTE主要可以用于树结构的递归和简化SQL语句,增加可读性和可维护性。

CTE的使用场景

由于业务需要,我们经常会写一些比较复杂的SQL语句,里面可能会包含很多的JOIN或子查询,要维护和理清这种N多个表的JOIN关系是一件非常头疼的事情,而使用CTE就可以使维护和理解复杂的SQL语句变得简单一些。

在开发的时候使用子查询,一般是这种情况:需要从一个复杂的子查询,甚至多级子查询嵌套。在这种情况下,在整个SQL语句里面,无论你是直接写SQL语句还是把这段SQL语句包装成子查询然后用别名来访问,当业务需求越来越变得复杂,你可能随时需要修改这个长且复杂的SQL语句段,而维护这种复杂的、可读性差的SQL语句简直是噩梦。

有了CTE只有,我们就可以使用CTE来定义一个SQL语句,并且为这个SQL语句执行后返回的结果集定义一个别名,接下来就可以通过这个别名来引用这些预先执行返回的数据集,就像使用普通的表一样。

CTE的语法
一个公用表表达式主要包含三个主要部分:

1.CET名称(WITH后面,列名列之前)。

2.列名列(可选)。

3.CET查询语句主体(AS后面括起来的内容)。
  1. with expression_name (column_name, …) as (
  2.     -- cte_query_definition cte查询语句定义
  3. )
复制代码

要注意的是,如果要定义多个表达式,需要用逗号分隔。

使用CTE进行多次查询
CTE是可以在跟随其后的查询中多次引用的。
  1. with tmp(id) as (
  2.     select id from users where name like '杨%';
  3. )
  4. select * from tmp;
  5. select * from orders where userId in (select id from tmp);
复制代码


使用CTE递归查询树形记录(向上查询父节点或向下查询子节点)
CTE有一个特性就是它是支持递归的,即在CTE的查询语句主体中引用自身。这一特性常常被用在查询树形记录。
  1. with subqry(id, pid, name) as (
  2.         select cb.id,
  3.             cb.pid,
  4.             cb.namefrom cb
  5.         where cb.id = '001001001'
  6.   
  7.         union all
  8.   
  9.         select cb.id,
  10.             cb.pid,
  11.             cb.namefrom cb, subqry
  12.         where cb.id = subqry.pid
  13. )
  14. select distinct *
  15. from subqry
复制代码

  1. with subqry(id, pid, name) as (
  2.         select cb.id,
  3.             cb.pid,
  4.             cb.name
  5.         from cb
  6.         where cb.id = '001'
  7.   
  8.         union all
  9.   
  10.         select cb.id,
  11.             cb.pid,
  12.             cb.name
  13.         from cb, subqry
  14.         where cb.pid = subqry.id
  15. )
  16. select distinct *
  17. from subqry
复制代码


使用CTE的注意事项

1.CTE后面必须紧跟着使用CTE的SQL语句,比如SELECT、INSERT和UPDATE等,否则CTE将失效(直接报错)。
  1. with tmp(id) as (
  2.     select id from users where favor = '牛奶';
  3. )
  4. select 1;
  5. select * from tmp;
复制代码

像上面的语句就会报【定义了公用表表达式,但没有使用】的错。

2.CTE后面也可以跟其他的CTE,但是只能使用一个WITH,多个CTE中间用逗号【,】隔开。
  1. with
  2. milk(id) as (
  3.     select id from users where favor = '牛奶';
  4. ),
  5. apple(id) as (
  6.     select id from users where favor = '苹果';
  7. )
  8. select id from milk, apple where milk.id = apple.id
复制代码


3.如果CTE表达式名称与某个实体表或者视图重名,则紧跟在该CTE后面的SQL语句使用的仍然是CTE。

要注意的是,后面再使用该同名就是使用实体表或视图了。

4.CTE可以引用自身,也可以引用在同一个WITH子句中预先定义的CTE,但是不允许前向引用(定义前使用)。

5.不能在CTE_QUERY_DEFINITION(CTE查询语句定义)中使用以下子句:

(1)COMPUTE或COMPUTE BY

(2)ORDER BY(除非指定了TOP 子句)

(3)INTO

(4)带有查询提示的OPTION 子句

(5)FOR XML

(6)FOR BROWSE

6.如果将CTE用于批处理的一部分的语句中,那么在它之前的语句必须以分号结尾。
  1. declare @id int
  2. set @id = 0; -- 这里必须以分号结尾
  3. ;with tmp(name) as ( -- 在with前加上分号避免出错
  4.     select name from users where unrequitedLove = '静静';
  5. )
  6. select * from tmp;
复制代码

当然了,一个良好的习惯(技巧)是在写CTE的时候统统在WITH前加上分号【;】,这样就能避免出错,比如上面的语句。

总结
如果经常写查询的话,比如一些统计分析或制作报表,CTE是会经常使用到的,因为使用起来十分方便,也几乎不会有什么副作用,在一定程度上能够提高开发和维护的效率。另外,其递归属性在树形记录的查询中的应用十分广泛,是一个要好好掌握的语法。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

客服中心
关闭
在线时间:
周一~周五
8:30-17:30
QQ群:
653541906
联系电话:
010-85786021-8017
在线咨询
客服中心

意见反馈|网站地图|手机版|小黑屋|EPS数据狗论坛 ( 京ICP备09019565号-3 )   

Powered by BFIT! X3.4

© 2008-2028 BFIT Inc.

快速回复 返回顶部 返回列表