1.認識selectsql
select的主要語法以下,這個很重要由於只有記住了總體的結構才能應對任何狀況。從中能夠看到select的強大主要就是創建在where、group by、having、order by這4個功能之上。數據庫
select [all | distinct] select_list [into new_table] [from table_source] express
[where search_condition]ide
[group by byexpression] 函數
[having search_condition]性能
[order by order_expression [asc|desc] ]網站
再來看這6個關鍵字的執行順序,顯然首先你得找到表取得最原始最龐大的數據,所以是from。接着是where用來進行過濾,而後group by和having開始執行,這樣數據的過濾已經完成因此就是select了,還有一個order by就是最後了。總結起來順序是from、where、group by、having、select、order by。若是再加上其它功能點,完整的執行順序爲from,on,join,where,group by,having,with rollup或cube,select,distinct,order by,top。關於from要注意當爲表使用別名時,一旦使用將不可以再用表名,只能使用as後的別名。where中可使用不少運算符組合過濾條件,系統過濾數據時將按照過濾條件以行爲單位一條條的進行過濾。在運算符中邏輯運算符的優先級爲not、and、or,並且not只能用於簡單條件式,不能用於包含and和or的複雜條件式。spa
group by爲咱們帶來了很是方便的分組功能,但要注意使用時select中只能是by後面的列名和彙集函數。當以by後面的列進行分組時,若是在select中包括其它的列好比columnA,那麼系統將不知道顯示分組後的columnA集合中的哪一條數據,這就是爲何不能select其它列的緣由。另外還要注意group by後的列名必須使用完整的名字,不能出現as的別名,緣由很簡單就是由於執行順序。having和where很類似,它們均可以對結果進行過濾。它們的區別則有2點:having中能夠包含彙集函數,而where是不容許有彙集函數的;having中出現的列必須是select中存在的,而where則可使用表中的任意列。日誌
在查詢中,若是要對多表進行查詢可以使用where或錶鏈接來進行關聯。和錶鏈接同樣,聯合查詢也是查詢中頗有效的手段,固然它和錶鏈接有着本質的區別,使用它有3個要注意的地方。首先union聯合的2個select語句,必需要有相同數量的列。在有相同列的狀況下,列還必須擁有類似的數據類型,最後select語句的順序也要相同。它的做用則是將多個select的結果集拼接在一塊兒並一塊兒顯示在結果集上,錶鏈接是將表進行關聯鏈接,而聯合查詢只是聯合了查詢出來的結果集,將這些結果集放到一塊兒顯示而已。使用union會發現它除了去除重複行外,還會對結果集進行一個排序,union all既不會去除重複行也不會對結果進行排序。關於union的用法讀者可本身去寫sql,這裏我要強調的是一個使用union常見的錯誤,數據表sql語句以下所示。code
--建立數據庫 create database testDb on ( name=testDb_data, filename='D:\testDb_data.mdf', size=4, filegrowth=10% ) log on ( name=testDb_log, filename='D:\testDb_data.log', size=2, filegrowth=10% ) --建立student表 use testDb create table student ( studentId int primary key, studentName nvarchar(16) not null, studentAge int default(18), studentSex nchar(1) ) create table teacher ( teacherId int primary key, teacherName nvarchar(16) not null, teachClass nvarchar(16) ) --爲student添加新的一列並添加主外鍵約束 alter table student add teacherId int,constraint teacher_FK foreign key(teacherId) references teacher(teacherId) select * from teacher insert into teacher values(1,'劉老師','安卓') insert into teacher values(2,'吳老師','網站') insert into teacher values(3,'王老師','物聯網') select studentId,studentName from student union all select teacherId,teacherName from teacher
若是在上面sql中的union後加上order by teacherId則會出現錯誤,提示上說order by項必須出如今選擇列表中,但是這裏teacherId明明就是選擇列表中的列啊。再仔細看看結果集會發現列上的名字是以第一個select中的列名爲標題的,所以這裏teacherId還真沒有出現選擇列表中。將teacerId改成studentId或studentName將會順利執行,關於結果集讀者可自行去試。
select studentId,studentName from student union all select teacherId,teacherName from teacher order by teacherId
select studentId,studentName from student union all select teacherId,teacherName from teacher order by studentId,studentName
在錯誤提示中還出現了intersect和except運算符,既然遇到了那確定要掌握。這3個運算符一塊兒出現說明它們有着某種緊密的聯繫。union如前面所說是兩個數據集的並集,intersect是兩個結果集的交集,except則是兩個結果集的差集。以上面的表爲例,若是使用intersect結果集將爲空,由於這兩個集合根本就沒有相同的數據集。使用except則返回的是第一個select返回的結果。使用union和except的結果以下所示。
select studentId,studentName from student union select teacherId,teacherName from teacher order by studentId,studentName select studentId,studentName from student except select teacherId,teacherName from teacher order by studentId,studentName
2.從select into到臨時表
在實際應用中開發者常常會須要去建立一個臨時的表存儲數據,select into正是扮演着這樣的角色。使用select into要注意建立的表名必須是惟一的,當咱們使用select into建立一個臨時的表時會在當前數據庫中創建一張新表。注意這張表已存在於當前數據庫中,這樣的話開發者還須要手動drop,若是忘記刪除將會致使數據庫中的表愈來愈多,並且頗有可能重名。爲了改進這一缺點,SQL利用了和C#裏的垃圾回收同樣的思想,就是由系統來刪除臨時表,固然咱們也能夠手動刪除。咱們只須要在設置臨時表名前加上#或##,一個#表示本地臨時表,兩個#表示全局臨時表。對於本地臨時表,最重要的特色是建立後只對當前此次會話狀態有效,一次會話狀態指的是客戶端與數據庫引擎的鏈接,這裏客戶端指登入者在數據庫上進行操做的一端,最終執行是須要鏈接數據庫引擎來完成的。好比select * into #table1 from student where studentId<4,執行後在系統數據庫中的tempdb可看到建立的臨時表。而且它的名字頗有意思,sql多是爲了防止重名吧,它還爲咱們建立的本地臨時表又添加了後綴名。當我關掉選項卡後,這個臨時表也就從tempdb中消失了,也就是說本地臨時表它屬於建立它的當前用戶,且只在當前會話狀態下可以使用。全局臨時表建立後,全部用戶均可見,當建立者介紹此次會話時好比我關掉選項卡,會發現全局臨時表和本地臨時表一塊兒被刪了。那是否是說全局臨時表和本地臨時表同樣,也是當前會話狀態結束就被系統刪除呢?答案是否認的,這裏和GC很像,若是沒有其餘任務引用這個全局臨時表,那它就被刪除。但要注意建立着會話狀態存在時,其餘任務可引用它建立的全局臨時表,建立着會話狀態存結束時,其餘任務將不能再引用這個全局臨時表,可是此時若是已有任務引用這個全局臨時表不會刪除,直至沒有任務引用它。另外臨時表並非只有select into能夠建立,咱們也能夠直接使用create table建立。
建立臨時表和非臨時表相比,有哪些優勢和缺點呢?首先咱們最關注的確定是性能,臨時表有一個特色那就是對它的操做不會記錄日誌文件,而非臨時表則會進行記錄,所以臨時表性能比非臨時表更快。在臨時表中,因爲本地臨時表只對當前用戶的當前會話狀態有效,那麼徹底不須要對本地臨時表進行加鎖,因此從這一點來講本地臨時表比全局臨時表更快。顯然這些性能的提升同時伴隨着某些功能將沒法使用,有利也有弊。臨時表與非臨時表同樣,也能夠創建索引、約束,只是不能創建外鍵約束,對於臨時表和非臨時表咱們均可以使用drop和truncate來刪除表。