2011-03-03 79 views
11

公共表表达式的优势,我们在写SQL CTE类似下面一个什么是SQL Server

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

会有什么优势,把SQL与块。我认为,如果我们把复杂的SQL与块,然后我们可以写像SQL SELECT * FROM yourCTE。就好像我正在访问视图一样。 在性能方面使用CTE有哪些额外优势。请讨论。谢谢

回答

3

This MSDN article描述它是最好的。底线是,如果您已经从视图中选择数据,则不必将其包装在CTE中,然后从CTE中选择。我不认为CTE和观点之间有很大差异(性能明智)。至少不是以我的经验(我一直在处理一些复杂的数据库结构,最近有很多记录)。然而,CTE对于递归选择是理想的。

不过,另一件事是,如果您要在查询中多次选择相同的连接数据子集并且没有为其定义视图,则CTE可能会有所帮助。我认为如果你只是为了一个单一的查询而加入数据,然后把它封装在一个CTE中,那就太过分了。查询路径仍然会得到缓存,即使你不使用CTE ...

+0

你说CTE是递归选择的理想选择。你想说什么递归选择。请让我明白,什么是由CTE递归选择。 – Thomas 2011-03-03 06:58:01

+0

再次,MSDN通过关于使用CTE的递归查询的详细文章来解决:http://msdn.microsoft.com/zh-cn/library/ms186243.aspx。还可以查看marc的答案,其中提供了一个非常简短的(但容易理解的)递归查询的解释。 – FarligOpptreden 2011-03-03 07:07:15

12

有许多情况下,其中一个CTE可真有用:

  • 递归查询,像走了一个层次树 - 这是非常棘手和繁琐无CTE(见here for a sample of a recursive CTE)要使用的排名功能ROW_NUMBER()RANK(),一个

  • 随时随地等等(请参阅here for info on ranking functions

  • 一般情况下,您需要根据某些标准先选择几行/列,然后对其进行操作。更新表,删除重复等

一个情况下,我经常使用的CTE被删除所有,但最近的一组给定的数据的行,例如如果您有客户,并且与订单的关系为1:n,并且您想要删除除最近订单(基于OrderDate)之外的所有订单,那么对于每个客户而言,在没有CTE的情况下在SQL中执行此操作会非常繁琐。

的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一块蛋糕 - 没有它的杂乱代码....

+0

当你简单地说:'从CTE中删除,如你的例子中那样,RDBMS如何知道它应从哪个表中删除? – 2011-03-03 09:12:29

+0

@Andriy M:更新了我的查询 - 这应该让它更加明显。 – 2011-03-03 09:37:59

+0

确实非常明显,谢谢。:) – 2011-03-03 10:54:30

-2

今天晚上好。今天我们要了解的是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') 

我已经创建了两个表雇员和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我们写“与”条款,那么我们给一个名字表表达式,在这里我给名为“CTE_Example”

然后我们写“为”,并在两个括号包含我们的代码(---),我们可以在括号内加入多个表格。

在最后一行中,我使用了“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行,它会删除从在热膨胀系数所使用的参考表“DEPT”的数据。

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

+0

我知道这篇文章有点旧,但是因为人们已经低估了这个答案,所以我想我会添加一个为什么我这么做的理由。 OP正在询问CTE将提供什么优势。这篇文章向我们展示了如何做一个CTE,而不是为什么它应该被使用。 – Semperfi89 2017-01-19 14:17:13

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