在sqlserver中如何使用CTE解决复杂查询问题

最近,同事需要从数个表中查询用户的业务和报告数据,写了一个SQL语句,查询比较慢:

Select
S.Name,
S.AccountantCode,
(
Select COUNT(*) from (
Select Distinct BusinessBackupId from Biz_BusinessBackupCustomer where Id in (
Select BusinessBackupCustomerId from Rpt_RegistForm where ( SignatureCPA1Id=S.Id or SignatureCPA2Id=S.Id ) and DocStatus=30
) ) T
) as 'BNum',
(case when R.Id is null then 0 else 1 end ) as 'Num',
R.ReportBackupDate
from
Base_Staff S
left join Rpt_RegistForm R on ( R.SignatureCPA1Id=S.Id or R.SignatureCPA2Id=S.Id ) and R.DocStatus=30
where S.UserType=3 

该查询需要执行10秒左右,仔细分析,它有2次查询类似的结果集(Base_Staff,Rpt_RegistForm 关联部分),这正是CTE应用的场合。

从SQLSERVER 联机丛书,我们来了解下CET的概念:

ms-help://MS.SQLCC.v10/MS.SQLSVR.v10.zh-CHS/s10de_6tsql/html/27cfb819-3e8d-4274-8bbe-cbbe4d9c2e23.htm

指定临时命名的结果集,这些结果集称为公用表表达式 (CTE)。该表达式源自简单查询,并且在单条 SELECT、INSERT、UPDATE、MERGE 或 DELETE 语句的执行范围内定义。该子句也可用在 CREATE VIEW 语句中,作为该语句的 SELECT 定义语句的一部分。公用表表达式可以包括对自身的引用。这种表达式称为递归公用表表达式。

下面看看经过CET改写过的查询:

With CTE as
(
select
    --s.Id as S_ID,
    s.Name ,s.AccountantCode,
    r.BusinessBackupCustomerId --, r.Id as R_ID ,r.SignatureCPA1Id,r.SignatureCPA2Id
from  Base_Staff S
left join Rpt_RegistForm  R
    on ( R.SignatureCPA1Id=S.Id or R.SignatureCPA2Id=S.Id ) and r.DocStatus=30
where s.UserType=3
)
select t0.*
,(
 Select COUNT(*) from (
  Select Distinct BusinessBackupId
  from Biz_BusinessBackupCustomer b
  inner join CTE on b.Id =CTE.BusinessBackupCustomerId
  where t0.AccountantCode=CTE.AccountantCode
) t1
) as '约定书数'
from
(
select Name, AccountantCode,COUNT( BusinessBackupCustomerId) as '报告数'
from CTE
group by Name,AccountantCode
) t0

执行此查询,只需要5秒钟时间,比原来的查询提高了一倍。

注意上面的Count函数,它统计了一个列,如果该列在某行的值为NULL,将不会统计该行,这正符合需求。

另外,CTE还可以做递归处理,详细见上面的联机丛书URL的内容说明。

(0)

相关推荐

  • sqlserver另类非递归的无限级分类(存储过程版)

    下面是我统计的几种方案: 第一种方案(递归式): 简单的表结构为: CategoryID int(4), CategoryName nvarchar(50), ParentID int(4), Depth int(4) 这样根据ParentID一级级的运用递归找他的上级目录. 还有可以为了方便添加CategoryLeft,CategoryRight保存他的上级目录或下级目录 第二种方案: 设置一个varchar类型的CategoryPath字段来保存目录的完整路径,将父目录id用符号分隔开来.比

  • 使用SQLSERVER 2005/2008 递归CTE查询树型结构的方法

    下面是一个简单的Family Tree 示例: 复制代码 代码如下: DECLARE @TT TABLE (ID int,Relation varchar(25),Name varchar(25),ParentID int) INSERT @TT SELECT 1,' Great GrandFather' , 'Thomas Bishop', null UNION ALL SELECT 2,'Grand Mom', 'Elian Thomas Wilson' , 1 UNION ALL SELE

  • 使用SqlServer CTE递归查询处理树、图和层次结构

    CTE(Common Table Expressions)是从SQL Server 2005以后版本才有的.指定的临时命名结果集,这些结果集称为CTE. 与派生表类似,不存储为对象,并且只在查询期间有效.与派生表的不同之处在于,CTE 可自引用,还可在同一查询中引用多次.使用CTE能改善代码可读性,且不损害其性能. 递归CTE是SQL SERVER 2005中重要的增强之一.一般我们在处理树,图和层次结构的问题时需要用到递归查询. CTE的语法如下 WITH CTE AS ( SELECT Em

  • SQLSERVER2008中CTE的Split与CLR的性能比较

    我们新建一个DataBase project,然后建立一个UserDefinedFunctions,Code像这样: 复制代码 代码如下: 1: /// <summary> /// SQLs the array. /// </summary> /// <param name="str">The STR.</param> /// <param name="delimiter">The delimiter.&l

  • SqlServer使用公用表表达式(CTE)实现无限级树形构建

    SQL Server 2005开始,我们可以直接通过CTE来支持递归查询,CTE即公用表表达式 公用表表达式(CTE),是一个在查询中定义的临时命名结果集将在from子句中使用它.每个CTE仅被定义一次(但在其作用域内可以被引用任意次),并且在该查询生存期间将一直生存.可以使用CTE来执行递归操作. DECLARE @Level INT=3 ;WITH cte_parent(CategoryID,CategoryName,ParentCategoryID,Level) AS ( SELECT c

  • SQLSERVER2005 中树形数据的递归查询

    问题描述.借用了adinet的问题.参见:http://www.jb51.net/article/28670.htm 今天做项目遇到一个问题, 有产品分类A,B,C顶级分类, 期中A下面有a1,a2,a3子分类. 但是a1可能共同属于A和B,然后我的数据库是这样设计的       id           name         parnet   1 A 0 2 B 0 3 a1 1,2 如果想要查询A的所有子类的话就要查询parent中包含1的,所以就萌生了这个办法.呵呵,解决方案 复制代码

  • 在sqlserver中如何使用CTE解决复杂查询问题

    最近,同事需要从数个表中查询用户的业务和报告数据,写了一个SQL语句,查询比较慢: Select S.Name, S.AccountantCode, ( Select COUNT(*) from ( Select Distinct BusinessBackupId from Biz_BusinessBackupCustomer where Id in ( Select BusinessBackupCustomerId from Rpt_RegistForm where ( SignatureCP

  • SqlServer中如何解决session阻塞问题

    简介 对于数据库运维人员来说创建session或者查询时产生问题是常规情况,下面介绍一种很有效且不借助第三方工具的方式来解决类似问题. 最近开始接触运维工作,所以自己总结一些方案便于不懂数据库的同事解决一些不太紧要的数据库问题.类似方法很多理论也很多,我就不做深究,就是简单写一个方案,便于菜鸟使用的. 阻塞理解 在Sql Server 中当一个数据库会话中的事务正锁定一个或多个其他会话事务想要读取或修改的资源时,会产生阻塞(Blocking).通常短时间的阻塞没有问题,且是较忙的应用程序所需要的

  • 分页存储过程(二)在sqlserver中返回更加准确的分页结果

    在我的使用SQL Server2005的新函数构造分页存储过程中,我提到了使用ROW_NUMBER()函数来代替top实现分页存储过程. 但是时间长了,又发现了新问题,就是主子表的分页查询.例如:订单表和订单明细表,要求是查询订单,第二页,每页10条 复制代码 代码如下: --使用row_unmber()实现分页 --本来我们想要的结果是10条订单,结果却不是10条订单,而是10条明细 --其实是针对的子表进行分页了,订单并不是要显示的个数,出来的个数是明细的个数 --就是因为主表和子表联合查询

  • SQLServer中使用扩展事件获取Session级别的等待信息及SQLServer 2016中Session级别等待信息的增强

    什么是等待 简单说明一下什么是等待: 当应用程序对SQL Server发起一个Session请求的时候,这个Session请求在数据库中执行的过程中会申请其所需要的资源, 比如可能会申请内存资源,表上的锁资源,物理IO资源,网络资源等等, 如果当前Session运行过程中需要申请的某些资源无法立即得到满足,就会产生等待. SQL Server会以不用的方式来展现这个等待信息,比活动Session的等待信息,实例级的等待信息等等. SQL Server中,等待事件是作为DBA进行TroubleSh

  • SQLServer中JSON文档型数据的查询问题解决

    近日在项目中遇到一个问题: 如何在报表中统计JSON格式存储的数据? 例如有个调查问卷记录表,记录每个问题的答案. 其结构示意如下(横表设计) Id user date Q1_Answer Q2_Answer Q3_Answer 行Id 答题用户 答题日期 问题一结果 问题二结果 问题三结果 在[Q1_Answer].[Q2_Answer].[Q3_Answer]中记录的数据格式是JSON文档内容,因为是选项值,而且考虑到可能有多选, 所以存储的格式如下: 1 [ {"code":&q

  • SpringMail使用过程中的报错解决办法

    SpringMail使用过程中的报错解决办法 1.Unable to locate provider for protocol: smtp –>缺少依赖造成的 <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4</version> </dependency> <dependency

  • SQLserver中cube:多维数据集实例详解

    1.cube:生成多维数据集,包含各维度可能组合的交叉表格,使用with 关键字连接 with cube 根据需要使用union all 拼接 判断 某一列的null值来自源数据还是 cube 使用GROUPING关键字 GROUPING([档案号]) = 1 : null值来自cube(代表所有的档案号) GROUPING([档案号]) = 0 : null值来自源数据 举例: SELECT * INTO ##GET FROM (SELECT * FROM ( SELECT CASE WHEN

  • Oracle数据库中ora-12899错误的解决方法

    在使用ORACLE的过程中,会出现各种各样的问题,各种各样的错误,其中ORA-12899就是前段时间我在将数据导入到我本地机器上的时候一直出现的问题.不过还好已经解决了这个问题,现在分享一下,解决方案; 出现ORA-12899,是字符集引起的,中文在UTF-8中占3个字节,ZHS16GBK中占2个字节,而源dmp文件字符集是ZHS16GBK库里倒出来的数据,现在要导入到目标字符集为UTF-8的库里,所以会出现ORA-12899 其实只要修改一下ORACLE 的字符集就可以很好的解决这个问题; 但

  • SQLServer中防止并发插入重复数据的方法详解

    SQLServer中防止并发插入重复数据,大致有以下几种方法: 1.使用Primary Key,Unique Key等在数据库层面让重复数据无法插入. 2.插入时使用条件 insert into Table(****) select **** where not exists(select 1 from Table where ****); 3.使用SERIALIZABLE隔离级别,并且使用updlock或者xlock锁提示(等效于在默认隔离级别下使用(updlock,holdlock)或(xl

  • SqlServer中模糊查询对于特殊字符的处理方法

    今天在处理sql查询的时候遇到了like查询不到的问题,于是对问题进行剖析 问题: select * from v_workflow_rt_task_circulate where Name like '%[admin]请假申请[2017-02-13至2017-02-13]%' 查询不到,但是在数据库中是存在在这一条数据的. 修改后: select * from v_workflow_rt_task_circulate where Name like '%[[]admin]请假申请[[]2017

随机推荐