1. 程式人生 > >SQL學習--Select(一)TOP、派生表、連接、謂詞

SQL學習--Select(一)TOP、派生表、連接、謂詞

eid from tro ant tst 便是 進行 opened title

TOP關鍵字

技術分享圖片
1 select top 4 WITH TIES t.title,sum(s.qty)as totalSales from sales s
2 left join titles t on s.title_id=t.title_id
3 group by t.title
4 order by totalSales
View Code

這裏的top 4 WITH TIES 是獲取前4條數據且需要重復值,但是請註意這個重復值是會影響返回數據的行
比如,重復值在第4行出現那麽可能就會返回5行數據(2個值的重復)
如果重復值在第二行或者第三行出現則只返回4條數據
另外需要註意的TOP N WITH TIES...需要與order by一同使用否則會報錯。

TOP N的缺點

  無法返回與查詢的GroupBy子句中的被分組的結果集的前幾條,
  這就標明TOP N指向的是整個查詢的結果集,而不是指向源表中或已被分類的組中的行。
  TOP N的運算順序在整個sql關鍵字的後邊。實例:

技術分享圖片
1 select t.state,t.stor_name,sum(s.qty)as totalSales 
2 from sales s join stores as t on s.stor_id=t.stor_id
3 group by t.state,t.stor_name
4 order by totalSales desc
5 
6 select top 1
t.state,t.stor_name,sum(s.qty)as totalSales 7 from sales s join stores as t on s.stor_id=t.stor_id 8 group by t.state,t.stor_name 9 order by totalSales desc
View Code

技術分享圖片

派生表

  select除了直接引用表或試圖外還可以使用派生表(子查詢),也叫邏輯表。它可以像表或視圖一樣查詢和鏈接

select au_lname,au_fname from (select * from authors) as a

  這個派生表是由select * from authors語法創建的,此處可以插入任何一個有效的查詢,

  但需要註意這裏使用別名且必須使用別名。因為T-SQL支持非列表的Select語句。

技術分享圖片
1 select * from (
2     select Blotchet-Halls as weightClass ,0 as lowBound ,112 as highBound
3     union all
4     select DeFrance as weightClass ,112 as lowBound ,118 as highBound
5     union all
6     select Green as weightClass ,127 as lowBound ,135 as highBound
7 )as w
8 order by w.lowBound
View Code

  例子中這個表不存在只是通過union all鏈接形成了一張邏輯表,邏輯表同時可以與表或試圖相連接

連接

  在內連接中,從句順序s不會影響到結果集。如果A等於B,那麽B就等於A。

而在外連接中則不然,表中的順序直接影響結果集中包含的哪些行及值

技術分享圖片
1 select sum(d.UnitPrice*d.Quantity) as totalOrders from Orders o 
2 left join [Order Details] d on o.OrderID+10=d.OrderID
3 left join Products p on d.ProductID=p.ProductID
4 
5 select sum(d.UnitPrice*d.Quantity) as totalOrders from [Order Details] d 
6 left join Products p on d.ProductID=p.ProductID
7 left join [Orders] o on o.OrderID+10=d.OrderID
8 --連接部分的先後順序改變了
View Code

技術分享圖片

在例子中故意把OrderID+10造成不匹配,觀察兩次查詢的運算結果,並不相同。

因為第一個查詢中引起的表Orders和Order Details的不匹配是在對列UnitPrice*Quantity匯總前,

而第二個查詢的不匹配是發生在匯總後。第二個查詢的情況下,會得到所有Details中的所有項的總和,

無論他與Orders是否匹配,而在第一個查詢中就不是這樣了。

看一下在2個查詢中不匹配的數據有哪些

技術分享圖片
1 select o.OrderDate,d.UnitPrice,d.Quantity from Orders o 
2 left join [Order Details] d on o.OrderID+10=d.OrderID
3 left join Products p on d.ProductID=p.ProductID
4 where o.OrderDate is null or d.UnitPrice is null
View Code

執行語句後,會發現正是我通過OrderID+10的那10條數據。

