SQLServer學習筆記系列6

一.寫在前面的話

時間是咱們每一個人都特別熟悉的,可是到底它是什麼,用什麼來衡量,可能不少人會愣在那裏。時間能夠見證一切,也能夠消磨一切,那些過往的點點滴滴可思可憶。回想往年清明節事後,在家鄉的晚上總能聽見陣陣的青蛙叫聲,那是清脆的叫聲,那是家鄉的味道。時間一轉眼,貌似那些日子已離我遠去很久,在城市的喧囂浮華中,找尋不到那種心裏的寧靜。感嘆時間流逝的同時,懷念過去的點點滴滴。我想在繁華的都市中尋找一種安定的心情來學習,或許是一種不錯的方式。學習纔會讓咱們認清本身,找回自我,作心裏的強者,不驕不躁,積極進取,陽光自信。努力的人最幸運!Just do it!html

                                             從今之後,別再過你應該過的人生,去過你想過的人生吧!——梭羅sql

二.派生表

派生表也就是特殊的子查詢,用在from以後的子查詢,同時這裏注意一點:派生表必須起別名。函數

例如:加入咱們要查詢,顧客信息,以及每一個國家所擁有的顧客數量。那麼咱們能夠這樣寫:sqlserver

 

1  
2  SELECT * FROM
3  (
4  SELECT custid,COUNT(*) OVER(PARTITION BY country) AS N'顧客數量'
5  FROM Sales.Customers
6  ) t

括號裏面的子句就至關於一個派生表,假如咱們在這裏不給 COUNT(*) OVER(PARTITION BY country) 起別名,那麼select * 就不知道取出哪一列,因此會報錯。學習

同時有另外一種起別名的方法,也就是在外面其別名,一樣能夠達到效果,寫法以下:測試

1  SELECT * FROM
2  (
3  SELECT custid,COUNT(*) OVER(PARTITION BY country)
4  FROM Sales.Customers
5  ) t(custid,顧客數量)

三.CTE(公用表表達式)

(1)常見CTE用法ui

如何使用CTE,在這裏必須先定義,而且命名。定義形式以下:spa

1  WITH USE_Customers
2  AS
3  (
4    SELECT companyname,country
5    FROM Sales.Customers 
6    WHERE country='USA'
7  )

那麼咱們要使用CTE,只要查詢對應的CTE名稱便可。3d

1  WITH USE_Customers
2  AS
3  (
4    SELECT companyname,country
5    FROM Sales.Customers 
6    WHERE country='USA'
7  )
8  
9  SELECT * FROM USE_Customers

結果如圖所示:code

可是要注意的一點是:使用CTE時,外部查詢一旦完成,那麼CTE的生命期就結束了,若是須要在查詢這個CTE,此時失效。

同時也能夠給CTE每列其別名,其中也存在在表達式內部和外部起別名,看我的喜歡哪一種方式。

1  WITH USE_Customers
2  AS
3  (
4    SELECT companyname AS N'公司名',country AS N'國家名'
5    FROM Sales.Customers 
6    WHERE country='USA'
7  )
8  
9  SELECT * FROM USE_Customers
1  WITH USE_Customers(公司名,國家名)
2  AS
3  (
4    SELECT companyname ,country 
5    FROM Sales.Customers 
6    WHERE country='USA'
7  )
8  
9  SELECT * FROM USE_Customers

其查詢結果都爲:

(2)有參數的CTE

使用有參數的CTE能夠屢次使用,只須要改變參數的傳遞值便可。

例如:查詢每一個國家的顧客信息,國家存在USA,UK........,多個國家,此時咱們將國家做爲一個變量,相似於C#中的參數。聲明CTE以下:

 1  DECLARE @country NVARCHAR(300);
 2  SET @country='USA';
 3  WITH USE_Customers(公司名,國家名)
 4  AS
 5  (
 6    SELECT companyname ,country 
 7    FROM Sales.Customers 
 8    WHERE country=@country
 9  )
10  
11  SELECT * FROM USE_Customers

假如要查詢UK國家的一些顧客信息,那麼只須要改變set @country=‘UK’就能夠查詢了,不須要改變CTE的結構。

 1  DECLARE @country NVARCHAR(300);
 2  SET @country='UK';
 3  WITH USE_Customers(公司名,國家名)
 4  AS
 5  (
 6    SELECT companyname ,country 
 7    FROM Sales.Customers 
 8    WHERE country=@country
 9  )
10  
11  SELECT * FROM USE_Customers

(3)複雜的CTE使用

