日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

SQL CTE学习总结

發(fā)布時(shí)間:2025/4/14 数据库 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SQL CTE学习总结 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一句SQL完成動(dòng)態(tài)分級(jí)查詢

http://www.cnblogs.com/powertoolsteam/p/sqlite.html
在最近的活字格項(xiàng)目中使用ActiveReports報(bào)表設(shè)計(jì)器設(shè)計(jì)一個(gè)報(bào)表模板時(shí),遇到一個(gè)多級(jí)分類的難題:需要將某個(gè)部門所有銷售及下屬部門的銷售金額匯總,因?yàn)橄聦偌?jí)別的層次不確定,所以靠拼接子查詢的方式顯然是不能滿足要求,經(jīng)過(guò)一番實(shí)驗(yàn),利用了CTE(Common Table Expression)很輕松解決了這個(gè)問(wèn)題!

舉例:有如下的部門表

以及員工表

如果想查詢所有西北區(qū)的員工(包含西北、西安、蘭州),如下圖所示:

如何用CTE的方式實(shí)現(xiàn)呢?
Talk is cheap. Show me the code

-- 以下代碼使用SQLite 3.18.0 測(cè)試通過(guò) WITH[depts]([dept_id]) AS(SELECT [d].[dept_id]FROM [dept] [d]JOIN [employees] [e] ON [d].[dept_id] = [e].[dept_id]WHERE [e].[emp_name] = '西北-經(jīng)理'UNION ALLSELECT [d].[dept_id]FROM [dept] [d]JOIN [depts] [s] ON [d].[parent_id] = [s].[dept_id]) SELECT * FROM [employees] WHERE [dept_id] IN (SELECT [dept_id]FROM [depts]);
可能有些同學(xué)對(duì)CTE(Common Table Expression)還不太熟悉,這里簡(jiǎn)單說(shuō)一下,有興趣的同學(xué)可以google或者百度,介紹很多(這里以SQLite舉例):?

我還是更喜歡稱CTE(Common Table Expression)為“公用表變量”而不是“公用表達(dá)式”,因?yàn)閺男袨楹褪褂脠?chǎng)景上講,CTE更多的時(shí)候是產(chǎn)生(分迭代或者不迭代)結(jié)果集,供其后的語(yǔ)句使用(查詢、插入、刪除或更新),如上述的例子就是一個(gè)典型的利用迭代遍歷樹形結(jié)構(gòu)數(shù)據(jù)。

CTE的優(yōu)點(diǎn):

遞歸的特點(diǎn)使得原本需要使用臨時(shí)表、存儲(chǔ)過(guò)程才能完成的邏輯,通過(guò)SQL就可以完成,尤其針對(duì)一些樹或者是圖的數(shù)據(jù)模型
因?yàn)槭菚?huì)話內(nèi)的臨時(shí)結(jié)果集,不需要去顯示的聲明或銷毀
改寫后的SQL語(yǔ)句可讀性提高(看的明白才能修改)
給數(shù)據(jù)庫(kù)引擎優(yōu)化執(zhí)行計(jì)劃的可能性(這個(gè)不是肯定的,需要根據(jù)具體CTE的實(shí)現(xiàn)有關(guān)),優(yōu)化了執(zhí)行計(jì)劃,自然地性能就能上升
?
為了更好的說(shuō)明CTE的能力,這里附上兩個(gè)例子(轉(zhuǎn)自SQLite官網(wǎng)文檔)

曼德勃羅集合(Mandelbrot set)
-- 以下代碼使用SQLite 3.18.0 測(cè)試通過(guò) WITH RECURSIVExaxis(x) AS (VALUES(-2.0) UNION ALL SELECT x+0.05 FROM xaxis WHERE x<1.2),yaxis(y) AS (VALUES(-1.0) UNION ALL SELECT y+0.1 FROM yaxis WHERE y<1.0),m(iter, cx, cy, x, y) AS (SELECT 0, x, y, 0.0, 0.0 FROM xaxis, yaxisUNION ALLSELECT iter+1, cx, cy, x*x-y*y + cx, 2.0*x*y + cy FROM m WHERE (x*x + y*y) < 4.0 AND iter<28),m2(iter, cx, cy) AS (SELECT max(iter), cx, cy FROM m GROUP BY cx, cy),a(t) AS (SELECT group_concat( substr(' .+*#', 1+min(iter/7,4), 1), '') FROM m2 GROUP BY cy) SELECT group_concat(rtrim(t),x'0a') FROM a;
運(yùn)行后的結(jié)果,如下圖:(使用SQLite Expert Personal 4.2 x64)

