?。?)具體用法模板:
CASE expression
WHEN value1 THEN returnvalue1
WHEN value2 THEN returnvalue2
WHEN value3 THEN returnvalue3
ELSE defaultreturnvalue
END
(2)具體使用示例:
假設我們有一個論壇網(wǎng)站,其中有一張User表{ UId,Name,Level },Level是一個int類型,代表了用戶等級類型,例如:1代表骨灰,2代表大蝦等;我們就可以用CASE來對其進行等值判斷了:
select Name,Rank=( case Level when 1 then '骨灰' when 2 then '大蝦' when 3 then '菜鳥' end) from User
?。?)具體用法模板:
CASE
WHEN condition1 THEN returnvalue1
WHEN condition2 THEN returnvalue2
WHEN condition3 THEN returnvalue3
ELSE defaultreturnvalue
END
注意:then后面返回的數(shù)據(jù)類型要一致, returnvalue1、 returnvalue2、 returnvalue3的數(shù)據(jù)類型必須一致。
?。?)具體使用示例:
假設我們有一張Score成績表,里面記錄有所有同學的成績,此時我們想要對所有成績進行一個評級,比如成績?nèi)绻?gt;=90那么則評為A級,>=80且<90則評為B級,這里我們怎來寫呢?
select studentId,rank=( case when english between 90 and 100 then 'A' when english between 80 and 89 then 'B' when english between 70 and 79 then 'C' when english between 60 and 69 then 'D' when english < 60 then 'E' else '缺考' end)from Score
就像使用普通的表一樣,被當作結果集的查詢語句被稱為子查詢。所有可以使用表的地方幾乎都可以使用子查詢來代替。例如:我們?nèi)绻业剿杏嬁埔话嗟耐瑢W信息,可以首先通過T_Class表找到計科一班的Id,然后再在T_Student表中找到所有ClassId為計科一班Id的行即可。
select * from T_Student where ClassId=( select Id from T_Class where Name='計科一班')
只有返回且僅返回一行、一列數(shù)據(jù)的子查詢才能當成單值子查詢。例如我們上面提到的例子,子查詢中只返回了一個ClassId,這就是單值子查詢。當子查詢跟隨在=、!=、<、<=、>、>=,<> 之后,或子查詢用作表達式,只能使用單值子查詢。
如果子查詢是多行單列的子查詢,這樣的子查詢的結果集其實是一個集合,那么可以使用in關鍵字代替=號。例如:我們?nèi)绻肟焖俚卦赥_Student表中刪除計科一班和計科二班的所有學生記錄,我們可以使用in關鍵字:
delete from T_Student where ClassId in( select Id from T_Class where Name='計科一班' or Name='計科二班')
exists是用來判斷是否存在的,當exists查詢中的查詢存在結果時則返回真,否則返回假。not exists則相反。
exists做為where 條件時,是先對where 前的主查詢詢進行查詢,然后用主查詢的結果一個一個的代入exists的查詢進行判斷,如果為真則輸出當前這一條主查詢的結果,否則不輸出。
exists后面的查詢稱為相關子查詢,即子查詢的查詢條件依賴于外層父查詢中的某個屬性值,其處理過程一般為:先取外層查詢中的第一個元組,根據(jù)它與內(nèi)層查詢中的相關屬性值處理內(nèi)層查詢,若where子句返回true,則將此元組放入結果表中,然后取外層查詢中的下一個元組,重復這個過程直到全部檢查完畢為止。
例如:我們有一張人員信息表,里邊有一個人員類型Id字段(pTypeId),它是一個外鍵,對應著人員類型表的主鍵ptId。如果我們有以下的SQL語句,使用Exists關鍵字則可以有如下的理解:
select * from Employee e where exists (select * from EmployeeType et where e.pTypeId=et.ptId)
那么,在這句SQL的執(zhí)行過程中,我們可以將其理解為一個雙重的for循環(huán),外邊是主表的循環(huán)遍歷,然后將其放到一個temp變量中,再進入從表的for循環(huán),并與從表的項進行一個一個的按照匹配規(guī)則(這里是e.pTypeId=et.ptId)進行匹配,如果有匹配成功則返回true,并且將這一行記錄放到要返回的結果集中,否則返回false。
這里假設每頁的頁大小為10條記錄
?。?)如果我們要獲取第一頁的數(shù)據(jù),也就是前10個:
select top 10 * from Account
(2)現(xiàn)在我們要獲取第一頁之后的數(shù)據(jù),也就是第20個~最后一個:
select * from Account where Id not in (select top 10 Id from Account)
?。?)現(xiàn)在我們對第20個~最后一個的數(shù)據(jù)集中取前10個也就成為第二頁的數(shù)據(jù)了:
select top 10 * from Account where Id not in (select top 10 Id from Account)
(4)將上述代碼總結為分頁代碼,設頁大小為pageSize,請求頁號為pageIndex:
select top @pageSize * from Account where Id not in (select top ((@pageIndex-1)*@pageSize) Id from Account)
PS:這種分頁方式的缺點是如果要取很多頁之后的數(shù)據(jù),那么就要取出前面很多頁的ID,查詢開銷較大,執(zhí)行效率也就低下。
從圖中可以看出,在小數(shù)據(jù)量的對比下,Top N的查詢開銷較小。但是在大數(shù)據(jù)量的對比下,Row_Number的方式會取得更高的查詢效率以及較小的開銷。
?。?)SQL Server 2005后增加了Row_Number函數(shù),可以簡化分頁代碼的實現(xiàn)。首先,Row_Number()是一個排序函數(shù),它可以生成一個有序的行號(如果單靠ID來排序,中間存在斷層,例如某一個ID行已經(jīng)被刪除了)。根據(jù)MSDN的定義:返回結果集分區(qū)內(nèi)行的序列號,每個分區(qū)的第一行從 1 開始。而排序的標準是什么呢?這個就要靠緊跟其后的OVER()語句來定義了。這里我們可以通過一個示例來看看,其生成的行號如何。
select *,ROW_NUMBER() OVER(order by Id) as RowNum from Account
?。?)根據(jù)ROW_NUMBER()的使用,我們可以將其應用到分頁上,于是我們可以寫出以下的代碼來實現(xiàn)獲取第二頁的數(shù)據(jù)集:
select * from ( select *,ROW_NUMBER() OVER(Order by Id) as rownum from Account) as twhere t.rownum between 11 and 20order by t.Id asc
?。?)將上述代碼總結為分頁代碼,設頁大小為pageSize,請求頁號為pageIndex:
select * from ( select *,ROW_NUMBER() OVER(Order by Id) as rownum from Account) as twhere t.rownum between (@pageIndex-1)*pageSize+1 and @pageSize*pageIndexorder by t.Id asc
默認情況下,使用Join則代表Inner Join內(nèi)連接,表示兩個表根據(jù)某種等值規(guī)則進行連接。例如下面示例:查詢所有學生的學號、姓名及所在班級
select p.Id,p.Name,c.Name from T_Person p join T_Class c on p.ClassId=c.Id
例如:查詢所有學生(參加及未參加考試的都算)及成績,這里涉及到學生表及成績表,題目要求參加及未參加考試的都要列出來,于是以學生表為基準,對成績表進行左連接:
select * from Student sleft join SC sc on s.S#=sc.S#
可以通過運行結果圖,看到王二小這個童鞋沒有參加考試,也就沒有成績。
例如:要查詢出所有沒有參加考試(在成績表中不存在的學生)的學生的姓名。于是還是可以以學生表為基準,但是要對成績表進行右連接:
select * from Student sright join SC sc on s.S#=sc.S#
此種連接在實際應用中不算常見的,但卻是理論基礎,因為它代表了笛卡爾積。其實,所有連接方式都會先生成臨時笛卡爾積表,笛卡爾積是關系代數(shù)里的一個概念,表示第一個表的行數(shù)乘以第二個表的行數(shù)等于笛卡爾積結果集的大小。
select * from Student scross join SC sc
這里假如Student表中有10行記錄,SC表中有20行記錄,那么兩表進行交叉連接笛卡爾積運算會得到10*20=200行記錄的結果集。
從用戶角度來看,一個視圖是從一個特定的角度來查看數(shù)據(jù)庫中的數(shù)據(jù)。
從數(shù)據(jù)庫系統(tǒng)內(nèi)部來看,一個視圖是由SELECT語句組成的查詢定義的虛擬表。
從數(shù)據(jù)庫系統(tǒng)內(nèi)部來看,視圖是由一張或多張表中的數(shù)據(jù)組成的;從數(shù)據(jù)庫系統(tǒng)外部來看,視圖就如同一張表一樣,對表能夠進行的一般操作都可以應用于視圖,例如查詢,插入,修改,刪除操作等。
例如,我們可以創(chuàng)建一個學生成績詳細信息視圖,對一個需要進行三表連接的查詢進行封裝:
create view vw_scasselect s.S#,s.Sname,c.Cname,sc.Score from Student sjoin SC sc on s.S#=sc.S#join Course c on sc.C#=c.C#
然后,我們對vw_sc進行select查詢: