數據庫概論正則表達式
數據庫一直是個人一個痛。。由於不是科班出生,不少知識都有待補充。而數據庫這一塊,一方面沒作過什麼必需要用到數據庫的大項目,另外一方面身邊不少同事都和我說數據庫這東西很好學(畢竟咱們不是專業作數據庫開發的,只要會用就好了),因此一直沒怎麼系統學習過。此次趁着培訓講到SQL,終於在本身電腦上裝了個MySQL服務,開始嘗試本身使用數據庫了。。翻開了好久以前買的《數據庫概論》這本書,這篇文章就是它的筆記了。算法
■ 緒論數據庫
書的第一章講了不少理論性較強的東西。首先是數據存儲技術的發展歷史。首先數據是靠人工維護管理在實體上的(紙帶機和彙編時代),後來人們搞出了文件系統來維護數據不過文件系統的數據存儲冗餘度大獨立性差等問題。再後來就是數據庫技術的出現。數據庫技術具備數據結構化程度高,冗餘度低,獨立性高,有統一的DBMS(Database Manage System)程序來調度管理數據和對數據的操做。編程
回過頭來再來看「數據」究竟爲什麼物。在從天然世界到機器世界,數據含有不一樣的含義。從咱們眼中現實世界裏活生生的一個實物,到機器中1100的二進制碼,數據的抽象化大約經歷了三個階段。這三個階段的工做分別被稱爲概念模型,邏輯模型和物理模型。概念模型用於將現實世界抽象成一個較爲簡潔有序的模型,作這個工做的主要是數據庫的設計人員,他們按照用戶的觀點來對數據和信息建模。物理模型是最底層的抽象,它描述了數據在系統內部是以怎麼樣的形態和方式存取,具體的物理模型實現是由數據庫軟件的開發人員編寫的DBMS來完成,數據庫設計人員須要知道什麼樣的物理模型最合適他要設計的數據庫。邏輯模型處於概念和物理模型之中,包括了層級模型,網狀模型,關係模型等等模型,它將具備必定抽象度的問題轉化爲信息技術更加能理解的樣子。數據結構
具象點來講,概念模型就是根據現實世界中錯綜複雜地關係畫出的一張實體與實體間關係的拓撲圖,邏輯模型則是把這張拓撲圖具體到庫、表、列等數據庫的要素,而後物理模型指導瞭如何把數據庫中的結構以合理的方式存儲到磁盤等物理介質上去。架構
經常使用的數據(邏輯)模型有不少,可是比較經常使用的果真仍是關係模型。基於這種模型設計出來的數據庫天然就是關係型數據庫了。框架
■ 關係型數據庫數據庫設計
關係型數據庫中有一些看起來十分拗口,可是其實是挺直白的基本概念。編程語言
關係:在關係型數據庫中,「關係」就能夠理解成一張二維表,記錄了一些元組(元組在這裏能夠理解成是一條「記錄」,元組中每個值叫作一個「份量」)。很明顯,一個關係應該是由跟此關係相關的全部域的笛卡爾乘積的一個子集。好比有三個域:D1={"張三",「李四」}、D2={"男","女"}、D3={"醫生","護士"}。他們的笛卡爾乘積就是:函數
張三 | 男 | 醫生 |
張三 | 男 | 護士 |
張三 | 女 | 醫生 |
張三 | 女 | 護士 |
李四 | 男 | 醫生 |
李四 | 男 | 護士 |
李四 | 女 | 醫生 |
李四 | 女 | 護士 |
而現實狀況是張三李四隻可能有一個性別,且只可能有一個職業,因此真實的關係應該是這個笛卡爾積的一個子集。這樣一個關係能夠記做R(D1,D2...Dn),其中n是關係的目或者度(Degree),表示一共有幾個域參加了這個關係的造成,當n爲1時關係稱爲單元關係,n爲2時稱爲二元關係。。。爲了表現一列數據具備統一的性質且獨立於其餘列的性質,須要爲每個列取個名字,因此一列的名字稱爲「屬性」。能夠看到,n元關係至少有n個屬性(至少而不是恰好主要是考慮到可能有多個屬性來自同一個域)。
域(Domain):一組具備相同數據類型的值的集合
候選碼:若是一個屬性組的值能夠惟一地標識一個元組,那麼就稱該屬性組是候選碼。若是一個關係有多個候選碼,那麼就能夠選定其中一個座位主鍵(或者叫主碼)。不包含候選碼的屬性是非主屬性或叫非碼屬性。若是極端狀況下,一個關係中全部屬性都是這個關係的候選碼的話那麼稱爲全碼關係。
對於一個關係型數據庫而言,關係能夠有三種,分別是基本關係,查詢表和視圖表。基本關係或叫基本表是指實際存在於存儲介質中的表,它是實際數據的邏輯表示。查詢表是用戶進行查詢以後獲得的表,而視圖表是指由基本表或其餘視圖表導出的表,是通過DBMS處理的虛表,不對應實際存儲的數據。
● 基本表的性質
對於一個基本表,須要明確如下幾點性質:
1. 列內份量是同質的,即同一類型的數據
2. 不一樣的列可能出自同一個域,但必需要有不一樣的屬性名
3. 列的順序無所謂
4. 任意兩個元組的候選碼不能相同
5. 行的順序無所謂
6. 份量必須取原子值,即份量必須是不可再分割的數據單位,不能表中嵌表
● 關係模式
關係的描述稱爲關係模式,它能夠形象地表示爲R(U,D,DOM,F)。其中,R是關係名,U是組成該關係的屬性名集合,D是屬性組U中屬性來自的域的集合,DOM是屬性向域的映射集合,F是屬性間數據的依賴性集合。這樣表示一個關係模式邏輯上雖然十分準確,可是有點事無鉅細的感受。通常而言關係模式能夠只關注關係名和關係中的各個屬性,能夠記爲R(U)或者R(A1,A2...An)其中A1到An爲屬性名。而D,DOM這些參數實質上能夠經過對屬性的類型和長度進行描述來補全。
關係是關係模式在某一時刻的具體狀態或內容,關係模式是靜態的穩定的,而關係是動態的不斷變化的。
■ 關係型數據庫的操做與關係的完整性
關係模型由關係數據結構,關係操做集合以及關係完整性結構三部分組成,以前講到的都屬於關係數據結構範疇內,接下來講明關係操做集合。
關係模型中經常使用的操做包括查詢(Query),插入(Insert),刪除(Delete),修改(Update)四個部分。其中關於查詢操做,由於關係型數據庫或者說關係模式的特色,具備很是強大的功能。查詢操做還能夠進一步細分爲SELECT,PROJECT,JOIN,DIVIDE,UNION,EXCEPT,INTERSECTION,笛卡爾積等等。在此之中比較經常使用的是SELECT,PROJECT,UNION,EXCEPT和笛卡爾積。
關係模型中對數據的操做對象都是集合,也就是全部操做的方式都是一次一集合的方式。即對一個集合對象進行操做返回的也是一個集合對象。相對的,非關係型數據庫的操做有可能就是一次一記錄的操做。好比比較簡單的一個k-v型數據庫的一次簡單查詢獲得的只是一條記錄。
對關係的操做一般用關係數據語言來實現,關係數據語言能夠分爲代數方式的關係代數,或者邏輯方式的關係演算兩種。兩種方式分別關注經過運算和語義的指定來操做數據。如今通用的SQL語言則是一種間於關係代數類語言和關係演算類語言之中的,具備數據定義和數據控制功能的強大數據庫操做語言。具體的SQL說明會在下面單獨列出。
關係的完整性這個術語看着懵逼,其實就是說明了關係中一些參數的約束條件。這些約束性的出現時基於現實世界中的要求。關係模型中的完整性約束能夠分爲實體完整性,參照完整性和用戶定義的完整性。其中實體完整性和參照完整性是全部關係模型必須知足的,用戶定義的完整性體現了具體領域中的由語義指出的約束。
實體完整性指若是屬性A是關係R的主屬性,那麼A的任何一個份量都不能爲空值。這是顯而易見的,由於當主屬性爲空就表示該元組沒法識別,更不用說區別於其餘元組了。
參照完整性是指,關係模型中不一樣的實體之間可能會存在互相引用,這就致使了不一樣關係與關係間的相互引用。好比 學生(學號,姓名,專業號,年齡) 和 專業(專業號,專業名)兩個關係間,在學生關係中專業號是引用自專業關係的。那麼學生關係中引用過的專業號必須是存在於專業關係中,而不能是憑空捏造的。上述例子是最簡單的一個參照完整性約束的說明,實際上引用能夠發生在不少關係之間,甚至能夠發生在一個關係內部,這也說明了參照完整性的適用範圍十分普遍。
在給出參照完整性的嚴格定義以前,首先來看一個概念「外碼」。當屬性F是關係R的一個非主屬性,但同時F與另外一個關係R’的主鍵對應的話,就稱F是R的外碼,併成R爲相對於R'的參照關係,R'相對於R是被參照關係。好比上例中,專業號屬性是學生關係的外碼,專業關係是被參照關係而學生關係是參照關係。須要指出的是參照關係的外碼的屬性名並不必定要和被參照關係主鍵的屬性名一致,能夠根據實際須要取不一樣的名字。接下來就能夠給出參照完整性的嚴格定義,就是說屬性或屬性組F是基本關係R的外碼,說明它與基本關係S的主碼K相對應,則對於R中F上每一個元組的值都必須爲空值(全部值都取空值)或者S中某個元素的主碼值。
用戶定義的完整性是指某一個具體的應用場景中關係中數據應該知足的條件。好比某個屬性只能取惟一值,某個非主屬性也不能爲空,年齡分數等屬性應該在必定合理的邏輯範圍內等等。這一部分約束在數據庫系統發展早期老是經過應用程序來制定,如今DBMS基本上能夠在數據庫內部規定好這些約束從而讓應用程序的編寫者和使用者更加方便。
教材中第二章末尾還詳細講解了關係代數和關係演算兩方面的知識,由於這兩種操做方式都已經再也不通用,這裏就再也不詳細展開講了。接下來是重頭戲,SQL的說明
■ SQL語言使用
SQL的全稱是Structured Query Language,結構化查詢語言。因爲其功能強大,如今已經成爲關係型數據庫的通用型語言了。同時不一樣廠商根據本身的想法也對SQL有不一樣的擴展。
SQL語言將數據查詢(DQL),數據操縱與控制(DML/DCL),數據定義(DDL)所有囊括在中,造成了風格統一,能夠貫穿數據庫整個生命週期的數據庫操做語言。同時SQL是一個高度非過程化的語言,意思就是說SQL語言只關心語言獲得的結果是什麼而不關心具體是怎麼作的。怎麼作的留給了DBMS的程序來決定,這大大減輕了用戶的負擔而且提升了數據的獨立性。
相比於高級編程語言,SQL也是很是簡單的。其操做的動詞只有9個,分別是:
數據查詢 SELECT
數據定義 CREATE , DROP , ALTER
數據操控 INSERT , UPDATE , DELETE
數據控制 GRANT , REVOKE
● SQL的基本概念
和以前說過(啊咧,仍是沒說過來着。。)的同樣,SQL也是基於一種外模式/模式/內模式的架構,用戶能夠用SQL對基本表(模式)和視圖表(外模式)進行查詢和其餘操做。在這裏,基本表和視圖表都是關係。而基本表對應到具體的存儲文件則是內模式,通常用戶沒必要關心存儲文件的物理結構。
視圖表是從基本表中導出的表,自己不獨立存在於存儲結構之中。另外用戶能夠在視圖表的基礎上進一步導出視圖表,視圖表在概念和操做上和基本表同樣,由於都是關係。
通常而言SQL是在大多數RDBMS中通用的,可是也有一些RDBMS產品對SQL有本身定製化的改變,與標準SQL可能有10%-15%的出入,須要使用者在使用以前對此有所瞭解。下面將以創建一個學生數據庫爲例說明SQL的具體語句操做。
■ 數據定義操做
在這個庫中咱們大概要創建三張表:
Student(Sno,Sname,Ssex,Sage,Sdept) #字段分別是學號,姓名,性別,年齡和院系
Course(Cno,Cname,Cpno,Ccredit) #字段分別是課程編號,課程名,要求先修課程和學分數
SC(Sno,Cno,Grade) #選課狀況表,三個字段分別是學號,課程號,課程成績
● 數據定義
關係型數據庫支持三級模式結構,與外模式,模式,內模式相對應的咱們能夠操做的基本對象有視圖,表,索引。模式做爲一個把握數據總體的框架也能夠做爲對象。這四種對象基本上就是咱們能夠定義和刪除的對象了。定義的關鍵字是CREATE,刪除的關鍵字是DROP。另外針對表,咱們還能夠用ALTER關鍵字進行修改。
定義模式:
CREATE SCHEMA "test_schema" AUTHORIZATION Frank;
就是爲用戶Frank定義了一個模式test_schema。當沒有指定模式名的時候默認模式名是用戶名。模式從層級的角度來說就是定義了一個命名空間。在這個命名空間裏,被受權的用戶能夠進一步定義該模式的基本表,視圖,索引等等。
刪除模式:
DROP SCHEMA "test_schema" <CASCADE | RESTRICT>;
參數CASCADE和RESTRICT二者選其一,CASCADE表示刪除模式的同時刪除全部該模式下的數據庫對象包括基本表視圖等等,至關於force。若是是RESTRICT就表示在刪除模式前對模式作檢查,若是發現了其中有數據庫對象就放棄刪除。
定義表:
CREATE TABLE Student( Sno char(9) primary key, Sname char(20) unique, Ssex char(2) not null, Sage int not null, Sdept char(20) )
建立了一張表,表的屬性都被完整的指出了,須要注意這個順序仍是十分重要的。另外primary key,unique,not null這些關鍵字修飾了相關屬性爲主鍵,候選碼,不能爲空等。
再來看如何創建一張課程表:
CREATE TABLE Course( Cno char(4) primary key, Cname char(10) not null, Cpno char(4), Ccredit int, FOREIGN KEY Cpno REFERENCES Course(Cno) )
由於Course表比較特殊,涉及到了一個外碼(並且這個外碼對應的就是表自身的主鍵,因此這個外碼對應關係中,參照關係和被參照關係是同一個關係)。因此須要用FOREIGN KEY關鍵字聲明。
最後創建選課表SC:
CREATE TABLE SC( Sno char(9), Cno char(4), Grade int, primary key(Sno,Cno), //指定多重主鍵能夠這麼操做 foreign key (Sno) references Student(Sno), foreign key (Cno) refenreces Course(Cno) )
● 數據定義中的域
在上面例子中能夠看到一些域,也就是在建立表的時候聲明的各個屬性的類型,其實能夠看作一種域。經常使用的(但並不是全部DBMS都是這樣的)域有:
char(n) 長度爲n的長字符串
varchar(n) 長度爲n的變長字符串,char和varchar的區別在於varchar(10)是指定了字符串最大長度爲10,不足10的時候按照實際狀況存儲,而char(10)無論實際長度多少都是按10個字節存儲。相比之下,char因爲統一儲存格式,效率更高,是一種以空間換時間的作法。
int 長整數
smallint 短整數
float(n) 精度爲n的浮點數
date 日期,格式默認是YYYY-MM-DD
time 時間,格式默認是HH:MM:SS
numeric(p,d) 定點數,由p位數字組成,小數點後面d位數
● 模式與表之間的關係
上述定義模式和表的方法都是獨立的,沒有將二者聯繫起來。其實能夠有:
create schema "test_schema" authorization Frank create table testtable( test int, ); /*以上是在創建模式的同時創建表*/ create table "test_schema".testtable(...); /*這個是在創建表時把他和一個模式關聯*/
實際上一個表必須屬於一個模式,當沒有指定模式的時候系統會根據搜索路徑來自動找到一個某個表應該屬於的模式。
修改基本表:
以前說過,基本表能夠直接修改,用ALTER關鍵字。這裏的修改指的不是修改某些具體的數據,而是修改表結構,約束條件等更加高層次的修改。下面是一些例子:
alter table Student add S_entrance date; /*給Student表添加一列「入學時間」的屬性*/ alter table Student alter column Sage smallint; /*將屬性Sage的類型從INT改爲SMALLINT*/ alter table Course add unique(Cname); /*爲Course表的Cname屬性加上unique的約束條件*/ alter table Course drop unique(Cname); /*刪除Course表的Cname屬性上的unique約束條件*/
刪除基本表:
和刪除模式相似的:
drop table <表名> [CASCADE | RESTRICT];
CASCADE和RESTRICT兩者選一。缺省狀況下是RESTRICT模式。通常RESTRICT的刪除會檢查表是否被其餘基本表引用,是否有視圖,有觸發器,有函數等等。
建立索引:
須要瞭解一下什麼是索引(http://blog.csdn.net/kennyrose/article/details/7532032/)。總的來講,索引是一種爲幫助提高查找數據效率而維護在數據庫中的一種輔助數據。索引能夠提高一次查詢時的效率可是代價是佔用了一些空間以及增刪修改數據時要同步地維護索引。因此綜合考慮,對於一些有表明性的數據(好比主鍵)以及讀取頻率比較高可是變更比較少的數據能夠創建索引。具體的實現索引的技術除了上面那篇博文中提到的B樹算法,還有基於hash值的索引等,具體用什麼技術由DBMS決定。
建立索引要基於現有的數據,好比:
create unique index Stusno on Student(Sno);
這個語句中,unique表示此索引的每個索引值只對應惟一的數據記錄,Stusno是索引名,這句話至關因而以學號的升序(默認是升序)給Student表建立惟一索引
create cluster index Stusname on Student(Sname);
這個語句中cluster是關鍵字,表示創建的索引是簇聚索引。簇聚索引是指這個索引中索引項的順序和表中記錄的物理順序一致。具體性能特色還需進一步學習。。
create unique index SCno on SC(Sno ASC, Cno DESC);
這句建立了一個惟一索引,其以SC表按學號升序和課程號降序創建。
刪除索引:
刪除索引就是用DROP INDEX <索引名> 就行了。
■ 數據查詢操做(單表查詢)
查詢最主要的是SELECT語句。通常格式的SELECT語句是:
SELECT [ALL | DISTINCT] <目標列表達式> [ ,<目標列表達式> ]... FROM <視圖或表名> [ ,<視圖或表名> ]... [ WHERE <條件表達式> ] [ GROUP BY <列名1> [ HAVING <條件表達式> ] ] [ ORDER BY <列名2> [ ASC | DESC ] ]
最經常使用的就是SELECT XXX FROM XXX WHERE XXX='XXX'的格式,意思就很少說了。GROUP BY 子句的意思是將結果按照<列名1>指定的列的值進行分組。好比有一個性別列,性別只有男和女,對這個列全部數據作一個set以後依照set中剩下的數據分類對全部元組進行分組。若是還帶有HAVING短語,則是隻有知足指定條件的組纔會被列出。
若是還有ORDERED BY子句的話,則結果表還會按照<列名2>指定的列的值進行升序或降序的排列。ASC是升序DESC是降序。
下面是一些查詢數據的SQL語句實例:
SELECT Sno,Sname FROM Student; //選擇全部學生的學號和姓名並展現 SELECT Sname,2004 - Sage FROM Student; //查詢一個通過計算的值 SELECT Sname NAME,'Year of Birth:'BIRTH,2004 - Sage BIRTHDAY,LOWER(Sdept) DEPARTMENT FROM Student; //給選擇出來的列取名字,注意這裏大小寫敏感了,由於要區分值和列名 SELECT DISTINCT Sno FROM SC; //能夠去除結果中重複的值,至關於set了一下。當沒有DISTINCT關鍵字指定時默認這裏有個ALL關鍵字 SELECT Sname FROM Student WHERE Sdept='CS'; //WHERE關鍵字支持各類各樣的比較條件搜索,除了=外還有> , < , >= , <= , != , NOT等等 SELCT Sname FROM Student WHERE Sage BETWEEN 20 AND 23; //除了比較還有肯定範圍,也有NOT BETWEEN 20 AND 23這種 SELECT Sname FROM Student WHERE Sdept IN ('CS','MA'); //還有IN和NOT IN SELECT Sname FROM Student WHERE Sdept LIKE 'C%' //LIKE和NOT LIKE關鍵字用於字符串匹配,後面跟的字符串是一個簡單的相似正則串的東西,下面詳細講它的匹配規則。 SELECT Sname FROM Student WHERE Sdept IS NULL; //判斷是不是空值,注意空值是不能用=NULL的! SELECT Sname FROM Student WHERE Sage < 20 and Sdept = 'CS'; //AND,OR,NOT聯結多個條件實現多重條件的查詢
*關於LIKE的正則規則:LIKE後面跟的表達式一般用引號引發來,用到的正則邏輯符號主要是兩個,一個是%。%至關於經典正則中的.*,即匹配從0個到任意多個任意字符。另外一個是_,下劃線至關於經典正則中的.,表明一個字符。若是要匹配%或者_自己那麼在表達式中的兩個符號前面加上\就能夠轉義了。好比LIKE 'DB\_config'。
另外須要注意的一點是中文字符並非一個字符,而是根據不一樣的編碼格式而有2-3個字符,因此在用_匹配中文字符時應當注意多寫幾個。好比LIKE '歐陽__'匹配的是全部歐陽開頭後面還跟着一個漢字的值。
上面的全部實例都有一個共同的特色,就是FROM關鍵字後面都是一張表,即單表查詢。實際上,和SELECT後面的子句同樣,能夠在FROM後面寫上多張表而後用逗號分隔。這麼作的結果就是初次選擇出的結果是兩個表全部元組組成的笛卡爾乘積。這顯然不是頗有意義。
● 彙集函數
爲了方便用戶,SQL還自帶了不少彙集函數,即經過它們能夠方便地調出一些數據的綜合屬性。經常使用的彙集函數和用法以下:
COUNT( [ DISTINCT | ALL ] * ) 統計元組個數,參數DISTINCT和ALL能夠控制是否統計重複出現項
COUNT( [ DISTINCT | ALL ] <列名> ) 統計某一個屬性下有多少值
SUM( [ DISTINCT | ALL] <列名> ) 求算一列值的總和(數據必須都是數值型的)
AVG( [ DISTINCT | ALL ] <列名> ) 求算一列值的平均(數據必須都是數值型的)
MAX( [ DISTICT | ALL ] <列名> ) 求一列值中的最大值
MIN( [ DISTINCT | ALL ] <列名> ) 求一列值中的最小值
例子:
SELECT COUNT(DISTINCT Sno) FROM SC; /*從選課表統計學生人數,由於一個學生選了多門課,因此要用DISTINCT關鍵字來去除重複的*/ SELECT AVG(Grade) FROM SC WHERE Cno='1'; /*統計選擇1號課程的全部人的平均分*/ SELECT SUM(Ccredit) FROM SC,Course WHERE Sno='20121001' AND SC.Cno=Course.Cno; /*統計學號爲20021001學生在選課表中選課的總學分數*/
須要注意的一點是,彙集函數中除了COUNT(*)以外,其他的都會略過一個列中的空值而只處理非空值。
GROUP BY子句將查詢結果按照指定的某一列或者多列的值對全部查詢所得結果進行分組,經常用於對彙集函數所獲得結果的進一步細化處理。好比:
SELECT Cno,COUNT(Sno) FROM SC GROUP BY Cno; /*當沒有groupby子句的時候,選擇出錯,由於不可能既選出實在數據又統計選擇數目。可是加上groupby以後先用Cno爲結果分組,而後獲得結果再用COUNT計數,獲得的就是選擇每門課的人數是多少的表格了*/ SELECT Sno FROM SC GROUP BY Sno HAVING COUNT(*) > 3; /*這裏除了groupby子句,還用到了having條件。和where條件不一樣,having條件主要做用於組而不是基本表或者視圖*/
■ 數據查詢操做(鏈接查詢)
以上提到的全部查詢操做都是基於一張基本表或者視圖的,實際應用中有不少查詢涉及到兩個及以上的表,這種查詢時鏈接查詢。細分鏈接查詢還能夠有等值鏈接查詢,天然鏈接查詢,自身鏈接查詢,外鏈接查詢等等。
● 等值鏈接查詢和非等值鏈接查詢
利用where關鍵字來鏈接兩個表的條件稱爲鏈接條件。當鏈接符是=時查詢爲等值鏈接查詢,其餘符號時則爲非等值鏈接查詢。一般要求where子句中的條件字段是兩個表中的公共字段,好比:
SELECT student.*,SC.* FROM student,SC WHERE student.Sno = SC.Sno; /*在屬性名以前加上「表名.」是爲了防止混淆。沒有where子句的時候很明顯獲得的是student和SC兩表的笛卡爾積,在有了子句以後,子句就能夠從笛卡爾積中篩選出一些符合子句條件的元組了*/
上面這個例子中選出來的結果中會有兩列Sno,由於選擇的兩個表都是*。若是去掉一列Sno,那麼這個結果也被稱爲天然鏈接(即沒有重複屬性列)。好比手動地去除了多餘的一列Sno的話:
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade FROM Student,SC WHERE Student.Sno = SC.Sno; /*由於Sname,Ssex這些屬性名都是獨一無二的,不必特別之處是student.的,這樣的select就避免了重複屬性的出現,從概念上來講這就是一個天然鏈接*/
● 自身鏈接
鏈接操做不只在兩個表之間能夠進行,也能夠在同一個表內本身鏈接本身。好比在Course表中咱們設計了每一個課程均可能有一個先修課程的編號。若是咱們想找到每門課程和其先修課程編號的對應關係的話就能夠以下這麼操做:
SELECT FIRST.Cno,SECOND.Cpno FROM Course FIRST,Course SECOND WHERE FIRST.Cpno = SECOND.Cno; /*爲了實現自身鏈接,首先搞出兩張表並取不同的名字(FIRST和SECOND),而後經過以上形式來鏈接兩張表中的不一樣字段*/
● 外鏈接
在上面說到的等值鏈接的例子中,若是存在某些學生沒有選課,那麼他們的記錄就會存在於stdudent表可是不存在於SC表中。這樣子的話在等值鏈接選出來的結果中必然是沒有這些學生的。若是想要讓這些學生也出如今結果中那麼就要用到外鏈接:
SELECT student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade FROM student LEFT OUT JOIN SC ON (student.Sno = SC.Sno); /*或者寫成FROM student LEFT OUT JOIN SC USING (Sno)*/
外鏈接的定義就是讓鏈接過程當中,由於空值存在而使得部分會被忽略的元組也出如今結果中且空值用null填充。外鏈接還分紅左外鏈接和右外鏈接和全鏈接,左外鏈接保證左邊的表中全部元組都在結果中出現,右外鏈接則保證右邊的全出現,全鏈接就是二者並集。相對的,通常意義上的鏈接就是內鏈接。
● 複合查詢
上面全部的查詢過程當中,where後面的查詢條件都只有一個條件。用AND,OR,NOT這些關鍵字則可使用複合條件查詢。好比:
SELECT student.Sno,Sname,Cname,Grade FROM student,SC,Course WHERE student.Sno = SC.Sno AND SC.Cno = Course.Cno; /*這個多表查詢中,首先關聯了student和SC中的學號字段,篩選出了全部選了課的學生,而後再關聯了SC和Course表中的課程號字段,將結果中的課程號變爲課程名*/
正如上所示,運用關鍵字能夠進行多重表的查詢,也被稱爲多表鏈接。
祭出一張關於JOIN的彙總圖
■ 數據庫查詢操做(嵌套查詢)
一個SELECT-FROM-WHERE句子被稱爲一個查詢塊,把一個查詢塊嵌套在另外一個查詢塊的WHERE子句或者HAVING短語的條件中的查詢叫作嵌套查詢。好比:
SELECT Sname FROM student WHERE Sno IN ( SELECT Sno FROM SC WHERE Cno='2' ); /*內層查詢從SC表中查出全部Cno是2的記錄,而後以此爲IN的依據再篩選從student中選出的數據*/
須要注意的是,SQL雖然容許多重嵌套,好比在內層查詢中再嵌套一個內層查詢。可是對於ORDER BY子句,它只能修飾最外層的查詢結果,即不能再任何一個內層查詢中使用。此外,上面的查詢中能夠看到,內層查詢(或者叫子查詢)跟父查詢時不相關的。此時這個查詢也被稱爲不相關子查詢。
上面這個例子也能夠經過以前說過的鏈接的方法來實現,好比SELECT Sname FROM student,SC WHERE student.Sname = SC.Sname and SC.Cno = '2'; 對於一樣的查詢結果,確定有各類各樣不一樣的查詢方法和SQL語句,當數據量大的時候不一樣的查詢語句可能帶來性能上的差距是很大的。因此這就須要數據庫的優化了。
既然有不相關子查詢,那麼就確定有相關子查詢了。下面這個例子就是一個相關子查詢:
SELECT Sno,Cno FROM SC x WHERE Grade > ( SELECT AVG(Grade) FROM SC y WHERE y.Sno=x.Sno ) /*選擇每個學生分數高於其全部課程平均分的課程 *注意這裏where後面跟的還不是等號而是大於號 *另外子查詢計算的是哪門課的平均分這個是根據每一個父查詢中Sno不一樣而決定的,因此是個相關子查詢*/
原理能夠理解爲這樣:父查詢中先選得一個Sno,而後把這個具體的值傳入子查詢中,計算出這個學生全部分數的平均分,再返回父查詢和當時的Grade進行比較得出結果。
● 帶有ANY或者ALL的嵌套查詢
還有一種嵌套查詢中帶有謂詞ANY(部分系統中也有SOME的說法)或ALL。使用二者時必需要配合使用一些比較運算符。好比=,>=等等。一個典型的應用SQL句子:
select Sname,Sage from student where Sage<ANY(select Sage from student where Sdept='CS') AND Sdept != 'CS'; /*選擇全部年齡比某一個計算機系學生小(至關於只要找到計算機系學生最大年齡,比那個數字小便可)的非計算機系學生,顯示他們的名字和年齡*/
而相對應的ALL就是表明了要比全部計算機系學生年齡小(即要小於全部計算機系學生中最小年齡)。從邏輯上來講,ANY,ALL能夠和其餘一些聚合函數和關鍵字作一些等價替換。好比where xx=ANY(...)就至關因而where xx IN (...);而<ALL(..)和>ALL(...)就至關因而<MIN(...)和>MAX(...)的意思了。
● 帶EXISTS謂詞的嵌套查詢
從天然語言的角度來思考,很容易把EXISTS和IN兩個關鍵字搞混。其實在SQL中,EXISTS後面跟着的子查詢是不返回任何查詢結果而只返回一個true或者false的邏輯判斷,若是查詢結果爲空返回false反之返回true。好比下面這個SQL句子:
select Sname from student where exists(select * from sc where Sno=student.Sno and Cno='1'); /*子查詢是查看一個特定的學號指代的學生有沒有選修1號課程,若是沒有選子查詢天然是空集,返回的是false,而後這個Sno的那個元組就不被父查詢select出來。總的來講,這個句子的意義就是選擇全部選擇了1號課程的學生名字*/
由於EXISTS不須要返回值,因此有時候是比其餘查詢方法更加高效的一個途徑。
*EXISTS有不少高級的用法,我看也看不懂。。之後在研究把
■ 數據庫查詢操做(集合查詢)
每一個SELECT句獲得的都是一個子集,多個SELECT獲得的集合之間天然能夠進行一些集合操做。集合操做的關鍵字主要有UNION(並集操做),INTERSECT(交集)和EXCEPT(差集)。注意,參加集合擦操做的各個查詢子集的列數必須相同且對應字段的數據類型也必須相同。
好比查詢全部計算機系和年齡不大於19歲的學生:
select * from student where Sdept='CS' UNION select * from stduetn where Sage <= 19; /*SQL是無所謂分行的,這麼寫純粹是爲了好看。固然若是願意的話不用特意寫集合的運算,能夠直接Sdept='CS' or Sage<=19*/
在這裏的計算中,系統會自動濾去重複的部分即年齡不大於19歲的計算機系學生的元組,這些元組只出現一遍。若是要保留重複元組那麼集合關鍵字就應該寫成UNION ALL。
相似的咱們能夠很輕易地看出把UNION換成INTERSECT的話就能夠算得交集,即不大於19歲的計算機系學生了。一樣的能夠將其改形成AND鏈接兩個條件的一句SELECT語句。
關於差集,也是相似的,只不過是寫在前面的集合減去寫在後面的集合。若是想改形成相對應的一條SELECT語句,就須要邏輯上對條件作一個修改而後用AND鏈接條件便可。好比:
select * from student where Sdept='CS' EXCEPT select * from student where Sage<=19; /*選擇出年齡大於19的全部計算機系學生,能夠改形成下面的形式*/ select * from student where Sdept='CS' AND Sage>19;
■ 數據查詢操做總結
在經歷上述全部操做以後,就能夠感覺到SELECT這個語句是多麼的豐富多彩了。實際上,SELECT正是SQL中的核心語句,其通常格式以下:
SELECT [ALL|DISTINCT] <目標列表達式> [別名] [,<目標列表達式> [別名]]... FROM <表名或視圖名> [別名] [,<表名或視圖名> [別名]]... [WHERE <條件表達式>] [GROUP BY <列名1> [HAVING <條件表達式>]] [ORDERED BY [ASC|DESC]]
1.目標列表達式可選形式
* 所有
<表名>.* 某特定表的所有(寫屬性名就是指定字段,下面很少廢話了)
COUNT([DISTINCT|ALL] *) 對元組數計數,COUNT也能夠換成其餘彙集函數如SUM,AVG,MAX,MIN等。
2. WHERE表達式可選形式
<屬性列名> <比較運算符> <屬性列名>/<常量>/[ANY|ALL] (SELECT子查詢)
<屬性列名> [NOT] BETWEEN <屬性列名>/<常量>/(SELECT子查詢) AND <屬性列名>/<常量>/(SELECT子查詢)
<屬性列名> [NOT] IN (值1,值2)/(SELECT子句)
<屬性列名> [NOT] LIKE <匹配串> //注意匹配串的格式不是經典的正則,而是一種簡化版的正則表達式
<屬性列名> [NOT] EXISTS (SELECT子句)
以上的條件還能夠經過AND,OR等關鍵字來進行條件串聯。
■ 數據更新(插入數據)
數據更新能夠分紅向表中添加,從表中刪除,以及修改表中的若干行數據。這裏先來講說插入數據
插入數據用到了INSERT關鍵字,能夠分紅插入元組(插入一行數據)以及插入子查詢結果(插入多行數據)。
● 插入元組
INSERT語句的通常格式是:
insert into <表名> [(<屬性列1>,...)] values(<值1>[,<值2>...])
SQL規定,若是into後面沒有跟任何屬性列的說明的話,那麼默認values後面的各個值根據定義表時屬性的順序,依次賦給新元組的各個屬性,不能多一個或者少一個且順序嚴格對應。若是into後面寫了屬性列的話,那麼就須要把values中的值和這裏寫出來的屬性列的順序一一對應,沒有寫出的屬性列默認賦空值,此外還要注意得讓定義表時說明的NOT NULL的字段不能是空值不然會報錯。
● 插入子查詢
一行一行插入數據效率過低了,SQL支持將一個複雜的子查詢的結果批量地插入表中。好比我想計算每一個系學生的平均年齡而後插入另外一個統計平均年齡的表格中的話就能夠這麼作:
insert into Dept_age(Sdept,avg_age) select Sdept,AVG(Sage) from student group by Sdept;
固然,最好就是可以作到子查詢的屬性是和指出的表屬性順序一一對應,這樣能夠減小麻煩。
■ 數據更新(修改數據)
修改數據是指對錶的某些部分進行修改,用到的關鍵字是UPDATE。通常格式爲:
UPDATE <表名> SET <列名>=<表達式> [,<列名>=<表達式>]... [WHERE <條件>]; /*運用UPDATE和SET來修改數據,WHERE限定了修改的地方,若是沒有WHERE那麼就是修改全部元組的相關數據了*/
除了基本的條件表達式,也能夠在表達中加入子查詢好比:
update sc set Grade=Grade+1 where 'CS'=(select Sdept from student where student.Sno=sc.Sno) /*不要忘了常量還能夠寫前面這種操做 這個句的做用就是把全部計算機系學生的課程成績+1*/
■ 數據更新(刪除數據)
刪除語句的格式通常是:
DELETE FROM <表名> [WHERE <條件>];
當須要清空一個表可是不刪除這個表自己的時候,咱們不能用DROP而是用DELETE好比:
DELETE FROM sc;
■ 視圖操做 定義視圖
視圖是從一個或者幾個表中導出的表,與實際存在的基本表不一樣,視圖表是一個虛表,數據庫中只存放視圖的定義而不存放視圖中的數據。這些數據只在原先的基本表中存放。當原來基本表中數據發生了變化,那麼在視圖中的響應數據也就發生了變化。
視圖是一個獨立的對象,能夠被建立,查詢,刪除,也能夠在視圖的基礎上定義出新的視圖,對於視圖的更新(增刪改)操做規則是有必定的限制的。
視圖的定義用CREATE VIEW(也可被稱爲視圖的創建),其通常操做格式是:
CREAATE VIEW <視圖名> [(<列名> [,<列名>]...)] AS <子查詢> [WITH CHECK OPTION]; /*子查詢能夠是任何複雜的SELECT語句,可是一般不包括ORDERED BY和DISTINCT等要素 當有WITH CHECK OPTION存在時,表示這個視圖的增刪改操做要遵循子查詢中的條件表達式給出的條件 組成視圖的屬性名要麼所有給出要麼所有省略,省略時默認其屬性名就是子查詢獲得的屬性名 */
■ 關於ACID(唐突)
額 今天偶爾看到了 記錄一下。
ACID各個字母表明Atomic,Consistency,Isolation,Durability。即原子性,一致性,隔離性和持久性。
和ACID緊密相關的是事務這個概念。簡單來講,若是把一個SQL視爲一個操做,那麼事務就是一次性串行進行多個操做,相對地將這部分操做視爲一個總體。一個事務一般有一個開始標誌,一個結束標誌(結束標誌一般是commit之類的提交)。
而後須要明確,ACID是事務執行最終要達到的一個要求,若是這個要求達不到,極可能會發生數據庫數據紊亂,不符合業務預期的狀況。因爲它是一個須要結合具體業務達到的標準,因此有可能會有一些內容並非靠數據庫系統自己實現的。
原子性,指事務在執行時事務纔是執行的最小單位。事務中內含的各類操做,要麼全不作,要麼全作。可是注意,這並不指出這些操做是否作成功了。也就是說,5條操做可能第3條執行失敗,第1/2/4/5條執行成功。這不和原子性這個性質矛盾。同時提醒下我本身,操做失敗時要求回滾,這一來通常不會自動作,二來也不是原子性的要求。總之,只要事務中的操做對事務外呈現爲一個總體,那麼原子性就達到了。再說到原子性的實現,因爲應用的開發者使用事務時自己就是沒法介入事務的具體執行機理的,因此原子性通常得靠數據庫系統實現。
持久性是指一旦事務結束,作出的變化應該就要被寫入磁盤的相關數據文件中,保證數據改變的持久。由於和存儲相關,和具體應用關係不大,由數據庫系統實現。
上面兩個還算勉強能夠理解。麻煩的是一致性和隔離性……
隔離性,在我看了不少人的解釋以後,自我理解是這樣的。事務和事務之間互相隔離。一個事務雖然得作到原子性,可是其內部對於數據的變動畢竟仍是一步一步來的。這就勢必會致使數據庫會有一些中間狀態。就好像有機反應會有一些能量比較高的中間體。隔離性強調的就是,這類中間體狀態會不會被其餘事務看到,又能看到多少。所謂「看到」,是指好比說事務A在對一個數據update以後,後面又去作一些其餘事情,可是在提交以前,有另一個事務B來讀這個數據了,此時該不應讓數據B讀取到這個數據?說到這裏可能已經察覺到了,與原子性,持久性等定性的概念不一樣,隔離性實際上是一個定量的概念。也就是說根據業務、數據庫系統的不一樣,存在強的隔離性和弱的隔離性。顯而易見,較強的隔離性能夠比較好的迴避各類數據紊亂的問題(包括髒讀,不可重複讀,幻讀等,具體什麼意思沒看懂…可參考https://www.zhihu.com/question/31346392/answer/59815366),可是相對的性能會有所降低;反之亦然。隔離性從強到弱也有各個級別(上面那個回答裏也有提到)。應用的開發者能作的是爲應用選擇不一樣程度的隔離性,隔離性自己的實現仍是由數據庫系統來幹。
最後是一致性。一致性能夠認爲是上述三個特性再配合應用系統的一些控制來實現的一個「軟」目標。對於一致性的描述,最多的仍是以狀態來講。即某一個事務開始前和提交後,數據庫處於的狀態都是要合法的。合法的定義比較廣,首先它必須符合數據庫的規則好比建表時定下的各個字段的限制,好比int類型的字段不能update爲小數,不然數據庫會報錯;其次它也要符合應用的邏輯。好比一個描述「人數」的字段不能通過一個事務以後變成負數。出現上述狀況時,咱們能夠在應用中選擇手動觸發回滾。這樣能夠保證數據庫仍然處於合法的狀態。