SQL-Server使用点滴(一-数据对象篇)
前言
SQL的語法比較簡單,學起來相比界面UI控制要簡單得多,但是SQL在企業級應用中又是如此的重要,以至于很多開發人員都把重點放在SQL上。
SQL并沒有面向對象的概念,最復雜的設計也不過是表值函數,以及基于ORM思維的表類型映射處理了,還包括一些通用的程序數據結構處理。當然,SQL真正的精華在我看來,是如何優化其執行效率。各類數據庫范式的應用以及索引的構建讓數據效率足夠強大,同時又結合了數據庫結構設計與現實工程中的聯系。一般程序語言總會在程序可讀性和代碼效率性中間遇到矛盾,而SQL直觀的代碼表達和復雜的關系結構運算,讓她變成效率處理中的王者。我們幾乎不用考慮太多的代碼可讀性問題,只需要關注規范及效率即可。
說這么,反回說來還是落在現在的這片文檔上,本文著力收錄一些基礎通用的SQL語法點,并且包含一些巧妙的處理內容。舉例力求少和精簡,使之即可以作為一個文檔手冊,又可以作為SQL知識擴展使用。
一,基礎的增刪改查:
SQL中大概可以分為三種操作的對象類型:數據庫,數據表,記錄。這三種對象都有其對應的操作語句。
1,【數據庫】操作
????? 1>, 創建數據庫
??????????? if exists(Select * from sys.databases where name='數據庫名')????????????????? --先判斷要建立的數據庫是否存在
????????????Drop Database 數據庫名??????????????????????????????????????????????????????????????????????? --刪除數據庫
??????????? Go
??????????? Create Database 數據庫名
??????2>,刪除數據庫:參照1>
????? 3>,備份數據庫
???????????? --先創建備份數據的設備(Device)
??????????????use master????????? --當前庫轉到主庫
????????????? Exec sp_addumpdevice 'Disk', 'Testbak', '路徑\文件名.dat'???????????? --這里Disk為設備類型,還可以寫Pipe(管道),tape(磁帶機),不過都使用較少。
???????????????????????????????????????????????????????????????????????????????????????????????????????????? --Testbak是為當前設備起的別名
????????????? --開始備份
????????????? Backup Database?要備份的數據庫名 to Testbak
?????? 4>數據庫修改操作使用的比較少,一般即便要修改也是通過企業管理器來進行,具體的語句這里不寫了。
?
?????? 2, 【數據表】及各類約束的操作
???????1>創建新表
??????????a> 標準建表:?Create Table TbName(Col1 Type1[not null] [ Primary key] Default(Value1), Col2 Type2[null],...)
????????? b>利用查詢建表: Select * into 目地表名 from 原表名
??????????????這種建表的方式,不能把原表中的約束復制到新表中,必須通過其他語句逐一復制。如果利用這樣的語句建立一個空表結構,可以增加 Top 0 或者 Where 1=0即可。
????????????? /*還有一種查詢建表的方式: Create Table TbName as Select Col1,Col2 From TbOldName [Definition only]
????????????? 這里的Definition only 也是只建立表結構的意思,第二種查詢建表只對Oracle數據庫有效。*/
???????2>刪除表
?????????? Drop Table TbName
???????3>修改表
?????????? a>增加列
???????????????Alter Table TbName Add ColName ColType [Default Value]
???????????b>刪除列
?????????????? Alter Table TbName Drop Column ColName
?????????? c>添加/刪除 主鍵 (這里也可以通過建立和刪除約束的方法實現同樣的效果)
???????????????Alter Table TbName Add Primary Key (ColName)?? --注意,這樣設置的列,必須是不為空的列,為空列設置主鍵會報錯。
?????????????? /*Alter Table TbName Drop Primary Key(ColName)? 這種語法只適合Oracle,SqlServer只有通過刪除主鍵約束的方式來刪除主鍵)
??????????? d>更改列的字段類型
????????????? Alter Table TbName Alter ColName ColType?????????? --注意,不是所有類型列都可以轉換的,其兼容級別可以通過?sp_dbcmptlevel 來查詢
???????????????????????????????????????????????????????????????????????????????????????--另外,對已經有約束的列,也是不允許更改的,必須先刪除其約束
????????4>修改列的高級附屬屬性
??????????? a>索引的建立與刪除:
????????????????Create [Unique] Index IdxName On TbName(ColName1, ..)???? --這里的Unique 效果也可以通過約束來實現,效果細節有差別。
??????????????? Drop Index IdxName on TbName
注意,索引是不可以更改的,如果要修改原有的索引,必須通過刪除,然后重建來實現。
??????????? b>約束的使用:
約束的對象是表,雖然其大多是對字段起作用。約束分四種:主鍵PK(PRIMARY KEY),默認值DF(DEFAULT),唯一UQ(UNIQUE),
???????????????? 規則檢查CK(Check), 外鍵約束FK(Foreign Key).
???????????????? (1) 建立
???????????????? 約束都是以Alter Table 開始的。
???????????????? Alter Table TbName Add/Alter ColName CONSTRAINT?約束名?約束類型??? --這里允許省略 CONSTRAINT?約束名 直接跟約束類型,系統會自動生成約束名
???????????????? 也可以直接建約束
???????????????? Alter Table TbName Add CONSTRAINT? 約束名 約束類型?? --整體約束
??????????????? 或者在建表的時候,直接增加約束:
??????????????? ?Create Table TbName(
??????????????????? Col1 ColType1 約束類型..,????? --這種方式,約束名會由系統自動生成.
??????????????????? Col2...,
????????????????????...
????????????????????CONSTRAINT? 約束名 約束類型..??? --這種方式,適合對多字段建立整體約束例如Check
??????????????????? )
???????????????? (2) 刪除??????????????????
???????????????????? Alter Table?TbName??Drop CONSTRAINT? 約束名
???????????????? (3)約束使用示例:
?????????????????★主鍵:Alter Table?TbName ADD CONSTRAINT PK_主鍵約束名后部 Primary key?[NOCLUSTERED]([ColName])
?
?????????????????★默認值:Alter Table?TbName ADD CONSTRAINT DF_默認約束名后部 DEFAULT (DefaultValue) FOR [ColName]
?????????????????當然也可以這么寫: Alter Table TbName?Add?ColName?ColType Default(DefaultValue)??[not null]? --系統自動生成約束名,也可以在Create Table中這么寫.
?
?????????????????★唯一約束: Alter Table?TbName?? ADD CONSTRAINT UQ_唯一約束命后部 UNIQUE (ColName)?? --同樣,也可以在增加字段時,由系統自動命名
????????????????????? 自動命名寫法: Create Table TbName(..., ColName ColType Unique, ...)??????
???????????????? 這里需要強調下主鍵約束,唯一約束,唯一性索引的區別:
?????????????????i>主鍵約束會自動創建唯一性索引,并且是非空的,在表中無其他聚集索引的情況下,會自動標志為聚集索引(Clustered).
ii>唯一性索引,必須主動命名,無法象約束一樣由系統自動生成。其值雖然唯一,但是允許多個空值的存在。其主要的意義是加速表遍歷。
???????????????? iii>唯一性約束,可以在定義字段時自動由系統生成,并且不允許有多個空值(可以有一個Null),其存在的意義是保證字段的完整性,而不是訪問速度。
? ? ? ? ? ? ? ? ?iv>這里要對第三條進行一個修正,在SQL2008以后的數據庫中,建立唯一約束時,會自動建立出一個唯一索引,并標識出Unique Key(與唯一索引不同),
? ? ? ? ? ? ? ? ? ? ?而且,本身約束也會檢查是否有多個null值,并因重復而阻止。帶Unique Key標志的索引,會直接影響并出現在視圖:information_schema.key_column_usage。?
?
???????????????? ★規則檢查約束: Alter Table TbName Add [Constraint CK_檢查約束后部] Check(檢查性約束的布爾表達式)?
Check約束一般是精確限制一個或幾個字段的取值范圍,以及實現一些字串的掩碼。其定義比其他的約束要隨意得都,雖然可以在新增
列的定義后面附加Check約束,但是它并不依附在某一列上,而是一個全局性的約束。并且,其約束名稱也可以隨意省略。
???????????????? 注意:i>有Null參與的比較運算,其結果被Check表達式判定為Unknow值,而不是False值,這個不受其限制的;
?????????????????????????ii>在Delete 語句中,增加約束是不起作用的 例如:Delete TbName Check(表達式)
???????????? ??????????? iii>在查詢的列上增加Check約束,可以提升查詢性能。
★外鍵約束:Alter Table TbName1 Add [Contraint FK_外鍵后部] Foreign Key(ColName)?References (TbName2)
?????????????????????????????? ?[On Update Cascade On Delete Cascade]
???????????????? 這里的ColName會自動去對應引用表TbName2中的主鍵,類型必須一致;并且,當一個表被引用的話,其他表中的外鍵引用約束不刪除,
則被引用表也不允許刪除,被引用表的主鍵約束也不能被改變。
?????????????????注意:這里的On Update Cascade 和 On Delete Cascade就是外鍵的精華了,它可以防止在從表中出現垃圾數據(丟失外鍵的數據).
????????????????????????? On Update ...是當主表(TbName2)中的主鍵主動改變的時候,所有的從表(TbName1)中的外鍵也隨著一起改變;
On Delete ...是當主表(TbName2)中的主鍵所在記錄被刪除時,會自動刪除其從表(TbName1)中所有對應的明細。
?????? 3, 【記錄】的增刪改查操作.
???????? 記錄的操作不會影響到表的結構,但是其操作的復雜度卻可以比數據庫操作和表結構操作復雜得多,在表嵌套和表關聯后可以直接增加其算法復雜度的級數。
1>新增記錄:
Insert [Into] TbName (字段名列表) Values (值列表) --這里 字段名列表 如果省略的話,代表所有字段;
???????????Insert [Into] TbName Select 查詢??????????????????????????????? --?Values(值列表)其實是一個關系集合,也可以由查詢實現,注意這里查詢并不需要括號
?????????? 2>修改記錄:
?????????? Update TbName Set
?????????????? ColName1=Value1, ColName2=Value2,..
?????????? From TbName?????????????????? --這里允許跟幾個表的關聯模式,但是更新時,只針對Update后接的表,這里的關聯表,只相當于多了一些循環。
?????????? Where 條件
?????????? 3>記錄刪除
?????????? Delete TbName1,TbName2,...?????????????? --這里的表名可以省略,默認是From中出現的所有表,如果單獨刪除某一個表的記錄,這里就打某一個表名。
?????????? From TbName1,TbName2,...關聯關系
?????????? Where 條件???????????????????????????????????????? --這里省略的話,就是刪除對應表中的所有記錄。
?????????? 4>記錄查詢
?????????? 記錄查詢表面上看似不重要,因為其出錯不會改變實際記錄而造成影響,但是事實上查詢是記錄操作中最復雜的部分,因為它可以嵌在前三種操作當中,成為子操作。
???????????? a>普通查詢:
???????????????? Select [別名=]ColList1????????????? --這里可以為每一列重新命名,也可以用[As 別名]的方式,效果跟[別名=]是一樣的。
???????????????? From TbName [As 別名]??????????? --其實這里的As也可以省略
???????????????? Where Condition????????????????????? --省略Where Condition的話,是默認查所有數據
???????????????? Order By ColList2 [Desc]????????? --這里Desc省略的時候,默認值是Asc 即自小到大升序排列; ColList2也可以用序號代替,如1,2,3會自動對應查詢結果列.
?
???????????? b>統計(聚合)函數查詢:
???????????????? ★Avg:平均數。
??????????????????????如果非要將null值的數值參與計算的話,可以用isnull(表達式,0)來轉換;整型字段的平均值計算,不會自動轉換為實型,而會自動以去尾法(Floor)取整。
?????????????????★Count:計數。
??????????????????????可以統計一個或多個字段的數量,同樣需要統計null的話,需要用isnull進行轉換;Count支持內置的Distinct使用技巧,可以只統計非重復列。?
?????????????????★Min/Max: 最小/大值。
????????????????????? 往往用排序加Top 1的方式也可以求到最值。
????????????? ★Sum:求和
????????????????????? 自動忽略null值,所以不用額外寫isnull;只能對整型和實型類數值操作,不能對字串或流操作。
???????????????? ★CheckSum,Binary_CheckSum,CheckSum_Agg : 行檢查函數
????????????????????? CheckSum:生成一列或多列的校驗值,常用于建立哈希索引。
????????????????????????? eg. Alter Table TbName Add NewCol As CheckSum(ColList)
???????????????????????????????Create Index IX_NewCol On TbName(NewCol)
??????????????????????Binary_CheckSum:常用于整行統計出校驗值,用戶檢測行改變。但是它會忽略二進制和游標字段(text,ntext,image,cursor).
????????????????????? CheckSum_Agg:可以將一個小組校驗值轉換成一個整型數輸出,從而校驗整個小組數據的改變。可以用Distinct連用,組內數據的順序不會改變校驗值。
??????????????????????????eg. Select GroupName, CheckSum_Agg(Binary_CheckSum(*))
?????????????????????????????? From TbName Group by GroupNmae.
?????????????????★Var/Varp: 樣本/總體 方差.? 計算每個項,離其平均值差的平方均值。
?????????????????????????????????
???????????????????????????????? 上面的公式,【S方】就是方差; 而【S】是標準偏差。
???????????????? ★Stdev/Stdevp:樣本/總體 標準偏差.
????????????????????方差及標準偏差的SQL分布計算,以計算表TbName中的iQty字段為例:???????????????
????????????????????SELECT @AVG=AVG(iQty*1.0)
???????????????????????????????? FROM TbName
??????????????????? SELECT? SUM(SQUARE (iQty-@AVG))/COUNT(*) AS [VARP],????????????? --總體方差
??????????????????????? SQRT(SUM(SQUARE(iQty-@AVG))/COUNT(*)) AS [STDEVP],????????? --總體標準方差
??????????????????????? SUM(SQUARE(iQty-@AVG))/(COUNT(*)-1) AS [VAR],??????????????????? --樣本方差???????????? 樣本在總統計數上,少1
??????????????????????? SQRT(SUM(SQUARE(iQty-@AVG))/(COUNT(*)-1)) AS [STDEV]?????? --樣本標準方差
????????????????????FROM TbName?????????????????????????????
???????????????? 注意:所有聚合函數都會忽略表達式為null值的項。
????????????????
???????????? c> 集合運算查詢:
??????????????? ?如果將一個查詢結果看做一個集合,那么SQL就提供了三種集合運算符:Union(并), Except, InterSect(交).
???????????????? Except是計算在前一個集合中存在,但不在后一個集合中存在的記錄。 Union結果=Except結果+InterSect結果。
??????????????? 注意: Union的計算結果都會自動合并相同行,如果在連接符號后跟All 則自動去掉重復行;
必須要保證兩個查詢的數據類型結構一致,如果出現結果字段名不一致的情況,則集合運算結果按第一個表的結果字段名取新字段名。
????
???????????? d> 表連接:
??????????????? ★內連接: 也稱為普通連接或者自然連接,標準寫法: [Inner] Join?TbName On Condition。?這里Inner 通常允許省略,并且如果直接將表排列在一起,
并且用逗號隔開,ON的連接條件寫到后面Where 部分里,也是允許的,在SQL-92標準以后,這樣寫的執行效率不會受任何影響。
????????????????★左連接: 通常左連接可以代替右連接,不是在特別必要的情況下,能用左連接,就不寫右連接,以免造成人的使用差異。左連接的標準寫法為:
???????????????????????????? Left Join TbName On Condition 這里什么都不可以省略。當TbName中找不到符合Condition的數據時,會對應左表記錄生成對應右表字段類型
但值為Null。這種連接適合取基礎表數據,不會因為基礎資料的缺失影響到整體表的查詢結果條數。
??????????????? ★外連接: Full [Outer]?Join On Condition?這種連接跟inner內連的不同之處,是會在類Inner的條件下,附加一組左表全為Null值匹配全右表的結果記錄,
還附加一組右表全為Null匹配左表全記錄的結果記錄。這相當于把左連接,右連接相對內連接的增量,一次全加在內連接上。
??????????????? ★全連接: Cross Join 注意,這種連接是不需要On條件的,相當于寫兩個表名列表,然后Where 1=1的效果。它的結果集記錄數恰好是左表記錄數*右表記錄數。
???????????? e>查詢嵌套:
???????????????? 這里只講兩層查詢嵌套的模式,多層嵌套可以由兩層嵌套擴展
用一條語句表示三種嵌套形式:
Select ColName1,
?????????????????????????? AliasName=(Select Top 1 ColName From?TbName2?Where?KeyName=A.KeyName)????????? --第一種嵌套
?????????????????From TbName1 A inner Join (Select * from TbName3) As B On A.KeyName=B.KeyName??????????? --第二種嵌套
?????????????????Where exists(Select 1 From?TbName4 Where?KeyName=A.KeyName)?????????????????????????????????????? --第三種嵌套
???????????????? ★第一種嵌套:利用了查詢語句返回單值的效果,用一個子查詢直接賦值,這么做的好處跟建空字段,然后用表關聯Update效果很象,
不會因為空值或者多值影響到查詢結果的記錄數。但是效率不是很高,雖然因為SQL緩存的關系不會形成多次查詢,但是
對于大型數據表,最好還是用建空字段+Update語句的形式來更實現。
???????????????? ★第二種嵌套:最常用的嵌套,一般不會象舉例那樣查單表,而是用多表關聯并帶很多條件或者還有分組的查詢結果作為一個新表B,來實現嵌套。
????????????????????????????????? 這樣做也有一些缺點,就是嵌套的查詢結果在外層是沒有索引的,這個也不利于超大型數據的處理。
???????????????? ★第三種嵌套:這種子查詢是利用了查詢返回是否為空的特性,使用很少,也有人很喜歡用 ColName1 In (子查詢)的模式進行判斷。但是,
有一種需求是非利用這樣的查詢完成不可,不然就需要寫多段復雜語句,那就是分組取每組的Top n 結果記錄。
??????????????????eg. Select * from TbName A
??????????????????????? Where (Select Count(1) from TbName B Where A.KeyCol=B.KeyCol And B.OrderCol>A.OrderCol)<nTopQty
??????????????????????? Order by KeyCol,OrderCol? --這里KeyCol是用來分組的字段,OrderCol是每組用來排序的字段,nTopQty是每組顯示的前多少條。
?????????????????????? 上面這條語句實現的效率非常高,并且使用了自身查詢的效果。當然,還有另一種也是一條語句解決問題的,效率也不錯:
?????????????????????? Select * from
???????????????????????(Select *, Row_Number() over (Partition by SectionID order by OrderCol) as RowID from TbName) A
?????????????????????? Where A.RowID<=nTopQty
?????????????????????? Order by KeyCol,OrderCol
????????????????????? 這里調用了系統函數Row_Number()功能,并且使用的是第二種嵌套模式。
??????????
??????????????????????
?
轉載于:https://www.cnblogs.com/Murphieston/p/5700815.html
總結
以上是生活随笔為你收集整理的SQL-Server使用点滴(一-数据对象篇)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机应用基础期末考试要点,计算机应用基
- 下一篇: 深入浅出的mysql第三版和第二版的区别