【1】在這裏,假如咱們要查詢年度訂單數量在10以上的顧客信息。按照通常的思惟,咱們能夠講訂單按照年度分組,而後用聚合函數count統計每一個顧客下的訂單數量,接着找出大於訂單數量大於10的顧客信息。因此咱們能夠下sql以下:

查詢結果如圖所示:

【2】那麼同時可使用子查詢,即派生表依次來出來問題。

第一步,先查詢訂單的年份,顧客的信息

1  SELECT  YEAR(orderdate) AS orderyear,custid
2  FROM Sales.Orders

第二步,根據年份進行分組,統計每位顧客的訂單數量。第一步查詢出來的結果做爲子查詢,即派生表。

1  SELECT orderyear,custid,COUNT(*) AS N'訂單數量'
2  FROM
3  (
4      SELECT  YEAR(orderdate) AS orderyear,custid 
5      FROM Sales.Orders
6  ) AS t1
7  GROUP BY orderyear,custid

 

第三步,找出訂單數量大於10的顧客信息。

 1  SELECT orderyear,custid,ordercount
 2  FROM
 3  (
 4  SELECT orderyear,custid,COUNT(*) AS  ordercount
 5  FROM
 6          (
 7              SELECT  YEAR(orderdate) AS orderyear,custid 
 8              FROM Sales.Orders
 9          ) AS t1
10          GROUP BY orderyear,custid
11  ) AS t2
12  WHERE ordercount >10

是否是感受使用子查詢,一層套一層,不過度析之後,符合咱們通常解決問題的思路先作哪一步,再作哪一步。在這裏咱們可使用新學的CTE來解決問題。

【3】使用CTE來解決年度訂單數量在10以上的顧客信息。

好處就是定義好的CTE,能夠直接拿來做爲一個派生表使用,那麼咱們能夠這樣定義CTE,按照上述的分析,分別定義三個CTE,最後查詢出結果:

須要注意的一點事:定義多個CTE之間用逗號(,)隔開便可,不須要使用with從新定。

 1  WITH yearorder01
 2  AS
 3  (
 4        SELECT YEAR(orderdate) AS orderyear,custid
 5        FROM Sales.Orders
 6  ),
 7  yearorder02
 8  AS 
 9  (
10          SELECT orderyear,custid,COUNT(*) AS ordercount
11          FROM yearorder01
12          GROUP BY orderyear,custid
13  ),
14  yearorder03
15  AS
16  (
17         SELECT orderyear,custid,ordercount
18         FROM yearorder02
19         WHERE  ordercount>10
20  )
21  
22  
23  SELECT * FROM yearorder03

查詢結果如圖所示,跟子查詢結果相同:

四.多CTE

多個CTE的使用會讓咱們更加方便的進行相關子查詢。例如:假如咱們要查詢年度有多少顧客,測試該怎麼處理了?咱們會想到,仍是根據年度分組,而後聚合count(custid)求出每一年度有多少顧客,其中要注意去重,即相同的custid屬於同一個顧客,因此要寫成count(distinct custid)。sql以下:

1  
2  SELECT YEAR(orderdate) AS orderyear,COUNT(DISTINCT custid) AS  custcount
3  FROM Sales.Orders
4  GROUP BY YEAR(orderdate)

如今加入有一個需求,就是要作一個查詢,求出當年的顧客數量以及前一年的顧客數量,同時算出二者之間顧客數量隔了多少,咱們又該怎麼處理了?要求前一年和當前年的差,那麼就能夠想到,是否能夠把當前查出來的結果集作一次鏈接,不就能夠獲得前一年和當前年的嘛,因此sql以下:

 1  SELECT pre_orderyear,now_orderyear,pre_custcount,now_custcount,
 2        (now_custcount-pre_custcount) AS N'顧客數量差'
 3  FROM 
 4  (
 5  SELECT YEAR(orderdate) AS now_orderyear,COUNT(DISTINCT custid) AS now_custcount 
 6  FROM Sales.Orders
 7  GROUP BY YEAR(orderdate)
 8  ) AS t1
 9  LEFT JOIN 
10  (
11   SELECT YEAR(orderdate) AS pre_orderyear,COUNT(DISTINCT custid) AS  pre_custcount
12  FROM Sales.Orders
13  GROUP BY YEAR(orderdate)
14  ) AS t2
15  ON t1.now_orderyear=t2.pre_orderyear+1;

