SQL Server CTEs的語法與功能
以下的文章主要向大家講述的是SQL Server CTEs 的遞歸功能是SQL Server數(shù)據(jù)庫中的三種保存臨時(shí)結(jié)果的實(shí)際操作方法之一。其另兩種是臨時(shí)表與View,當(dāng)然你也可以說View并不保存數(shù)據(jù),從這一點(diǎn)上來將, CTE更像View一些。
當(dāng)你的查詢需要從一個(gè)源表中統(tǒng)計(jì)出結(jié)果,基于這個(gè)結(jié)果再做進(jìn)一步的統(tǒng)計(jì),如此3次以上的話,你必然會用到View或者臨時(shí)表,現(xiàn)在你也可以考慮用CTE了。
CTE的語法相當(dāng)?shù)暮唵? 如下:
With CTE的名字 AS
(
子查詢
)
Select * from CTE的名字
SQL Server CTEs支持在定義時(shí)引用自身,從而可以達(dá)到遞歸的目的,看下面的例子(1):
- ---prepare test data
- SET NOCOUNT ON;
- CREATE TABLE dbo.Parts
- (
- partid INT NOT NULL PRIMARY KEY,
- partname VARCHAR(25) NOT NULL
- );
- INSERT INTO dbo.Parts(partid, partname)
- select 1, 'Black Tea'
- union all select 2, 'White Tea'
- union all select 3, 'Latte'
- union all select 4, 'Espresso'
- CREATE TABLE dbo.BOM
- (
- partid INT NOT NULL REFERENCES dbo.Parts,
- assemblyid INT NULL REFERENCES dbo.Parts,
- unit VARCHAR(3) NOT NULL,
- qty DECIMAL(8, 2) NOT NULL,
- UNIQUE(partid, assemblyid),
- CHECK (partid <> assemblyid)
- );
- INSERT INTO dbo.BOM(partid, assemblyid, unit, qty)
- select 1, NULL, 'EA', 1.00
- union all
- select 2, 1, 'EA', 1.00
- union all
- select 3, 2, 'EA', 1.00
- union all
- select 4, 3, 'EA', 1.00
- -- perform the test
- WITH BOMTC AS(
- SELECT assemblyid, partid
- FROM dbo.BOM
- WHERE assemblyid IS NOT NULL
- UNION ALL
- SELECT P.assemblyid, C.partid
- FROM BOMTC AS P
- JOIN dbo.BOM AS C ON C.assemblyid = P.partid
- )
- SELECT DISTINCT assemblyid, partid FROM BOMTC;
輸出結(jié)果如下:
例子(2):
- create table Employee
- (
- MgrId int,
- EmpId int,
- Title nvarchar(256)
- )
- insert into employee
- select NULL, 1 ,'CEO'
- union all
- select 1, 2, 'VP'
- union all
- select 2, 3, 'Dev Manager'
- union all
- select 2, 4, 'QA Manager'
- union all
- select 1, 5, 'Sales Manager'
- union all
- select 3, 30, 'Developer'
- union all
- select 3, 31, 'Developer'
- union all
- select 4, 40, 'Tester'
- union all
- select 4, 41, 'Tester'
- With DirectReports as
- (
- select MgrId, EmpId, Title, 0 as [Level] from Employee where MgrId is null
- union all
- select a.MgrId, a.EmpId, a.Title, [Level]+1 as [Level]
- from Employee a join DirectReports b on a.MgrId=b.EmpId
- )
- select * from DirectReports
結(jié)果:
講解:重點(diǎn)是子查詢中的兩個(gè)select語句,以上述例子加以說明:
***個(gè)Select子句被稱為錨點(diǎn)語句,它返回的結(jié)果跟普通的SQL沒有區(qū)別,在這里返回MgrID為null的員工。
第二個(gè)子句就沒那么普通了,它被稱為遞歸語句,請注重到在from后面, Employee和DirectReport進(jìn)行了鏈接操作。你一定會問,DirectReport的定義還沒完成,這個(gè)名字代表什么結(jié)果呢?答案是它不只是代表了一個(gè)結(jié)果,實(shí)際上代表了一系列的結(jié)果。換句話說,在DirectReport這個(gè)名字下,包含著DirectReport0,DirectReport1,DirectReport2...這些較小的集合。
DirectReport0 是Employee和錨點(diǎn)結(jié)合的產(chǎn)物;
DirectReport1 是Employee和 DirectReport0 結(jié)合的產(chǎn)物;
依次類推, DirectReport n是Employee和DirectReport n-1結(jié)合的產(chǎn)物;
當(dāng)DirectReport_n為空的時(shí)候,這個(gè)過程就結(jié)束了。
*** 錨點(diǎn)和DirectReport0,DirectReport1... 的并集就是DirectReport的內(nèi)容。
作為一個(gè)程序員,每次看到遞歸的程序,必然會想到無限遞歸這個(gè)錯誤。為了避免了在開發(fā)階段,無限遞歸導(dǎo)致數(shù)據(jù)庫的崩潰,SQL Server提供了一個(gè)QueryHint, MaxRecursion,可以控制遞歸的***層數(shù),假如超過這個(gè)數(shù)字而仍為結(jié)束,則視為代碼錯誤,強(qiáng)制退出。如:Option(MaxRecursion 10)
可見SQL Server CTEs可以用來遞歸操作樹形結(jié)構(gòu)的數(shù)據(jù)表。
【編輯推薦】