數(shù)獨(dú)問(wèn)題(Sudoku)

假設(shè)有類似下圖的問(wèn)題:

-- 以下代碼使用SQLite 3.18.0 測(cè)試通過(guò)
WITH RECURSIVE
? input(sud) AS (
? ? VALUES('53..7....6..195....98....6.8...6...34..8.3..17...2...6.6....28....419..5....8..79')
? ),
? digits(z, lp) AS (
? ? VALUES('1', 1)
? ? UNION ALL SELECT
? ? CAST(lp+1 AS TEXT), lp+1 FROM digits WHERE lp<9
? ),
? x(s, ind) AS (
? ? SELECT sud, instr(sud, '.') FROM input
? ? UNION ALL
? ? SELECT
? ? ? substr(s, 1, ind-1) || z || substr(s, ind+1),
? ? ? instr( substr(s, 1, ind-1) || z || substr(s, ind+1), '.' )
? ? ?FROM x, digits AS z
? ? WHERE ind>0
? ? ? AND NOT EXISTS (
? ? ? ? ? ? SELECT 1
? ? ? ? ? ? ? FROM digits AS lp
? ? ? ? ? ? ?WHERE z.z = substr(s, ((ind-1)/9)*9 + lp, 1)
? ? ? ? ? ? ? ? OR z.z = substr(s, ((ind-1)%9) + (lp-1)*9 + 1, 1)
? ? ? ? ? ? ? ? OR z.z = substr(s, (((ind-1)/3) % 3) * 3
? ? ? ? ? ? ? ? ? ? ? ? + ((ind-1)/27) * 27 + lp
? ? ? ? ? ? ? ? ? ? ? ? + ((lp-1) / 3) * 6, 1)
? ? ? ? ?)
? )
SELECT s FROM x WHERE ind=0;
復(fù)制代碼
執(zhí)行結(jié)果(結(jié)果中的數(shù)字就是對(duì)應(yīng)格子中的答案)

附:SQLite中CTE(WITH關(guān)鍵字)語(yǔ)法圖解:

WITH

cte-table-name

Select-stmt:

總結(jié)
CTE是解決一些特定問(wèn)題的利器,但了解和正確的使用是前提,在決定將已有的一些SQL重構(gòu)為CTE之前,確保對(duì)已有語(yǔ)句有清晰的理解以及對(duì)CTE足夠的學(xué)習(xí)!Good Luck~~~

附件:用到的SQL腳本
========

T-SQL 公用表表達(dá)式(CTE)

http://www.cnblogs.com/CareySon/archive/2011/12/12/2284740.html


公用表表達(dá)式(CTE)
  在編寫T-SQL代碼時(shí),往往需要臨時(shí)存儲(chǔ)某些結(jié)果集。前面我們已經(jīng)廣泛使用和介紹了兩種臨時(shí)存儲(chǔ)結(jié)果集的方法:臨時(shí)表和表變量。除此之外,還可以使用公用表表達(dá)式的方法。公用表表達(dá)式(Common Table Expression)是SQL Server2005版本的引入的一個(gè)特性。CTE可以看組是一個(gè)臨時(shí)的結(jié)果集,可以再接下來(lái)來(lái)的一個(gè)SELECT,INSERT,UPDATE,DELETE,MERGE語(yǔ)句中多次引用。使用公用表達(dá)式CTE可以讓語(yǔ)句更加清晰簡(jiǎn)練。與公用表達(dá)式作用類似的還有臨時(shí)表和表變量。下面給出三種方法的對(duì)比。

  1、3種方法比較

   (一)、臨時(shí)表:需要在臨時(shí)數(shù)據(jù)庫(kù)TempDB中通過(guò)I/O操作來(lái)創(chuàng)建表結(jié)構(gòu),一旦用戶推出SQL Server環(huán)境則自動(dòng)被刪除。

   (二)、表變量:在內(nèi)存中以表結(jié)構(gòu)的形式存在,其定義與變量一致,其使用與表類似,不需要產(chǎn)生I/O。

   (三)、公用表表達(dá)式:Common Table Expression,定義在內(nèi)存中保存的臨時(shí)存儲(chǔ)結(jié)果集對(duì)象,不產(chǎn)生I/O,不需要按照表變量這樣定義,使用方法和表類似。可以自己引用,也可以再查詢中被多次引用。

  2、WITH AS的含義

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

  它用于定義一個(gè)SQL片段,該片段會(huì)被是整個(gè)SQL語(yǔ)句所用到。如果WITH AS所以定的表名被調(diào)用兩次以上,則優(yōu)化器會(huì)自動(dòng)將WITH AS所獲取的數(shù)據(jù)放入臨時(shí)表里,如果只是被調(diào)用一次,則不會(huì)。可以通過(guò)materialize將WITH AS短語(yǔ)里的數(shù)據(jù)強(qiáng)制放入全局臨時(shí)表里。

  WITH AS可以被緊跟著的一條SQL語(yǔ)句所使用多次,但不能被緊跟著的多條SQL語(yǔ)句使用。