其中就是將結果集作一個自身的鏈接,可是咱們是否是發現這樣寫顯得很冗餘了,做爲程序猿的咱們就是要寫出儘可能簡潔明瞭的code,Don‘t  repeat yourself !在這裏咱們的CTE就發揮出他的做用,定義的CTE能夠在下一步中使用,做爲查詢條件。那麼咱們看看用CTE如何實現?同理,咱們使用CTE以前就必須先定義CTE,這裏咱們定義一個CTE,查詢出每一年的顧客數量,其實跟上面的sql同樣,只不過定義成CTE的形式。

 1  WITH custcount
 2  AS
 3  (
 4  SELECT YEAR(orderdate) AS orderyear,COUNT(DISTINCT custid) AS  custcount
 5  FROM Sales.Orders
 6  GROUP BY YEAR(orderdate)
 7  )
 8  
 9  SELECT t1.orderyear AS nowYear,t2.orderyear AS preYear,t1.custcount AS nowcount,t2.custcount AS precount,
10        (t1.custcount-t2.custcount) AS N'顧客數量差'
11  FROM custcount t1
12  LEFT JOIN  custcount t2
13  ON t1.orderyear=t2.orderyear+1;

其結果如圖所示:

其實咱們從sql語句能夠看出,CTE的簡潔之處,就在於,能夠將已定義的CTE重複使用進行鏈接,相比於子查詢自身的鏈接,更加簡潔,容易操做,加入須要的計算,咱們只須要改變CTE的定義便可。

五.遞歸CTE

遞歸的CTE在遞歸查找中應用的很是多,其實能夠看作一種層次的查找關係,好比公司通常狀況下是分一級部門,二級部門,三級部門.......那麼一級部門下包含多個二級部門,二級部門又包含多個三級部門等等.....,舉例說明:公司內部有上下級的關係,假如咱們要查找某個員工的上級是誰,通常狀況下咱們能夠作一次自身的鏈接,找出上級是誰。

例如:查找全部顧客的上級信息。也就是在HR.employees裏面的mgrid等於員工的empid,那麼找到的那個員工幾位mgrid的上司。sql以下:

1  SELECT t1.empid,t1.mgrid,t1.lastname,t2.empid,t2.lastname
2  FROM HR.Employees t1 LEFT JOIN hr.Employees t2 
3  ON t1.mgrid =t2.empid

由於爲了確保全部的員工信息都顯示,因此在這裏用到餓左鏈接,保證左邊表裏面的員工都存在。其結果如圖:

這裏再進一步討論,加入咱們要查詢某個員工下面全部的下屬信息,怎麼辦了?好比要查詢2號員工的下屬信息,咱們這能夠這樣寫sql:

1  SELECT * FROM 
2  hr.Employees WHERE mgrid=2

咱們了能夠看到2號員工下屬有3號和5號,那麼5號員工可能也有下屬,接着查詢:

1  SELECT * FROM HR.Employees
2  WHERE mgrid in
3  (SELECT empid FROM 
4  hr.Employees WHERE mgrid=2
5  ) 

咱們能夠看到,查出的結果中有4,6,7,8,9,那麼4,6,7,8,9下面是否還有下屬了,是否是還須要接着查詢了,這樣查下去就是無止盡的,由於咱們不知道有多少層,因此遞歸CTE就是解決這樣的問題的,遞歸CTE能夠查詢出因此層級的狀況,直至結束。首先遞歸CTE須要定義一個起點,即查詢起點。而後根據定義的CTE自身作遞歸查詢,直至找出全部的節點信息。以下:

 1 DECLARE @mgrid INT;
 2 SET @mgrid=2;
 3 WITH Emplist
 4 AS
 5 (
 6     --此處爲起點,執行一次
 7     SELECT empid,lastname,mgrid
 8     FROM HR.Employees
 9     WHERE mgrid=@mgrid
10     UNION ALL
11     
12     --遞歸開始
13     
14     SELECT e.empid,e.lastname,e.mgrid
15     FROM HR.Employees e INNER JOIN Emplist m
16     ON e.mgrid=m.empid 
17     
18 )
19 
20 SELECT * FROM Emplist

定義一個變量,接受要查詢的員工id,設爲2,即查詢2號員工下面全部的下屬信息。

關於CTE的運用還有不少,這裏只列出一些基本的用法,若有想法,能夠提出,但願一塊兒學習!

sqlserver學習筆記1:http://www.cnblogs.com/liupeng61624/p/4354983.html

sqlserver學習筆記2:http://www.cnblogs.com/liupeng61624/p/4367580.html

sqlserver學習筆記3:http://www.cnblogs.com/liupeng61624/p/4375135.html

sqlserver學習筆記4:http://www.cnblogs.com/liupeng61624/p/4388959.html

sqlserver學習筆記5:http://www.cnblogs.com/liupeng61624/p/4392746.html

 

但願各位大牛給出指導,不當之處虛心接受學習!謝謝!

相關文章
相關標籤/搜索