1. 公共表達式CTE
公用表表達式 (CTE) 具有一個重要的優點,那就是能夠引用其自身,從而創建遞歸 CTE。遞歸 CTE 是一個重復執行初始 CTE 以返回數據子集直到獲取完整結果集的公用表表達式。
如下面的例子,可以遞歸把組織名放到一起。
其實CTE的作用就相當於子查詢

2.窗口函數、分區函數
窗口函數和聚集函數一樣都是對定義的行集(組)進行聚集,但是不像聚集一樣只返回一個值,窗口函數可以為每個組返回多個值,執行聚集的行組是窗口(因此稱為‘窗口函數’)。窗口函數是在聚集函數的基礎上加了一個 over(),所有的聚集函數都可以利用這種方式轉換成窗口函數。窗口函數是最后才執行的,在order by 之前,where和group by之后
Partition By分區子句:可以根據partition by子句定義行的分區或組,以完成聚集,如果使用空括號,那么整個結果集就是分區,窗口函數將對它進行聚集計算,可以把Partition By看成是移動的Group By,可以用Partition By對定義的行組計算聚集(當遇到新的組時復位),並返回每個值(每個組中的成員),而不是用一個組表示表中這個值的所有實例。

窗口函數除了用於聚集函數sum,count,avg等之外,還有row_number(計算行數),rank(排名),lead() ,lag()前移后移 在日常工作中使用也很大;
3.FOR XML Path
這個在sql server中的作用主要是把行數據轉列。在mysql中有group_concat,DB2中有listagg,而sql server中沒有,所以用for xml path
如下,我要取得年月,直接查詢是這樣的

當我在后面加上了for xml path 后就得到了一行的結果:

用字符串處理函數去掉前面的第一個逗號,就可以得到一個可用的字符串,用於存儲過程之類的;
4.PIVOT 和UNPIVOT 行列轉換函數
PIVOT:行轉列,下面的代碼實現的是,選擇orderid為71774和71780的兩個產品作為列名,以productID作為行,得到匯總數據

UNPIVOT 列轉行 貼一個官方教程的例子:
--Create the table and insert values as portrayed in the previous example.
CREATE TABLE pvt (VendorID int, Emp1 int, Emp2 int,
Emp3 int, Emp4 int, Emp5 int);
GO
INSERT INTO pvt VALUES (1,4,3,5,4,4);
INSERT INTO pvt VALUES (2,4,1,5,5,5);
INSERT INTO pvt VALUES (3,4,3,5,4,4);
INSERT INTO pvt VALUES (4,4,2,5,5,4);
INSERT INTO pvt VALUES (5,5,1,5,5,5);
GO
--Unpivot the table.
SELECT VendorID, Employee, Orders
FROM
(SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5
FROM pvt) p
UNPIVOT
(Orders FOR Employee IN
(Emp1, Emp2, Emp3, Emp4, Emp5)
)AS unpvt;
GO
運行結果:

5.Merge 的應用 主要用於更新數據,貼一個我寫的存儲
--Create the table and insert values as portrayed in the previous example.
CREATE TABLE pvt (VendorID int, Emp1 int, Emp2 int,
Emp3 int, Emp4 int, Emp5 int);
GO
INSERT INTO pvt VALUES (1,4,3,5,4,4);
INSERT INTO pvt VALUES (2,4,1,5,5,5);
INSERT INTO pvt VALUES (3,4,3,5,4,4);
INSERT INTO pvt VALUES (4,4,2,5,5,4);
INSERT INTO pvt VALUES (5,5,1,5,5,5);
GO
--Unpivot the table.
SELECT VendorID, Employee, Orders
FROM
(SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5
FROM pvt) p
UNPIVOT
(Orders FOR Employee IN
(Emp1, Emp2, Emp3, Emp4, Emp5)
)AS unpvt;
GO
6.動態sql
文本拼接語句 缺點:1.容易被注入,被黑 最好不用 2.容易報錯,如西安的拼音 xi'an
-- 實例1
DECLARE @sql NVARCHAR(1000)
SET @sql='select * from '+'[SalesLT].[Customer]'
PRINT @sql
--EXEC(@sql)
EXECUTE(@sql)
-- 實例2
DECLARE @sql NVARCHAR(1000),@i NVARCHAR(50)
--SET @i=100
SET @sql=N'select getdate()'
SET @sql=@sql+';select @i'
--EXECUTE(@sql)
DECLARE @we NVARCHAR(50)='xi''an'
EXEC sys.sp_executesql @sql,N'@i NVARCHAR(50)',@we -- 變量必須是unixcode 字符傳入
-- 實例3 可計算
DECLARE @sql NVARCHAR(1000),@i INT,@j int
--SET @i=100
SET @sql=N'select getdate()'
SET @sql=@sql+';select @i+@j'
--EXECUTE(@sql)
SET @i=500
SET @j=1
EXEC sys.sp_executesql @sql,N'@i INT,@j int',@i,@j
7.ON條件 在使用left jion時,on和where條件的區別如下:
on條件是在生成臨時表時使用的條件,它不管on中的條件是否為真,都會返回左邊表中的記錄。
where條件是在臨時表生成好后,再對臨時表進行過濾的條件。這時已經沒有left join的含義(必須返回左邊表的記錄)了,條件不為真的就全部過濾掉
舉個例子:
先創建t1,t2兩個表
CREATE TABLE t1 (
a CHAR(1)
)
INSERT INTO t1 VALUES('A'),('B'),('C')
CREATE TABLE t2 (
a CHAR(1)
)
INSERT INTO t2 VALUES('B'),('C'),('D')
以下是限制left join 左邊的表的結果,可以看到上面的才是我們想要的結果
以下是限制t2的結果,可以發現把條件放在on后面才是我們想要的結果

8.Except 和Intersect
比較兩個查詢的結果,返回非重復值。
EXCEPT 從左查詢中返回右查詢沒有找到的所有非重復值。
INTERSECT 返回 INTERSECT 操作數左右兩邊的兩個查詢都返回的所有非重復值,即二者交集。
還是用剛剛的表,t1中是ABC,t2中是BCD
那么EXCEPT返回的是A
INTERSECT返回的是BC