WITH B AS?
(
? ? SELECT * FROM xxx WHERE Id > 5
)
SELECT * FROM B
  3、CTE的定義

   CTE的定義語(yǔ)法如下,主要包括3個(gè)部分。

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

   (二)、Column_name:列名列表。

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

  WITH expression_name [(column_name [,...n] )]
  AS
  (?
    cte_query_definition?
  )
  根據(jù)微軟對(duì)CTE好處的描述,可以歸結(jié)為四點(diǎn):

  可以定義遞歸公用表表達(dá)式(CTE)
  當(dāng)不需要將結(jié)果集作為視圖被多個(gè)地方引用時(shí),CTE可以使其更加簡(jiǎn)潔
  GROUP BY語(yǔ)句可以直接作用于子查詢所得的標(biāo)量列
  可以在一個(gè)語(yǔ)句中多次引用公用表表達(dá)式(CTE)
  按照是否遞歸,可以將公用表(CTE)表達(dá)式分為遞歸公用表表達(dá)式和非遞歸公用表表達(dá)式.

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

  非遞歸公用表表達(dá)式(CTE)是查詢結(jié)果僅僅一次性返回一個(gè)結(jié)果集用于外部查詢調(diào)用。并不在其定義的語(yǔ)句中調(diào)用其自身的CTE。

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

  比如一個(gè)簡(jiǎn)單的非遞歸公用表表達(dá)式:

WITH CTE_Test
AS
(
? ? SELECT * FROM Person_1
)
SELECT * FROM CTE_Test
  公用表表達(dá)式的好處之一是可以在接下來(lái)一條語(yǔ)句中多次引用:

  WITH CTE_TestAS(SELECT * FROM Person_1)SELECT * FROM CTE_Test AS a  --第一次引用INNER JOIN CTE_Test AS b    --第二次引用ON a.Id = b.IdORDER BY a.Id DESC

  雖然以上引用了多次,但是只是一條語(yǔ)句,所以可以正常執(zhí)行。

  如果多條語(yǔ)句引用,如下面這樣,是會(huì)報(bào)錯(cuò)的。

復(fù)制代碼
  WITH CTE_Test
  AS
  (
? ?   SELECT * FROM Person_1
  )
  SELECT * FROM CTE_Test?


  SELECT * FROM CTE_Test
復(fù)制代碼
  輸出結(jié)果如下:
  

  由于CTE只能在接下來(lái)一條語(yǔ)句中使用,因此,當(dāng)需要接下來(lái)的一條語(yǔ)句中引用多個(gè)CTE時(shí),可以定義多個(gè),中間用逗號(hào)分隔,下面是一次定義多個(gè)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

  結(jié)果如下:
  

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

? ?  對(duì)于遞歸公用表達(dá)式來(lái)說(shuō),只需要在語(yǔ)句中定義兩部分:

? ?基本語(yǔ)句
? ?遞歸語(yǔ)句
? ?  先建一張表欄目表如下,欄目Id,欄目名稱,欄目的父欄目。
   

  現(xiàn)在使用CTE查詢其每個(gè)欄目是第幾層欄目的代碼如下:

WITH COL_CTE(Id,Name,ParentId,tLevel ) AS (--基本語(yǔ)句SELECT Id,Name,ParentId,0 AS tLevel FROM ColWHERE ParentId = 0UNION ALL--遞歸語(yǔ)句SELECT c.Id,c.Name,c.ParentId,ce.tLevel+1 AS tLevel FROM COL as c INNER JOIN COL_CTE AS ce   --遞歸調(diào)用ON c.ParentId = ce.Id )

SELECT * FROM COL_CTE
復(fù)制代碼
  輸出結(jié)果如下:
  


  0表示頂級(jí)欄目。1就是1級(jí)欄目。語(yǔ)法非常優(yōu)雅。就一個(gè)SELECT * FRON COL_CTE。這正是CTE強(qiáng)大的地方,但是,這要有約束,否則如果無(wú)限制遞歸可以會(huì)消耗掉非常多的系統(tǒng)資源。下面來(lái)看看如何限制遞歸的最大次數(shù)。


  如將上面的查詢語(yǔ)法改為:


復(fù)制代碼
WITH COL_CTE(Id,Name,ParentId,tLevel )
AS
(
? ? --基本語(yǔ)句
? ? SELECT Id,Name,ParentId,0 AS tLevel FROM Col
? ? WHERE ParentId = 0
? ? UNION ALL
? ? --遞歸語(yǔ)句
? ? 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)  --指定最大遞歸次數(shù)為2
復(fù)制代碼
  我們知道在上面的查詢中,要查到天河區(qū)新聞最少要遞歸3次,但是現(xiàn)在只遞歸2次,運(yùn)行是什么結(jié)果呢?


  
  提示信息如下:


  消息 530,級(jí)別 16,狀態(tài) 1,第 1 行
  語(yǔ)句被終止。完成執(zhí)行語(yǔ)句前已用完最大遞歸 2。
?  CTE是一種十分優(yōu)雅的存在。CTE所帶來(lái)最大的好處是代碼可讀性的提升,這是良好代碼的必須品質(zhì)之一。使用遞歸CTE可以更加輕松愉快的用優(yōu)雅簡(jiǎn)潔的方式實(shí)現(xiàn)復(fù)雜的查詢。
========

T-SQL查詢進(jìn)階--詳解公用表表達(dá)式(CTE)



簡(jiǎn)介


? ? ?對(duì)于SELECT查詢語(yǔ)句來(lái)說(shuō),通常情況下,為了使T-SQL代碼更加簡(jiǎn)潔和可讀,在一個(gè)查詢中引用另外的結(jié)果集都是通過(guò)視圖而不是子查詢來(lái)進(jìn)行分解的.但是,視圖是作為系統(tǒng)對(duì)象存在數(shù)據(jù)庫(kù)中,那對(duì)于結(jié)果集僅僅需要在存儲(chǔ)過(guò)程或是用戶自定義函數(shù)中使用一次的時(shí)候,使用視圖就顯得有些奢侈了.


? ? 公用表表達(dá)式(Common Table Expression)是SQL SERVER 2005版本之后引入的一個(gè)特性.CTE可以看作是一個(gè)臨時(shí)的結(jié)果集,可以在接下來(lái)的一個(gè)SELECT,INSERT,UPDATE,DELETE,MERGE語(yǔ)句中被多次引用。使用公用表達(dá)式可以讓語(yǔ)句更加清晰簡(jiǎn)練.


? ? ?除此之外,根據(jù)微軟對(duì)CTE好處的描述,可以歸結(jié)為四點(diǎn):


? ? ?可以定義遞歸公用表表達(dá)式(CTE)
? ? ?當(dāng)不需要將結(jié)果集作為視圖被多個(gè)地方引用時(shí),CTE可以使其更加簡(jiǎn)潔
? ? GROUP BY語(yǔ)句可以直接作用于子查詢所得的標(biāo)量列
? ? 可以在一個(gè)語(yǔ)句中多次引用公用表表達(dá)式(CTE)
?


公用表表達(dá)式(CTE)的定義


? ? 公用表達(dá)式的定義非常簡(jiǎn)單,只包含三部分:


? 公用表表達(dá)式的名字(在WITH之后)
? 所涉及的列名(可選)
? 一個(gè)SELECT語(yǔ)句(緊跟AS之后)
? ? 在MSDN中的原型:


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


AS?


( CTE_query_definition )?
?


