公用表表達式(CTE)

  在編寫T-SQL代碼時,每每須要臨時存儲某些結果集。前面咱們已經普遍使用和介紹了兩種臨時存儲結果集的方法:臨時表和表變量。除此以外,還可使用公用表表達式的方法。公用表表達式(Common Table Expression)是SQL Server2005版本的引入的一個特性。CTE能夠看組是一個臨時的結果集,能夠再接下來來的一個SELECT,INSERT,UPDATE,DELETE,MERGE語句中屢次引用。使用公用表達式CTE可讓語句更加清晰簡練。與公用表達式做用相似的還有臨時表和表變量。下面給出三種方法的對比。數據庫

  一、3種方法比較express

   (一)、臨時表:須要在臨時數據庫TempDB中經過I/O操做來建立表結構,一旦用戶推出SQL Server環境則自動被刪除。優化

   (二)、表變量:在內存中以表結構的形式存在,其定義與變量一致,其使用與表相似,不須要產生I/O。spa

   (三)、公用表表達式:Common Table Expression,定義在內存中保存的臨時存儲結果集對象,不產生I/O,不須要按照表變量這樣定義,使用方法和表相似。能夠本身引用,也能夠再查詢中被屢次引用。code

  二、WITH AS的含義對象

  WITH AS-作子查詢部分(subquery factoring)。blog

  它用於定義一個SQL片斷,該片斷會被是整個SQL語句所用到。若是WITH AS因此定的表名被調用兩次以上,則優化器會自動將WITH AS所獲取的數據放入臨時表裏,若是隻是被調用一次,則不會。能夠經過materialize將WITH AS短語裏的數據強制放入全局臨時表裏。遞歸

  WITH AS能夠被緊跟着的一條SQL語句所使用屢次,但不能被緊跟着的多條SQL語句使用。內存

WITH B AS 
(
    SELECT * FROM xxx WHERE Id > 5
)
SELECT * FROM B

  三、CTE的定義資源

   CTE的定義語法以下,主要包括3個部分。

   (一)、Expression_name:CTE表達式的名稱。

   (二)、Column_name:列名列表。

   (三)、CTE_query_definition:定義CTE結果集的Select查詢語句

  WITH expression_name [(column_name [,...n] )]
  AS
  ( 
    cte_query_definition
  )

  根據微軟對CTE好處的描述,能夠歸結爲四點:

  •   能夠定義遞歸公用表表達式(CTE)
  •   當不須要將結果集做爲視圖被多個地方引用時,CTE可使其更加簡潔
  •   GROUP BY語句能夠直接做用於子查詢所得的標量列
  •   能夠在一個語句中屢次引用公用表表達式(CTE)

  按照是否遞歸,能夠將公用表(CTE)表達式分爲遞歸公用表表達式和非遞歸公用表表達式.

  非遞歸公用表表達式(CTE):

  非遞歸公用表表達式(CTE)是查詢結果僅僅一次性返回一個結果集用於外部查詢調用。並不在其定義的語句中調用其自身的CTE。

  非遞歸公用表表達式(CTE)的使用方式和視圖以及子查詢一致。

  好比一個簡單的非遞歸公用表表達式:

WITH CTE_Test
AS
(
    SELECT * FROM Person_1
)
SELECT * FROM CTE_Test

  公用表表達式的好處之一是能夠在接下來一條語句中屢次引用:

複製代碼
  WITH CTE_Test
  AS
  (
      SELECT * FROM Person_1
  )
  SELECT * FROM CTE_Test AS a  --第一次引用
  INNER JOIN  CTE_Test AS b    --第二次引用
  ON a.Id = b.Id
  ORDER BY a.Id DESC
複製代碼

  雖然以上引用了屢次,可是隻是一條語句,因此能夠正常執行。

  若是多條語句引用,以下面這樣,是會報錯的。

複製代碼
  WITH CTE_Test
  AS
  (
      SELECT * FROM Person_1
  )
  SELECT * FROM CTE_Test 

  SELECT * FROM CTE_Test
複製代碼

  輸出結果以下:

  

  因爲CTE只能在接下來一條語句中使用,所以,當須要接下來的一條語句中引用多個CTE時,能夠定義多個,中間用逗號分隔,下面是一次定義多個CTE的例子:

複製代碼
WITH CTE_Test1
AS
(
SELECT * FROM Person_1
),
CTE_Test2
AS
(
SELECT * FROM Person_2
)
SELECT * FROM CTE_Test1
UNION
SELECT * FROM CTE_Test2
複製代碼

  結果以下:

  

   遞歸公用表表達式(CTE):

     對於遞歸公用表達式來講,只須要在語句中定義兩部分:

  •    基本語句
  •    遞歸語句

     先建一張表欄目表以下,欄目Id,欄目名稱,欄目的父欄目。

   

  如今使用CTE查詢其每一個欄目是第幾層欄目的代碼以下:

複製代碼
WITH COL_CTE(Id,Name,ParentId,tLevel )
AS
(
    --基本語句
    SELECT Id,Name,ParentId,0 AS tLevel FROM Col
    WHERE ParentId = 0
    UNION ALL
    --遞歸語句
    SELECT c.Id,c.Name,c.ParentId,ce.tLevel+1 AS tLevel FROM COL as c 
    INNER JOIN COL_CTE AS ce   --遞歸調用
    ON c.ParentId = ce.Id
)

SELECT * FROM COL_CTE
複製代碼

  輸出結果以下:

  

  0表示頂級欄目。1就是1級欄目。語法很是優雅。就一個SELECT * FRON COL_CTE。這正是CTE強大的地方,可是,這要有約束,不然若是無限制遞歸能夠會消耗掉很是多的系統資源。下面來看看如何限制遞歸的最大次數。

  如將上面的查詢語法改成:

複製代碼
WITH COL_CTE(Id,Name,ParentId,tLevel )
AS
(
    --基本語句
    SELECT Id,Name,ParentId,0 AS tLevel FROM Col
    WHERE ParentId = 0
    UNION ALL
    --遞歸語句
    SELECT c.Id,c.Name,c.ParentId,ce.tLevel+1 AS tLevel FROM COL as c 
    INNER JOIN COL_CTE AS ce 
    ON c.ParentId = ce.Id
)

SELECT * FROM COL_CTE
OPTION(MAXRECURSION 2)  --指定最大遞歸次數爲2
複製代碼

  咱們知道在上面的查詢中,要查到天河區新聞最少要遞歸3次,可是如今只遞歸2次,運行是什麼結果呢?

  

  提示信息以下:

  消息 530,級別 16,狀態 1,第 1 行
  語句被終止。完成執行語句前已用完最大遞歸 2。

   CTE是一種十分優雅的存在。CTE所帶來最大的好處是代碼可讀性的提高,這是良好代碼的必須品質之一。使用遞歸CTE能夠更加輕鬆愉快的用優雅簡潔的方式實現複雜的查詢。

相關文章
相關標籤/搜索