所以在使用外部鏈接存在不匹配鏈接的可能,所以一定要小心。

謂詞

  BETWEEN

    他的作用是判斷一個給定值是否落在了兩個值之間的內部

技術分享圖片
1 select au_lname,au_fname from authors 
2 where au_lname between s and zz
3 order by au_lname
View Code

帶有子集、變量和表達式的語句

技術分享圖片
1 Declare @au_id id
2 select @au_id=(select max(au_id) from titleauthor)
3 
4 select au_lname,au_fname from authors 
5 where au_id between (select min(au_id) from titleauthor) and (ISNULL(@au_id,zzzzzzzzzzzzz))
6 order by au_lname
View Code

盡管BetWEEN...AND很方便,但有時候很難界定多個區間的範圍。此時不如用逆向思維排除法,扣去必定發生的,就能得到不會發生的

  LIKE

  檢測一個值對字符串的模式匹配

  %:表示匹配任意字符

  _:表示只匹配一個字符

  [ab]:表示匹配a、b、ab

  EXISTS

  把子查詢作為單獨參數返回的判斷函數。在EXISTS前邊加NOT表示否定

  EXISTS在指定一個子查詢,檢測行的存在。遍歷循環外表,然後看外表中的記錄有沒有和內表的數據一樣的。匹配上就將結果放入結果集中

  如果成立則返回true不成立則返回false。如果返回的是true的話,則該行結果保留,如果返回的是false的話,則刪除該行,最後將得到的結果返回。

  在EXISTS中NULL值的處理

技術分享圖片
1 select title from titles t
2 where EXISTS(--此時為true
3     select * from( 
4         select *from sales
5         union all
6         select null,null,null,90,null,null
7     ) s--通過union all插入了一條為null,qty為90的數據
8 where t.title_id=s.title_id and s.qty>75)
View Code

  這個查詢結果最後還是空。為什麽呢?最後插入的null的那條數據是滿足where qty>75的為什麽沒有返回?

  答案是即便是返回了但是連接條件是titleid=titleid,而插入的數據titleID=null,null怎麽可能等於null呢?null誰都不等於,也不等於自己

  EXISTS和IN

  把EXISTS換成IN有一些特殊性。

技術分享圖片
1 select Count(title) from titles t
2 where t.title_id in(select title_id from sales)--16條
3 
4 select Count(title) from titles t
5 where t.title_id not in(select title_id from sales)--2條
6 
7 select Count(title) from titles t
8 where t.title_id not in(select title_id from sales union all select null)--0條
View Code

  IN在比較一個值與NULL是否相等的表達式總是返回NULL,所以不符合檢測,原因是其他行與null在同一列表所以返回null。這是IN和EXISTS的區別

  另外如果查詢語句使用了not in 那麽內外表都進行全表掃描,沒有用到索引;而not extsts 的子查詢依然能用到表上的索引。所以無論那個表大,用not exists都比not in要快。

  如果子查詢得出的結果集記錄較少,主查詢中的表較大且又有索引時應該用in, 反之如果外層的主查詢記錄較少,子查詢中的表大,又有索引時使用exists。

  同時不管使用哪種子查詢的方式都是比表連接要慢很多的,所以建議使用連接的方式。

  結果集為空

  EXISTS的另外一種用法是檢測結果集的多行。

  if exists(select * from sales)肯定要比if(select count(*) from sales )>0快的多,而且提供了一種不檢查系統對象來確定表是否為空的快速方法

  where和having以外的EXISTS

  EXISTS還可以做很多其他的工作,不僅僅是查詢返回的行。通過派生表還可以在case表達式和from子句中

  select case when EXISTS(Select * from titleauthor where au_id=a.au_id) then ‘true‘ else ‘false‘ end from authors a

 IN

技術分享圖片
1 select * from titles where title_id in
2 (
3     select title_id from (
4         select top 99999 title_id,count(*) as numberOrder from sales group by title_id order by numberOrder desc
5     )s
6 )
View Code

  

SQL學習--Select(一)TOP、派生表、連接、謂詞