? ?按照是否遞歸,可以將公用表(CTE)表達(dá)式分為遞歸公用表表達(dá)式和非遞歸公用表表達(dá)式.


?


非遞歸公用表表達(dá)式(CTE)


? ?非遞歸公用表表達(dá)式(CTE)是查詢結(jié)果僅僅一次性返回一個(gè)結(jié)果集用于外部查詢調(diào)用。并不在其定義的語(yǔ)句中調(diào)用其自身的CTE


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


? ?比如一個(gè)簡(jiǎn)單的非遞歸公用表表達(dá)式:


? ?1


? ?當(dāng)然,公用表表達(dá)式的好處之一是可以在接下來(lái)一條語(yǔ)句中多次引用:


? ?2


? ?前面我一直強(qiáng)調(diào)“在接下來(lái)的一條語(yǔ)句中”,意味著只能接下來(lái)一條使用:


? ?3


? ?由于CTE只能在接下來(lái)一條語(yǔ)句中使用,因此,當(dāng)需要接下來(lái)的一條語(yǔ)句中引用多個(gè)CTE時(shí),可以定義多個(gè),中間用逗號(hào)分隔:


? ?4


遞歸公用表表達(dá)式(CTE)


? ? 遞歸公用表表達(dá)式很像派生表(Derived Tables ),指的是在CTE內(nèi)的語(yǔ)句中調(diào)用其自身的CTE.與派生表不同的是,CTE可以在一次定義多次進(jìn)行派生遞歸.對(duì)于遞歸的概念,是指一個(gè)函數(shù)或是過(guò)程直接或者間接的調(diào)用其自身,遞歸的簡(jiǎn)單概念圖如下:


? ?1


? ? 遞歸在C語(yǔ)言中實(shí)現(xiàn)的一個(gè)典型例子是斐波那契數(shù)列:


long fib(int n)   
{  ?
? ? ?if (n==0) return 0;
?  if (n==1) return 1;   
? ? ?if (n>1) return fib(n-1)+fib(n-2);
}?
??


? ?上面C語(yǔ)言代碼可以看到,要構(gòu)成遞歸函數(shù),需要兩部分。第一部分是基礎(chǔ)部分,返回固定值,也就是告訴程序何時(shí)開(kāi)始遞歸。第二部分是循環(huán)部分,是函數(shù)或過(guò)程直接或者間接調(diào)用自身進(jìn)行遞歸.


? ?對(duì)于遞歸公用表達(dá)式來(lái)說(shuō),實(shí)現(xiàn)原理也是相同的,同樣需要在語(yǔ)句中定義兩部分:


? ?基本語(yǔ)句
? ?遞歸語(yǔ)句
? ?在SQL這兩部分通過(guò)UNION ALL連接結(jié)果集進(jìn)行返回:


? ?比如:在AdventureWork中,我想知道每個(gè)員工所處的層級(jí),0是最高級(jí)


? ?5


? ?這么復(fù)雜的查詢通過(guò)遞歸CTE變得如此優(yōu)雅和簡(jiǎn)潔.這也是CTE最強(qiáng)大的地方.


? ?當(dāng)然,越強(qiáng)大的力量,就需要被約束.如果使用不當(dāng)?shù)脑?#xff0c;遞歸CTE可能會(huì)出現(xiàn)無(wú)限遞歸。從而大量消耗SQL Server的服務(wù)器資源.因此,SQL Server提供了OPTION選項(xiàng),可以設(shè)定最大的遞歸次數(shù):


? ?還是上面那個(gè)語(yǔ)句,限制了遞歸次數(shù):


? ?6


? ?所提示的消息:


? ?7


? ?這個(gè)最大遞歸次數(shù)往往是根據(jù)數(shù)據(jù)所代表的具體業(yè)務(wù)相關(guān)的,比如這里,假設(shè)公司層級(jí)最多只有2層.


總結(jié)?


? ? CTE是一種十分優(yōu)雅的存在。CTE所帶來(lái)最大的好處是代碼可讀性的提升,這是良好代碼的必須品質(zhì)之一。使用遞歸CTE可以更加輕松愉快的用優(yōu)雅簡(jiǎn)潔的方式實(shí)現(xiàn)復(fù)雜的查詢。
========

總結(jié)

以上是生活随笔為你收集整理的SQL CTE学习总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。