SQL自學總結
來自專欄有關SQL5 人贊了文章
因為工作原因,要和資料庫打交道,除了公司內網自帶的指標平台、可供下載固定格式固定內容的有限張表之外,更多情況下需要自己從資料庫中靈活的取數,因此必須迅速學習和使用SQL語言。事實上,作為使用最為廣泛的資料庫語言,SQL是有些明顯的優點的:通用性強,幾乎所有重要的DSMS都支持SQL,針對不同的資料庫,如hivesql、mysql、sql server、oracle等,sql語法總體上大同小異,只是細微處的差別;簡單易學,關鍵詞很少,且貼近英文語法,普通的使用,一到兩周應該可以初步使用。我們公司使用的是ADHOC(advanced
data handler for on-line control)平台下的,hiveSQL語法,我的學習也是先基於標準SQL語法學習的。為了鼓勵大家,我想說我也是純小白一枚,零基礎,現在談談我的學習順序和一點心得。學習程序 也要發揚匠心精神,如切如磋,如琢如磨!
首先聲明,我們公司使用的資料庫,使用的代碼結構並不複雜,不需要很高級的語句,只用最基本的select、join、group by就可以,只要你語法正確、能順利跑下來,就可以了。所以,一開始我就奔著實用的態度選取資料學習的;大而全的專業書籍直接pass、高級技巧先放在一邊,號召「打好基礎」、一來就推薦好幾本類似《資料庫基礎》的純理論基礎大部頭也只能棄之不用。經過仔細搜索,我確定的方法是:紙質書一本《SQL必知必會(第4版)》(Ben Forta),在線刷題網站一個SQLZOO,http://sqlzoo.net/wiki/SELECT_basics/zh。書看兩遍,題刷兩遍,就能實現掌握基礎知識,大約70%?吧。學完這些,就可以硬著頭皮開始嘗試取數了,當然剛開始會有很多報錯,但是通過錯誤能學到更多、進步更快。這時要想進階的話,書可以看更全更專業一些的,刷題的話,可能要找找英文網站或者用一個資料庫管理軟體自己創建資料庫然後練習。關於自學方法和資料網上一搜一大堆,可以自己關注下吧,這裡不多說哦。
我想分享的是我學習的一點總結,和初始階段經過的一些雷區。
首先說語句結構。SQL 語句有一個讓大部分人都感到困惑的特性,就是SQL 語句的執行順序跟其語句的語法順序並不一致。當然也溫馨提示下,並非所有的資料庫對 SQL 語句使用相同的解析方式,這時具體情況具體對待吧,如果出現報錯,可以查閱相關幫助文檔或諮詢度娘。
如圖所示,我們書寫的時候,要注意關鍵字的順序,比如select,from寫完後,要先where,然後group by,然後having,order by永遠是放在最後面。但是實際執行的時候,系統先跳過select,從from開始、載入需要處理的表格,然後where進行初步過濾,注意這個過濾是在分組前進行過濾,然後通過group by進行分組,再利用having進行分組後的過濾、篩選滿足條件的組,然後才是select及其之後的語句。理解了這一點,也就很容易理解一些語法規定了,例如:where條件中不能跟聚合函數,而having後面可以;執行順序where>聚合函數(sum,min,max,avg,count)>having,order by是最後的顯示結果進行排序,必須放於最後,等等規定。
其次,是一些關鍵而重要的關鍵詞的使用。
(1)LIKE關鍵字,Like中最好只用%通配符。例如,要顯示包含單詞「United」為名稱的國家:WHERE name LIKE %United%;(正確),WHERE name LIKE *United*(報錯)。很多朋友會問,為什麼我在以上查詢時用「%」而不用「*」?我也查了資料,表明:%表示包含零個或更多字元的任意字元串。在搜索串中,%表示任何字元出現任意次數。百分號很兼容,但是其他的通配符都不一定兼容。也有說,星號往往使用在首尾的時候,例如姓張的名字:』張*』,或以強結尾:』*強』,等等。但為了保險起見,我建議以後在使用like關鍵字時,優先用%通配符。另外,注意「或」的用法,例如:提取以A或B開頭的國家名稱,
where name like 』A%』 or 』B%』(錯誤),where name like
(A% or B% )(錯誤),WHERE name LIKE A% OR name LIKE B%;(正確)。
(2)In,當結果不止一個時使用。例如:where name in
(『France』, 『Germany』, 『Italy』),這裡,一是注意要用圓括弧,二是,內容如果是字元串,要用英文狀態下的單引號。這裡還有些雷區,例如題目:選取在阿根廷Argentina及澳大利亞 Australia所在的洲份中,
where continent in
(select continent from world where name in (Argentina,Australia『) ) (正確)注意:這裡,嵌套括弧中的結果不止一個,就要用in(),而不能用等於=號,否則出錯。類似的,>,<,>=等等,後面都只能跟一個值,如果值多於一個,要用all,例如:where
25000000>= all(select populationfrom world b where b.continent = a.continent ),如果省了all,則會報錯。另外有一個雷區,in的對立面並不是NOT IN!not in等價的含義是<> all,例如In(『A』,』B』):A或者B;not in (『A』,』B』):不是A且B。為避免混淆,最好盡量避免或使用not in。
(3)關於聚集函數。為方便數據統計的檢索,SQL給出了5個聚集函數(aggregate
function),COUNT,SUM,AVG,MAX,MIN,計算並返回一個值。SQL的聚集函數在各種主要SQL實現中得到了相當一致的支持。聚集函數使用語法簡單,尤其當group by與聚合函數配合,十分好用!要求什麼的聚合函數,就先按照它來group by,然後直接count即可。不過,也有一些雷區要注意:①在不用聚合函數的時候,單獨用group by,group by 子句中必須包含所有的列,否則會報錯,但此時雖然成功執行了,group by在這裡並沒有發揮任何的作用,完全可以不用;若不用聚合函數,就是按照group by後面欄位的順序,把相同內容歸納在一起
③如果只有聚合函數,而沒有group by,則聚合函數用於聚合整個結果集 (匹配WHERE子句的所有行),相當於只分一組。
④where後面不能放聚合函數!無論是count還是sum。那麼如何解決呢,使用HAVING關鍵字!例如:having
sum(amount) >100⑤order by 後面是可以跟聚合函數的,即可以用聚合函數排序。
另外,除了Count(*)函數外,所有的聚合函數都忽略NULL值。
(4)注意語句末尾的分號!SQL是不區分大小寫的,也會忽略所有的空格。所以,SQL語句可以寫成多行,但是寫成長長的一行也是完全沒有錯的。但是,每一句話結束,如果不加分號,則出錯。這裡注意,select,create table,insert into 語句都是完整的一句話,分號結束。例如:
create table games (yr int,city varchar(255)) ;
insert into games (yr,city) values (2004,Athens) ;
insert into games (yr,city) values (2008,Beijing)
;insert into games (yr,city) values (2012,London) ;
SELECT * FROM games;
平時若只有一句話(例如select),可能沒加分號也能執行,但如果涉及創建表、插入、改寫,必須注意分號。值得一提的是case when語句,case when語句分為簡單case函數和case搜索函數,具體含義自行百度,但是例如:SELECT name, (逗號不可丟!case when本質上還是一個欄位的選取!)CASE WHEN
continent=『Oceania』 THEN (不用加continent=)Australasia』 ELSE continent (不可省) END。最後的End容易丟,千萬不要忘記。(5)最後,說兩個典型小問題的解決方法,看了很受啟發。一是,最後排序時若要將某一類放在最前或最後,可以利用case when,巧妙的引用輔助列,幫助排序。例如:
①ORDER BY (case
when subject in (Physics,Chemistry) then 1 else 0 end ), subject, winner結果:科目為(『Physics』,』Chemistry』)
的排在最後,其餘科目按subject升序排列,②ORDER BY (case
when subject in (Physics,Chemistry) then 1 else 0 end ) desc, yr desc, winner結果:將(『Physics』,』Chemistry』)
排在最前;同一科目種類時,按年份從新到老;同一科目、同一年份時,按獲獎者名字升序排列。二是,一個經典問題:分組後取每組的前幾條記錄。這裡看一個例子吧。
例:已知一個表, StudentGrade
(stuid--學號, subid--課程號, grade--成績)。PRIMARY KEY(stuid, subid)。想要:查詢每門課程的前2名成績。
方法①:
select distinct * from
studentgrade as t1where stuid in
(select top 2 stuid from
studentgrade as t2where t1.subid=t2.subid
order by t2.grade desc) order by subid, grade
desc思路:相同的表格自聯結,第二個表格將相同學科的所有學生按成績排序-倒序,選取前二。注意,mysql不支持select top n的語法!但是mysql可用limit來實現相關功能。
方法②:
select * from StudentGrade a
where (select count(1) from
studentGrade bwhere b.subId=a.subId and b.grade
>= a.grade) <=2思路:第一個>=號,限制了查詢條件是相同科目下成績從大往小排,第二個<=號,表示篩選個數是2個(從1開始的)。
注意,這裡大於等於、小於等於容易弄錯,尤其是第二個。
方法③:
select * from StudentGrade a
where (select count(1) from
StudentGrade b
where b.subid=a.subid and
b.grade> a.grade) <=1order by subId, grade desc
思路:這兩張表思路相同:相同表格自聯結,返回相同學科並且成績大於a表的影響行數。這就是查詢條件,再按 subId,grade 排序。
SQL才入手兩周,學習代碼一定要實踐,一定要實踐,一定要實踐(重要的事情說三遍)!畢竟不是科班出身,學習不夠系統,只能通過不斷實踐總結和不斷踩雷排雷來進步了,但是,重複重複重複,是時候發揚匠心精神了!
?Fe?
推薦閱讀:
※像對象一樣對待數據
※sql連接查詢中on篩選與where篩選的區別
※Cross Apply 與 Inner Join 的對抗
※請教一個SQL,詳情請看問題補充?
※數據分析入門之SQL演練
TAG:SQL |