惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
C
CXSECURITY Database RSS Feed - CXSecurity.com
V
Visual Studio Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
小众软件
小众软件
L
LangChain Blog
Cyberwarzone
Cyberwarzone
美团技术团队
The Register - Security
The Register - Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tor Project blog
V
V2EX
Security Archives - TechRepublic
Security Archives - TechRepublic
Hacker News: Ask HN
Hacker News: Ask HN
L
LINUX DO - 最新话题
Recent Announcements
Recent Announcements
H
Hackread – Cybersecurity News, Data Breaches, AI and More
酷 壳 – CoolShell
酷 壳 – CoolShell
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
aimingoo的专栏
aimingoo的专栏
人人都是产品经理
人人都是产品经理
F
Full Disclosure
V2EX - 技术
V2EX - 技术
The Cloudflare Blog
博客园 - 叶小钗
T
Threat Research - Cisco Blogs
阮一峰的网络日志
阮一峰的网络日志
G
GRAHAM CLULEY
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Latest news
Latest news
S
Security @ Cisco Blogs
Spread Privacy
Spread Privacy
Project Zero
Project Zero
K
Kaspersky official blog
MyScale Blog
MyScale Blog
Attack and Defense Labs
Attack and Defense Labs
云风的 BLOG
云风的 BLOG
博客园 - 【当耐特】
Hacker News - Newest:
Hacker News - Newest: "LLM"
大猫的无限游戏
大猫的无限游戏
P
Privacy International News Feed
Google DeepMind News
Google DeepMind News
WordPress大学
WordPress大学
C
Cybersecurity and Infrastructure Security Agency CISA
Webroot Blog
Webroot Blog
罗磊的独立博客
Vercel News
Vercel News
N
News and Events Feed by Topic
A
Arctic Wolf
C
CERT Recently Published Vulnerability Notes

博客园 - 似水流年-johnhuo

架构师向左,项目经理向右?? 今天迈出第一步,开始了解iphone开发 学习objective-c的一些特殊的地方 信息发布系统 Jquery+MVC架构开发(7) Controller层 . 信息发布系统 Jquery+MVC架构开发(6)BLL层提供WCF 服务 . 信息发布系统 Jquery+MVC架构开发(5) DAL层 信息发布系统 Jquery+MVC架构开发(4) Model 层 . 信息发布系统 Jquery+MVC架构开发(3) 解决方案创建 信息发布系统 Jquery+MVC架构开发(2) 在EA下进行数据库设计 信息发布系统 Jquery+MVC架构开发(1) 需求分析和架构构思 c# 设计模式(三)行为型 c# 设计模式(二)结构型 c# 设计模式(一)创建型 .NET平台上的Model-View-Presenter模式实践 关于cmmi的一些理解及资料 iphone 开发学习 C语言指针总结 Android 开发网站,记录一下 使用 TRY/CATCH 语句解决 SQL Server 2005 死锁
信息发布系统 Jquery+MVC架构开发(8)DAL层的补充
似水流年-johnhuo · 2011-07-29 · via 博客园 - 似水流年-johnhuo

CTE (Common Table Expression),是从sql server 2005开始支持的一种表达式,它是一种临时结果集,与派生表类似,仅在查询期间有效。与派生表不同的是,cte可以调用自身,从而实现递归。此外,还可以在同一查询中引用多次。

[ WITH [ ,n ] ]
::=
expression_name [ ( column_name [ ,n ] ) ]
AS
( CTE_query_definition )

至少有一个定位点成员和一个递归成员,当然,你可以定义多个定位点成员和递归成员,但所有定位点成员必须在递归成员的前面
定位点成员之间必须使用UNION ALL、UNION、INTERSECT、EXCEPT集合运算符,最后一个定位点成员与递归成员之间必须使用UNION ALL,递归成员之间也必须使用UNION ALL连接
定位点成员和递归成员中的字段数量和类型必须完全一致
递归成员的FROM子句只能引用一次CTE对象
递归成员中不允许出现下列项
    SELECT DISTINCT
    GROUP BY
    HAVING
    标量聚合
    TOP
    LEFT、RIGHT、OUTER JOIN(允许出现 INNER JOIN)
    子查询

派生表是一个查询结果生成的表,类似于临时表。

派生表可以简化查询,避免使用临时表。相比手动生成临时性能更优越。派生表与其他表一样出现在查询的FROM子句中

