網(wǎng)站首頁 編程語言 正文
在編寫T-SQL代碼時,往往需要臨時存儲某些結(jié)果集。前面我們已經(jīng)廣泛使用和介紹了兩種臨時存儲結(jié)果集的方法:臨時表和表變量。除此之外,還可以使用公用表表達(dá)式的方法。
公用表表達(dá)式(Common Table Expression)是SQL Server2005版本的引入的一個特性。CTE可以看組是一個臨時的結(jié)果集,可以再接下來來的一個SELECT,INSERT,UPDATE,DELETE,MERGE語句中多次引用。
一、3種方法比較
使用公用表達(dá)式CTE可以讓語句更加清晰簡練。與公用表達(dá)式作用類似的還有臨時表和表變量。下面給出三種方法的對比。
- 臨時表#:需要在臨時數(shù)據(jù)庫TempDB中通過I/O操作來創(chuàng)建表結(jié)構(gòu),一旦用戶退出SQL Server環(huán)境則自動被刪除。
- 表變量@:在內(nèi)存中以表結(jié)構(gòu)的形式存在,其定義與變量一致,其使用與表類似,不需要產(chǎn)生I/O。
- 公用表表達(dá)式with as:定義在內(nèi)存中保存的臨時存儲結(jié)果集對象,不產(chǎn)生I/O,不需要按照表變量這樣定義,使用方法和表類似。可以自己引用,也可以再查詢中被多次引用。
1、使用CTE好處
根據(jù)微軟對CTE好處的描述,可以歸結(jié)為四點:
- 可以定義遞歸公用表表達(dá)式(CTE)
- 當(dāng)不需要將結(jié)果集作為視圖被多個地方引用時,CTE可以使其更加簡潔
- GROUP BY 語句可以直接作用于子查詢所得的標(biāo)量列
- 可以在一個語句中多次引用公用表表達(dá)式(CTE)
二、WITH AS的含義
WITH AS-做子查詢部分(subquery factoring)。
它用于定義一個SQL片段,該片段會被是整個SQL語句所用到。如果WITH AS所以定的表名被調(diào)用兩次以上,則優(yōu)化器會自動將WITH AS所獲取的數(shù)據(jù)放入臨時表里,如果只是被調(diào)用一次,則不會。
可以通過materialize將WITH AS短語里的數(shù)據(jù)強制放入全局臨時表里。
WITH AS可以被緊跟著的一條SQL語句所使用多次,但不能被緊跟著的多條SQL語句使用。
WITH B AS
(
SELECT * FROM xxx WHERE Id > 5
)
SELECT * FROM B
三、CTE的定義
CTE的定義語法如下,主要包括3個部分。
- Expression_name:CTE表達(dá)式的名稱。
- Column_name:列名列表。
- CTE_query_definition:定義CTE結(jié)果集的Select查詢語句
WITH expression_name [(column_name [,...n] )]
AS
(
cte_query_definition
)
按照是否遞歸,可以將公用表(CTE)表達(dá)式分為遞歸公用表表達(dá)式和非遞歸公用表表達(dá)式.
1、非遞歸公用表表達(dá)式(CTE):
非遞歸公用表表達(dá)式(CTE)是查詢結(jié)果僅僅一次性返回一個結(jié)果集用于外部查詢調(diào)用。并不在其定義的語句中調(diào)用其自身的CTE。
非遞歸公用表表達(dá)式(CTE)的使用方式和視圖以及子查詢一致。
比如一個簡單的非遞歸公用表表達(dá)式:
WITH CTE_Test
AS
(
SELECT * FROM Person_1
)
SELECT * FROM CTE_Test
公用表表達(dá)式的好處之一是可以在接下來一條語句中多次引用:
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;
雖然以上引用了多次,但是只是一條語句,所以可以正常執(zhí)行。
如果多條語句引用,如下面這樣,是會報錯的。
with CTE_Test as (select * from Person_1)
select * from CTE_Test;
select * from CTE_Test;
輸出結(jié)果如下:
由于CTE只能在接下來一條語句中使用,因此,當(dāng)需要接下來的一條語句中引用多個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;
結(jié)果如下:
2、遞歸公用表表達(dá)式(CTE):
對于遞歸公用表達(dá)式來說,只需要在語句中定義兩部分:
- 基本語句
- 遞歸語句
先建一張表欄目表如下,欄目Id,欄目名稱,欄目的父欄目。
現(xiàn)在使用CTE查詢其每個欄目是第幾層欄目的代碼如下:
declare @table1 table(id int, Name varchar(10), ParentId int);
insert into @table1(id, Name, ParentId)
values(1, '國內(nèi)新聞', 0),
(2, '廣東新聞', 1),
(3, '廣州新聞', 2),
(4, '天河新聞', 3),
(5, '山東新聞', 1),
(5, '青島新聞', 5);
select * from @table1;
with COL_CTE(Id, Name, ParentId, tLevel) as (
--基本語句
select id, Name, ParentId, 0 as tLevel from @table1 where ParentId=0
union all
--遞歸語句
select c.id, c.Name, c.ParentId, ce.tLevel+1 as tLevel from @table1 as c
inner join COL_CTE as ce --遞歸調(diào)用
on c.ParentId=ce.Id)
select * from COL_CTE;
輸出結(jié)果如下:
0表示頂級欄目。1就是1級欄目。語法非常優(yōu)雅。就一個SELECT * FRON COL_CTE。這正是CTE強大的地方,但是,這要有約束,否則如果無限制遞歸可以會消耗掉非常多的系統(tǒng)資源。下面來看看如何限制遞歸的最大次數(shù)。
如將上面的查詢語法改為:
WITH COL_CTE(Id,Name,ParentId,tLevel )
AS
(
--基本語句
SELECT Id,Name,ParentId,0 AS tLevel FROM @table1 WHERE ParentId = 0
UNION ALL
--遞歸語句
SELECT c.Id,c.Name,c.ParentId,ce.tLevel+1 AS tLevel FROM @table1 as c
INNER JOIN COL_CTE AS ce
ON c.ParentId = ce.Id
)
SELECT * FROM COL_CTE
OPTION(MAXRECURSION 2) --指定最大遞歸次數(shù)為2
我們知道在上面的查詢中,要查到天河區(qū)新聞最少要遞歸3次,但是現(xiàn)在只遞歸2次,運行是什么結(jié)果呢?
提示信息如下:
消息 530,級別 16,狀態(tài) 1,第 1 行
語句被終止。完成執(zhí)行語句前已用完最大遞歸 2。
CTE是一種十分優(yōu)雅的存在。CTE所帶來最大的好處是代碼可讀性的提升,這是良好代碼的必須品質(zhì)之一。使用遞歸CTE可以更加輕松愉快的用優(yōu)雅簡潔的方式實現(xiàn)復(fù)雜的查詢。
原文鏈接:https://www.cnblogs.com/springsnow/p/9881118.html
相關(guān)推薦
- 2023-07-08 vscode上查看git的記錄,可以看到是誰多久前修改的代碼
- 2023-07-28 el-table 鼠標(biāo)懸浮時背景色改變
- 2022-11-18 Go與Redis實現(xiàn)分布式互斥鎖和紅鎖_Golang
- 2022-05-08 Python集合set的交集和并集操作方法_python
- 2022-08-17 C++超詳細(xì)實現(xiàn)堆和堆排序過像_C 語言
- 2023-02-01 Python中列表遍歷使用range和enumerate的區(qū)別講解_python
- 2022-04-15 ASP.NET?Core基礎(chǔ)之中間件_基礎(chǔ)應(yīng)用
- 2022-12-10 C++?Boost?Spirit進(jìn)階教程_C 語言
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支