[SQL] CTE 語法

[SQL] CTE 語法

SQL Server 從 2005 版開始,就有支援 CTE ( common table expression ),他不僅可以幫忙簡化 SQL 的寫法,讓原本可能一堆的 SubQuery 變成有一致的寫法,還可以搭配 INSERT, UPDATE, DELETE 這些 DML 來使用;或者是把 CTE 拿來配合 Recursive Queries 上的使用,可以讓我們整個 SQL 語法更為精簡也更有效率。

 

CTE 的基本語法會是這樣 :


	

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

AS

( CTE_query_definition )

 

 

 

這樣可能會看不大懂,我們實際來舉個簡單的範例,應該看起來就比較清楚了

 

WITH OrdersTable( OrderID, CustomerID, EmployeeID ) as
(
  Select OrderID, CustomerID, EmployeeID 
  from dbo.Orders
), 
OrderDetailsTable( OrderID, TotalPrice ) as 
(
  Select OrderID, SUM(Price) 
  from dbo.[Order Details]
  group by  OrderID
)
Select * 
From OrdersTable A 
inner join OrderDetailsTable B  on A.OrderID = B.OrderID 

 

在這個範例當中,我們示範了一次把原本的兩個 Table 先各自處理,接著最後再 Join 一起。如果採用傳統的做法,可能就會一開始就 Join 一起,看起來似乎比較簡單,但是如果這當中有不少 Aggregate 這類的處理,或者是接續的多段的組合時,那使用 CTE 就會相段的簡單多了。剛開始在學習的時候,從文獻上來看 CTE 是 ANSI SQL-99 Standard 的規範之一,因此也很好奇的寫了一小段的 Sample 在 Oracle 10 和 11 上面測試一下,看來似乎都是可以通用的,就沒有花太多時間在這個上面了。

 

前幾天幫忙朋友處理一個問題,他的狀況如果採用 subquery 的方式,SQL 就很難下的出來。了解他的需求之後,於是我就很自然的介紹他採用 CTE,於是朋友就很快的寫出原本非常複雜的 SQL 指令,還可以一塊一塊的測試增加,看起來似乎又是個簡單任務。

 

然而事情就又發生了,朋友主要是要利用一組 SQL 挑出一些很特殊的條件資料,將這些資料存到另外一個 Table 內,因此我就建議他把原本找出來的資料,在前面再加上 INSERT INTO 的指令,應該就可以解決了,以上述的例子來說,就可以寫成類似以下的語法:

WITH OrdersTable( OrderID, CustomerID, EmployeeID ) as
(
  Select OrderID, CustomerID, EmployeeID 
  from dbo.Orders
)
INSERT INTO SalesTable
  SELECT * FROM OrdersTable

 

因為手邊剛好沒有 Oracle 的環境,因此就把範例給朋友,請他自行測試了一下,但這樣的寫法在 Oracle 就不行了。原來在 Oracle 的世界中,如果要下 DML 的指令時,則他們會要是命令初始就要有那個保留字,因此就要把原本的語法改成:

 

INSERT INTO SalesTable
  WITH OrdersTable( OrderID, CustomerID, EmployeeID ) as
     (
        SELECT   OrderID, CustomerID, EmployeeID 
        FROM dbo.Orders
      )
    )
    SELECT  * FROM OrdersTable
 

這篇算是寫個自己的提醒資料,下次遇到 Oracle 的時候不要再搞錯了。