select * from (select * from athors)  temp
temp 就是派生表
Every derived table must have its own alias(每个派生表必须有自己的别名)

派生出来的表必须要是一个有效的表.因此,它必须遵守以下几条规则:

  1. 所有列必须要有名称

  2. 列名称必须是要唯一

  3. 不允许使用ORDER BY(除非指定了TOP)

我们在分页算法中应用了CTE,如下:

strSql.Append(@" SELECT count(1) as maxcount from Info " + strwhere.ToString() + "; ");

                strSql.Append(@" WITH Row AS

                                      (SELECT ROW_NUMBER() OVER(ORDER BY InfoId) AS rownumber, InfoId FROM Info (NOLOCK) "

                                            + strwhere.ToString() + ") ");

                strSql.Append("select InfoId,infoname,InfoContent,TypeId,PictureUrl,CreateId,CreateDate,ModifyDate,AttachMentUrl,IsTop from Info inner join Row on Info.InfoId=Row.InfoId WHERE rownumber BETWEEN @StartNum AND @StartNum + @pageSize - 1 ");

详细的代码见我的文章:

http://blog.csdn.net/hliq5399/article/details/6629032

大家可以看到应用了CTE的分页算法简洁了很多。

其实CTE的用处很多,一个常见的应用还可以用它来实现递归:

在网上找了个例子,就不自己写了,原文如下:

http://www.cnblogs.com/downmoon/archive/2009/10/23/1588405.html

  表结构如下:

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

CREATE TABLE [dbo].[CategorySelf](
    
[PKID] [int] IDENTITY(1,1) NOT NULL,
    
[C_Name] [nvarchar](50) NOT NULL,
    
[C_Level] [int] NOT NULL,
    
[C_Code] [nvarchar](255) NULL,
    
[C_Parent] [int] NOT NULL,
    
[InsertTime] [datetime] NOT NULL,
    
[InsertUser] [nvarchar](50) NULL,
    
[UpdateTime] [datetime] NOT NULL,
    
[UpdateUser] [nvarchar](50) NULL,
    
[SortLevel] [int] NOT NULL,
    
[CurrState] [smallint] NOT NULL,
    
[F1] [int] NOT NULL,
    
[F2] [nvarchar](255) NULLCONSTRAINT [PK_OBJECTCATEGORYSELF] PRIMARY KEY CLUSTERED
(
    
[PKID] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
)
ON [PRIMARY]GO
内容导航

  再插入一些测试数据

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

INSERT INTO [CategorySelf]([C_Name],[C_Level] ,[C_Code],[C_Parent] ,[InsertTime] ,[InsertUser] ,[UpdateTime]  ,[UpdateUser]  ,[SortLevel]  ,[CurrState]  ,[F1]  ,[F2])
select '分类1',1,'0',0,GETDATE(),'testUser',DATEADD(dd,1,getdate()),'CrackUser',13,0,1,'邀月备注' union all
select '分类2',1,'0',0,GETDATE(),'testUser',DATEADD(dd,78,getdate()),'CrackUser',12,0,1,'邀月备注' union all
select '分类3',1,'0',0,GETDATE(),'testUser',DATEADD(dd,6,getdate()),'CrackUser',10,0,1,'邀月备注' union all
select '分类4',2,'1',1,GETDATE(),'testUser',DATEADD(dd,75,getdate()),'CrackUser',19,0,1,'邀月备注' union all
select '分类5',2,'2',2,GETDATE(),'testUser',DATEADD(dd,3,getdate()),'CrackUser',17,0,1,'邀月备注' union all
select '分类6',3,'1/4',4,GETDATE(),'testUser',DATEADD(dd,4,getdate()),'CrackUser',16,0,1,'邀月备注' union all
select '分类7',3,'1/4',4,GETDATE(),'testUser',DATEADD(dd,5,getdate()),'CrackUser',4,0,1,'邀月备注' union all
select '分类8',3,'2/5',5,GETDATE(),'testUser',DATEADD(dd,6,getdate()),'CrackUser',3,0,1,'邀月备注' union all
select '分类9',4,'1/4/6',6,GETDATE(),'testUser',DATEADD(dd,7,getdate()),'CrackUser',5,0,1,'邀月备注' union all
select '分类10',4,'1/4/6',6,GETDATE(),'testUser',DATEADD(dd,7,getdate()),'CrackUser',63,0,1,'邀月备注' union all
select '分类11',4,'1/4/6',6,GETDATE(),'testUser',DATEADD(dd,8,getdate()),'CrackUser',83,0,1,'邀月备注' union all
select '分类12',4,'2/5/8',8,GETDATE(),'testUser',DATEADD(dd,10,getdate()),'CrackUser',3,0,1,'邀月备注' union all
select '分类13',4,'2/5/8',8,GETDATE(),'testUser',DATEADD(dd,15,getdate()),'CrackUser',1,0,1,'邀月备注'

  一个典型的应用场景是:在这个自关联的表中,查询以PKID为2的分类包含所有子分类。也许很多情况下,我们不得不用临时表\表变量\游标等。现在我们有了CTE,就简单多了。

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

WITH SimpleRecursive(C_Name, PKID, C_Code,C_Parent)
    
AS
(
SELECT C_Name, PKID, C_Code,C_Parent  FROM CategorySelf WHERE PKID = 2
UNION ALL
SELECT p.C_Name, p.PKID, p.C_Code,p.C_parent
FROM CategorySelf  P  INNER JOIN
SimpleRecursive A
ON A.PKID = P.C_Parent
)
SELECT sr.C_Name as C_Name, c.C_Name as C_ParentName,sr.C_Code as C_ParentCode
FROM SimpleRecursive sr inner join CategorySelf c
on sr.C_Parent=c.PKID

        查询结果如下:

C_Name C_ParentName  C_ParentCode
分类5 分类2 2
分类8 分类5 2/5
分类12 分类8 2/5/8
分类13 分类8 2/5/8

        感觉怎么样?如果我只想查询第二层,而不是默认的无限查询下去,可以在上面的SQL后加一个选项 Option(MAXRECURSION 5),注意5表示到第5层就不往下找了。如果只想找第二层,但实际结果有三层,此时会出错:

  Msg 530, Level 16, State 1, Line 1

  The statement terminated. The maximum recursion 1 has been exhausted before statement completion.

  此时可以通过where条件来解决,而保证不出错,看如下SQL语句:

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

WITH SimpleRecursive(C_Name, PKID, C_Code,C_Parent,Sublevel)
    
AS
(
SELECT C_Name, PKID, C_Code,C_Parent,0  FROM CategorySelf WHERE PKID = 2
UNION ALL
SELECT p.C_Name, p.PKID, p.C_Code,p.C_parent,Sublevel+1
FROM CategorySelf  P  INNER JOIN
SimpleRecursive A
ON A.PKID = P.C_Parent
)
SELECT sr.C_Name as C_Name, c.C_Name as C_ParentName,sr.C_Code as C_ParentCode
FROM SimpleRecursive sr inner join CategorySelf c
on sr.C_Parent=c.PKID
where SubLevel<=2

         查询结果:

C_Name C_ParentName C_ParentCode
分类5 分类2 2
分类8 分类5 2/5

        当然,我们不是说CTE就是万能的。通过好的表设计也可以某种程度上解决特定的问题。下面用常规的SQL实现上面这个需求。

  注意:上面表中有一个字段很重要,就是C_Code,编码 ,格式如"1/2",“2/5/8"表示该分类的上级分类是1/2,2/5/8

  这样,我们查询就简单多,查询以PKID为2的分类包含所有子分类:

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

SELECT C_Name as C_Name, (Select top 1 C_Name from CategorySelf s where c.C_Parent=s.PKID) as C_ParentName,C_Code as C_ParentCode
from CategorySelf c where C_Code like '2/%'

  查询以PKID为2的分类包含所有子分类,且级别不大于3。

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

SELECT C_Name as C_Name, (Select top 1 C_Name from CategorySelf s where c.C_Parent=s.PKID)  as C_ParentName,C_Code as C_ParentCode
from CategorySelf c where C_Code like '2/%' and C_Level<=3

        查询结果同上,略去。这里我们看出,有时候,好的表结构设计相当重要。

  有人很关心性能问题。目前没有测试过。稍后会附上百万级测试报告。不过,有两点理解邀月忘了补充:

  一、CTE其实是面向对象的,运行的基础是CLR。一个很好的说明是With查询语句中是区分字段的大小写的。即"C_Code"和"c_Code"是不一样的,后者会报错。这与普通的SQL语句不同。

  二、 这个应用示例重在简化业务逻辑,即便是性能不佳,但对临时表\表变量\游标等传统处理方式是一种业务层次上的简化或者说是优化。