sql server中公用表表达式的优点是什么

时间:2011-03-03 06:14:52

标签: sql sql-server tsql common-table-expression

我们编写CTE sql,如下所示

WITH yourCTE AS 
(
 SELECT .... FROM :... WHERE.....
) SELECT * FROM yourCTE

将sql放入块中会有什么好处。我认为如果我们将复杂的sql放入块中,那么我们就可以编写像SELECT * FROM yourCTE这样的sql。好像我正在访问视图。 在性能方面使用CTE的附加优势是什么。请讨论。感谢

4 个答案:

答案 0 :(得分:15)

在许多情况下,CTE非常有用:

  • 递归查询,就像走上一个层次结构树一样 - 没有CTE就非常棘手和繁琐(见here for a sample of a recursive CTE

  • 只要您想使用其中一个排名函数,例如ROW_NUMBER()RANK()NTILE()等等(请参阅{{3} })

  • 一般情况下,您需要首先根据某些条件选择几行/列,然后对这些行执行某些操作,例如:更新表,删除重复项等。

我经常使用CTE的一种情况是删除除给定数据集的最新行之外的所有行,例如如果你有客户和他们的订单有1:n的关系,并且你想要删除除最近订单之外的所有订单(基于OrderDate),对于每个客户,在SQL中执行此操作会非常繁琐CTE。

使用CTE和排名功能,这是轻而易举的事:

;WITH CustomerOrders AS
(
    SELECT  
       c.CustomerID, o.OrderID,
       ROW_NUMBER() OVER(PARTITION BY c.CustomerID ORDER BY o.OrderDate DESC) AS 'RowN'
    FROM
       dbo.Customer c
    INNER JOIN
       dbo.Orders o ON o.CustomerID = c.CustomerID
)
DELETE FROM 
    dbo.Orders
FROM 
    CustomerOrders co
WHERE 
  dbo.Orders.OrderID = co.OrderID
  AND co.RowN > 1

使用此功能,您可以创建一个按CustomerID分区的“内嵌视图”(例如,每个客户从1开始获取rownumbers),按OrderDate DESC排序(最新订单优先)。对于每个客户,最新的,最近的订单有RowN = 1,因此您可以轻松地删除所有其他行,并且您已经完成了您想要做的事情 - 带有CTE的小菜一碟 - 没有它的杂乱代码。 ..

答案 1 :(得分:3)

This MSDN article描述的最好。最重要的是,如果您已经从视图中选择数据,则不必将其包装在CTE中,然后从CTE中选择。我不认为CTE和视图之间存在很大差异(表现明智)。至少不符合我的经验(我最近一直在处理一些容纳大量记录的复杂数据库结构)。但是,CTE非常适合递归选择。

另一方面,如果您在查询中多次选择连接数据的相同子集并且没有为其定义视图,则CTE可能是有益的。如果您只是为一个查询加入数据然后将其包装在CTE中,我认为这太过分了。即使您没有使用CTE,查询路径仍会被缓存...

答案 2 :(得分:0)

  1. 进行递归查询。
  2. 在定义时命名为给定的临时区域中虚拟保存查询输出。
  3. 无需保存元数据。
  4. 当需要对某些查询输出执行更多操作时很有用。
  5. 查询输出保留,直到查询正在运行
  6. 最好使用暂存数据进行进一步处理。
  7. 允许比单个查询更多的分组选项。
  8. 允许从复杂查询中获取标量数据

答案 3 :(得分:-3)

晚上好朋友。今天我们将了解Common table表达式,它是SQL Server 2005中引入的新功能,也可以在以后的版本中使用。

公用表表达式: - 公用表表达式可以定义为临时结果集,换句话说,它可以替代SQL Server中的视图。公用表表达式仅在定义它的批处理语句中有效,不能在其他会话中使用。

声明CTE的语法(公用表表达式): -

with [Name of CTE]
as
(
Body of common table expression
)

让我们举一个例子: -

CREATE TABLE Employee([EID] [int] IDENTITY(10,5) NOT NULL,[Name] [varchar](50) NULL)

insert into Employee(Name) values('Neeraj')
insert into Employee(Name) values('dheeraj')
insert into Employee(Name) values('shayam')
insert into Employee(Name) values('vikas')
insert into Employee(Name) values('raj')

CREATE TABLE DEPT(EID INT,DEPTNAME VARCHAR(100))
insert into dept values(10,'IT')
insert into dept values(15,'Finance')
insert into dept values(20,'Admin')
insert into dept values(25,'HR')
insert into dept values(10,'Payroll')

我创建了两个表employee和Dept,并在每个表中插入了5行。现在我想加入这些表并创建一个临时结果集以进一步使用它。

With CTE_Example(EID,Name,DeptName)
as
(
select Employee.EID,Name,DeptName from Employee 
inner join DEPT on Employee.EID =DEPT.EID
)
select * from CTE_Example

让我们逐一掌握声明的每一行并理解。

要定义CTE我们写“with”子句,然后我们给表表达式命名,这里我给出了名称“CTE_Example”

然后我们写“As”并将我们的代码括在两个括号(---)中,我们可以在封闭的括号中连接多个表。

在最后一行中,我使用了“Select * from CTE_Example”,我们在最后一行代码中引用了Common表达式,所以我们可以说它就像一个视图,我们在那里定义和使用视图在单个批处理中,CTE不作为永久对象存储在数据库中。但它的行为就像一个观点。我们可以在CTE上执行删除和更新语句,这将对CTE中使用的引用表产生直接影响。让我们举个例子来理解这个事实。

With CTE_Example(EID,DeptName)
as
(
select EID,DeptName from DEPT 
)
delete from CTE_Example where EID=10 and DeptName ='Payroll'

在上面的语句中,我们从CTE_Example中删除一行,它将从CTE中使用的引用表“DEPT”中删除数据。

我希望这篇文章对您有所帮助,只要您觉得合适,您就可以使用CTE。