1. 程式人生 > >不會吧!不會吧!不會真有人不熟悉資料庫吧?這一篇讓你重新認識!!!

不會吧!不會吧!不會真有人不熟悉資料庫吧?這一篇讓你重新認識!!!

# 資料庫“真經” @[TOC](文章目錄)
#### 基本概念 1. mysql是一個處理檔案的軟體,可以將資料庫看作是一個資料夾,一個表看作是excel表或者是一個檔案 2. 結構化查詢語言 (Structured Query Language),具有定義、查詢、更新和控制等多種功能,是關係資料庫的標準語言 3. sql分類: 1. 資料操縱語言DML Data Manipulation Language,操作的物件主要是資料 : SELECT INSERT UPDATE DELETE 2. 資料定義語言DDL Data Definition language,操作的物件主要是表 : CREATE ALTER DROP RENAME TRUNCATE 3. 資料控制語言DCL Data Control Language ,操作的物件主要是角色: GRANT REVOKE 4. Transaction,操作的物件主要是一次事務: COMMIT ROLLBACK SAVEPOINT 4. 關係型資料庫:sql、mysql、sql server、sqlite、orcle、db2等,非關係型資料庫:mongodb、redis等 #### 基礎操作 ##### 資料庫的操作: 1. 建立使用者 `create user name identified by password;` 2. 更改密碼 `update user set password=password("1123") where user="user";` 3. 授予權力 `grant powers on tablename/databasename to username;` ` grant all privileges on userInfo to user0;授予使用者對於表的所有許可權` 4. 撤銷權力 `revoke powers on tablename/databasename from username;` 5. 建立 create database test0 character set utf8;` 6. 刪除 `drop database name;` ##### 表的操作 1. 增 ```sql create table name{ ...... }engine=innodb charactor set utf8mb4; ``` 2. 刪 1. 刪表 `drop table name;` 2. 刪資料 1. 全部 `delete from table;` `truncate table name;` 2. 單條 `delete from table where ...`刪除後再次插入的話,若有自增的欄位則會接著刪除欄位的值 3. 查 select * from tablename;` 4. 改 `update name set columns = values;` 5. 查看錶得相關屬性: `desc tbname; 查看錶得屬性` 6. 表重新命名 `rename old_name to new _name`要求是表的所有者 ##### 資料的操作 1. 增 `insert into tablename(columns...) values(..),(...),...;` 2. 刪 `delete from tablename where xxx;` 3. 改 `update tablename set column = xxx where xxx;` 4. 查 `select * from tablename;` ##### 欄位的操作 1. 增 `alter table name add column type;` 2. 刪 `alter table name drop column;` 3. 改 `alter table name modify(column type);` ##### 資料約束 1. 整數 1. int 2. tinyint 3. largeint 2. 浮點數 1. float 2. double 3. decimal 3. 字串 1. char 2. varchar 3. text 4. 關於char和varchar:在儲存效率方面varchar更高,在查詢的情況下char效率更高 4. 日期 1. time 2. date 3. datatime 5. 集合(表示欄位可以取其中到的元素的組合) ```sql create table name( columns set(...) ) ``` 6. 列舉(表示只能用其中的一個值) ```sql create table name( columns enum(...) ) ``` 7. 外來鍵 ```sql create table tb1( constraint foreign_key_name foreign key(column_name) references other_table_name(column_name ) ``` 8. 聯合主鍵,主鍵只有一個,但是可以由多個欄位共同組成。 ```sql create table name( id int..., name ...; primery key(id, name) ) ``` 9. 聯合外來鍵 ```sql create table name( id ..., name ..., primery key (id, name), condtraint fk_name foreign key(id,name) references other(id, name) ) ``` 10. 唯一索引 1. 單欄位索引 `unique unique_name (column);` 2. 聯合索引, 表示索引的組合是唯一的 `unique unique_name (column1, column2); ` 11. 索引與主鍵 1. 都可以加快查詢速度,且都是唯一的,都可以是聯合的 2. 索引可以為空, 主鍵不能 ##### 添加註釋 1. 為表添加註釋 `comment on table emp is "僱員表";` 2. 為列添加註釋 ` comment on column emp.Empno is "僱員工號"; ` ##### 查詢結果去重distinct 1. distinct必須放在開頭 2. 多欄位 每個欄位不一樣才去重 3. ```sql select distinct name from userinfo; ``` ##### 條件比較 1. =,!= ,<>, <,>,<=,>=,any,some,all ```sql -- any大於只查詢的最小值 -- all大於子查詢的最大值 -- some大於子查詢中介於最大值最小值之間的值 select * from class0 where class0.age > some (select age from class1); select * from class0 where class0.age > any (select age from class1); select * from class0 where class0.age > all (select age from class1); ``` 2. is null,is not null:是否為空 ```sql select * from class1 where name is null; select * from class1 where name is not null; ``` 3. between x and y:篩選查詢結果的某個欄位值是否存在範圍內 ```sql select * from class1 where age between 18 and 20; ``` 4. in(list), not in(list):篩選查詢結果的某個欄位值是否存在範圍內 ```sql select * from class1 where class1.age in (select age from class0); select * from class1 where class1.age not in (select age from class0); ``` 5. exists(sub- query):查詢的結果是否存在在子查詢中 ```sql select distinct age from class0 where exists(select age from class1); ``` 6. like _ ,%,escape ‘\‘ _\% escape ‘\’ ##### 邏輯複合條件 1. not,(and, or) and優先順序最高 ```sql select * from class1 where name like "老%" and age > 21; select * from class1 where name like "老%" or age > 21; ``` 2. sql優化問題 1. AND: 把檢索結果較少的條件放到後面 2. OR: 把檢索結果較多的條件放到後面 ##### like 1. 條件表示式中字串匹配操作符是‚like 1. %萬用字元表示任意字元出現任意次數 2. _萬用字元表示任意字元出現一次 2. 技巧和注意事項: 1. 不能過度使用萬用字元。如果其他操作符能達到目的,就不要使用萬用字元。 2. 確實需要使用萬用字元時,除非絕對必要,否則不要把萬用字元用到搜尋模式最開始處,因為這樣搜尋起來是最慢的 ##### order by 1. 按照單個列排序:order by col ```sql select * from class1 order by age; ``` 2. 降序和升序:order by col desc (asc) ```sql select * from class1 order by age desc; ``` 3. 按多個列排序(優先順序):order by col1 desc(asc), col2 desc(asc) ```sql select * from class1 order by age desc, id asc; ``` ##### 並集,全集,交集,差集 1. 並集(union):去重 ```sql select age from class1 union select age from class0; ``` 2. 全集(union all) ```sql select age from class1 union all select age from class0; ``` 3. 交集 ```sql select age from class1 where age in (select age from class0); ``` 4. 差集 ```sql select age from class1 where age not in (select age from class0); ``` ##### SQL 函式 函式一般是在資料上執行的,它給資料的轉換和處理提供了方便。只是將取出的資料進行處理,不會改變資料庫中的值 Sql函式可以分為組函式和單行函式。 1. 組函式又被稱作聚合函式,用於對多行資料進行操作,並返回一個單一的結果,組函式僅可用亍選擇列表戒查詢的having子句 2. 單行函式對單個數值進行操作,並返回一個值 ###### 單行函式的分類 1. 字元函式 1. concat(string1, string2)連線兩個字串 2. initcap(string) string中每個單詞首字母大寫 3. Lower(string) 以小寫形式返回string 4. lpad,rpad 填充字元型資料 5. ltrim/rtrim (string1,string2) 6. trim(A from B) 7. Substr() 提取字串的一部分substr(string, 1, 2) 8. upper(string)以大寫形式返回string 9. Instr()字串出現的位置, instr( string ,’A‘) 10. Length()字串長度 ,一個漢字3個長度 2. 數字函式 數字函式以NUMBER型別為引數返回NUMBER值 1. round(number, n) 返回四捨五入後的值 2. trunc(number, n) 3. mod(x, y)求餘數 4. ceil()上取整 5. floor()下取整 3. 日期和時間函式 1. Add_months(d,x) 返回加上x月後的日期d的值 2. LAST_DAY(d) 返回的所在月份的最後一天 3. Months_between(date1,date2) 返回date1和date2之間月的數目 4. 轉換函式 1. to_char 2. to_number 3. to_date ###### 單行函式巢狀 1. 單行函式可被嵌入到任何層 2. 巢狀函式從最深層到最低層求值 ###### 組函式 組函式基亍多行資料返回單個值 1. avg():返回某列的平均值 2. min():返回某列的最小值 3. max():返回某列的最大值 4. sum():返回某列值的和 5. count():返回某列的行數 6. **組函式僅在選擇列表和Having子句中有效** ##### 資料分組 1. 建立分組 1. group by 子句 Group by 子句可以包含任意數目的列 2. 除組函式語句外, select語句中的每個列都必須在group by 子句中給出 3. 如果分組列中具有null值,則null將作為一個分組返回。如果列中有多行null值,他們將 分為一組 4. Group by 子句必須出現在where子句之後, order by 子句之前 2. 過濾分組(having子句) 1. Where過濾行, having過濾分組 2. Having支援所有where操作符 3. 分組排序 1. 一般在使用group by 子句時,應該也給出order by子句 4. 出現在SELECT列表中的欄位,如果出現的位置不是在組函式中,那麼必須出現在GROUP BY子句中 5. 不能在 WHERE 子句中使用組函式.不能在 WHERE 子句中限制組. 使用Having對分組進行限制 ##### Select子句順序 1. Sql語句執行過程: 1. 讀取from子句中的基本表、檢視的資料, [執行笛卡爾積操作] 2. 選取滿足where子句中給出的條件表示式的元組 3. 按group子句中指定列的值分組,同時提取滿足Having子句中組條件表示式的那些組 4. 按select子句中給出的列名戒列表達式求值輸出 5. Order by子句對輸出的目標表進行排序 ##### 多表查詢 ###### 交叉連線 1. CROSS JOIN產生了一個笛卡爾積,就象是在連線兩個表格時忘記加入一個WHERE子句一樣 ```sql select emp.empno, emp.ename, emp.deptno, dept.loc from emp , dept; ``` 2. 可以使用CROSS JOIN 來達到相同的結果 ```sql select emp.empno, emp.ename, emp.deptno, dept.loc from emp cross join dept; ``` ###### 自然連線 1. NATURAL JOIN子句基亍兩個表中列名完全相同的列產生連線 1. 兩個表有相同名字的列 2. 資料型別相同 3. 從兩個表中選出連線列的值相等的所有行 ```sql select * from emp natural join dept Where deptno = 10; ``` 2. 自然連線的結果不保留重複的屬性 ###### using建立連線 ```sql select e.ename,e.ename,e.sal,deptno,d.loc from emp e join dept d using(deptno) where deptno=20; ``` using子句引用的列在sql任何地方丌能使用表名戒者別名做字首,同樣適合natural子句 ###### 使用on建立連線 1. 自然連線的條件是基亍表中所有同名列的等值連線 2. 為了設定任意的連線條件戒者指定連線的列,需要使用ON子句 3. 連線條件不其它的查詢條件分開書寫 4. 使用ON 子句使查詢語句更容易理解 ```sql select ename,dname from emp join dept on emp.deptno=dept.deptno where emp.deptno=30; ``` ###### 左外連線 在LEFT OUTER JOIN中,會返回所有左邊表中的行,即使在右邊的表中沒有可對應的列值 ```sql select e.ename,d.deptno,d.dname from dept d left outer join emp e on e.deptno=d.deptno; ``` ###### 右外連線 RIGHT OUTER JOIN中會返回所有右邊表中的行,即使在左邊的表中沒有可對應的列值 ```sql select e.ename,d.deptno,d.dname from emp e right outer join dept d on e.deptno=d.deptno; ``` ##### 分頁 ###### 一般情況 ```sql select * from (select rownum rn, t2.ename, t2.sal from (select e.ename, e.sal from emp e order by e.sal desc) t2 ) t1 where t1.rn >= 6 and t1.rn <= 10; --select * from t_user limit 0,10; limitstartRow,pageSize ``` ###### 效能優化 在使用`select * from tablenem limit start, step;` 當查詢時,會遍歷資料庫,找到start,當資料太大時就會很慢,解決方案: 1. 索引表中掃: ```sql select * from tablename where id > ? in ( select id from tablename limit start, step) ;--也會很慢 ``` 2. 最優方案: ```sql select * from tablename where id > ? limit step;--通過在主鍵中掃描,達到最快 ``` 3. 頁面只有上一頁, 下一頁max_id min_id 1. 下一頁: ```sql select * from tablename where id > max_id limit 10; ``` 2. 上一頁: ```sql select * from tablename where id < min_id order by id desc limit 10; ``` 4. 當有多頁時,上一頁 192 193 196 197 198 199 下一頁 ```sql select * from tablename where id in (select id from tablename where id > max_id limit 30) as N order by N.id desc limit 10; ``` 5. between...and...只適用於連續的id索引 #### 表設計 ##### 檢視 ###### 基礎概念 1. 檢視(view),也稱虛表, 不佔用物理空間,這個也是相對概念,因為檢視本身的定義語句還是要儲存在資料字典裡的。檢視只有邏輯定義。 每次使用的時候, 只是重新執行SQL 2. 檢視是從一個或多個實際表中獲得的,這些表的資料存放在資料庫中。那些用於產生檢視的表叫做該檢視的基表。一個檢視也可以從另一個檢視中產生 3. 檢視的定義存在資料庫中,與此定義相關的資料並沒有再存一份於資料庫中。通過檢視看到的資料存放在基表中 4. 檢視看上去非常象資料庫的物理表,對它的操作同任何其它的表一樣。當通過檢視修改資料時,實際上是在改變基表中的資料;相反地,基表資料的改變也會自動反映在由基表產生的檢視中 ###### 建立檢視 在CREATE VIEW語句後加入子查詢 ```sql CREATE [OR REPLACE] VIEW view [(alias[, alias]...)] AS subquery [WITH READ ONLY]; create or replace view v$_emp_dept as select emp.deptno,ename,dname from emp join dept on emp.deptno=dept.deptno with read only ``` ###### 使用檢視 在查詢時,不需要再寫完全的Select查詢語句,只需要簡單的寫上從檢視中查詢的語句就可以了 當檢視不再需要的時候,用“drop view” 撤銷。刪掉檢視不會導致資料的丟失,因為檢視是基於資料庫的表之上的一個查詢定義 #### 事務處理 ##### 基本概念 ###### 事務處理 1. 事務(Transaction)是一個操作序列。這些操作要麼都做,要麼都不做,是一個不可分割的工作單位,是資料庫環境中的邏輯工作單位。 事務是為了保證資料庫的完整性 2. 事務不能巢狀 3. 一個Transaction起始於一條DML(Insert、 Update和Delete )語句,結束於以下的幾種情況: 1. 使用者顯式執行Commit語句提交操作或Rollback語句回退 2. 當執行DDL(Create、 Alter、 Drop)語句事務自動提交 3. 使用者正常斷開連線時, Transaction自動提交 4. 系統崩潰或斷電時事務自動回退 ###### Commit & Rollback 1. Commit表示事務成功地結束,此時告訴系統,資料庫要進入一個新的正確狀態,該事務對資料庫的所有更新都以交付實施。每個Commit語句都可以看成是一個事務成功的結束,同時也是另一個事務的開始 2. Rollback表示事務不成功的結束,此時告訴系統,已發生錯誤,資料庫可能處在不正確的狀態,該事務對資料庫的更新必須被撤銷,資料庫應恢復該事務到初始狀態。每個Rollback語句同時也是另一個事務的開始 3. 一旦執行了commit語句,將目前對資料庫的操作提交給資料庫(實際寫入DB),以後就不能用rollback進行撤銷 4. 執行一個 DDL , dcl語句或從 SQL*Plus正常退出,都會自動執行commit命令 5. savepoint:儲存點,即相當於一個執行截斷點 ```sql delete from userInfo where name="xxx"; savepoint sp; delete from userInfo where name="xxxx"; rollback to sp; commit; -- 表示sp前面的成功執行。後面的不執行 ``` ###### 事務的四個特性:ACID 事務四大特徵:原子性,一致性,隔離性和永續性 1. 原子性(Atomicity) 一個原子事務要麼完整執行,要麼乾脆不執行。這意味著,工作單元中的每項任務都必須正確執行。如果有任一任務執行失敗,則整個工作單元或事務就會被終止。即此前對資料所作的任何修改都將被撤銷。如果所有任務都被成功執行,事務就會被提交,即對資料所作的修改將會是永久性的 2. 一致性(Consistency) 一致性代表了底層資料儲存的完整性。它必須由事務系統和應用開發人員共同來保證。事務系統通過保證事務的原子性,隔離性和永續性來滿足這一要求; 應用開發人員則需要保證資料庫有適當的約束(主鍵,引用完整性等),並且工作單元中所實現的業務邏輯不會導致資料的不一致(即,資料預期所表達的現實業務情況不相一致)。例如, 在一次轉賬過程中,從某一賬戶中扣除的金額必須與另一賬戶中存入的金額相等。**支付寶賬號100 你讀到餘額要取,有人向你轉100 但是事物沒提交(這時候你讀到的餘額應該是100,而不是200) 這種就是一致性** 3. 隔離性(Isolation) 隔離性意味著事務必須在不干擾其他程序或事務的前提下獨立執行。換言之,在事務或工作單元執行完畢之前,其所訪問的資料不能受系統其他部分的影響。 4. 永續性(Durability) 永續性表示在某個事務的執行過程中,對資料所作的所有改動都必須在事務成功結束前儲存至某種物理儲存裝置。這樣可以保證,所作的修改在任何系統癱瘓時不至於丟失 5. 所有的這些都是為了保證資料的一致性 ###### 提交或回滾前資料的狀態 1. 以前的資料可恢復 2. 當前的使用者可以看到DML操作的結果 3. 其他使用者不能看到DML操作的結果 4. 被操作的資料被鎖住,其他使用者不能修改這些資料 ###### 提交後資料的狀態 1. 資料的修改被永久寫在資料庫中. 2. 資料以前的狀態永久性丟失. 3. 所有的使用者都能看到操作後的結果 4. 記錄鎖被釋放,其他使用者可操作這些記錄 ###### 回滾後資料的狀態 語句將放棄所有的資料修改 1. 修改的資料被回退 2. 恢復資料以前的狀態 3. 行級鎖被釋放 ##### 事務測試 1. 開啟mysql的命令列,將自動提交事務給關閉 ```sql --檢視是否是自動提交 1表示開啟,0表示關閉 select @@autocommit; --設定關閉 set autocommit = 0; ``` 2. 資料準備 ```sql --建立資料庫 create database tran; --切換資料庫 兩個視窗都執行 use tran; --準備資料 create table psn(id int primary key,name varchar(10)) engine=innodb; --插入資料 insert into psn values(1,'zhangsan'); insert into psn values(2,'lisi'); insert into psn values(3,'wangwu'); commit; ``` 3. 測試事務 ```sql --事務包含四個隔離級別:從上往下,隔離級別越來越高,意味著資料越來越安全 read uncommitted; --讀未提交 read commited; --讀已提交 repeatable read; --可重複讀 serialize --序列化執行,序列執行 --產生資料不一致的情況: 髒讀 不可重複讀 幻讀 ``` | 隔離級別 | 異常情況 | | 異常情況 | | -------- | -------- | ---------- | -------- | | 讀未提交 | 髒讀 | 不可重複讀 | 幻讀 | | 讀已提交 | | 不可重複讀 | 幻讀 | | 可重複讀 | | | 幻讀 | | 序列化 | | | | 4. 測試1:髒讀 read uncommitted,當一個事務在更新資料時,另一個事務讀取到了該事務還未commit的事務 ```sql set session transaction isolation level read uncommitted; A:start transaction; A:select * from psn; B:start transaction; B:select * from psn; A:update psn set name='msb'; A:selecet * from psn B:select * from psn; --讀取的結果msb。產生髒讀,因為A事務並沒有commit,讀取到了不存在的資料 A:commit; B:select * from psn; --讀取的資料是msb,因為A事務已經commit,資料永久的被修改 ``` 更新資料: ![](https://img2020.cnblogs.com/blog/2061063/202103/2061063-20210304103417721-258253405.png) 插入: ![](https://img2020.cnblogs.com/blog/2061063/202103/2061063-20210304103432846-1534920227.png) 5. 測試2:當使用read committed的時候,就不會出現髒讀的情況了,當時會出現不可重複讀的問題,即在同一次事務中讀到不同的值,就好比取錢的時候,銀行卡插進去是1000元,等了幾分鐘就只有幾百元了 ```sql set session transaction isolation level read committed; A:start transaction; A:select * from psn; B:start transaction; B:select * from psn; --執行到此處的時候發現,兩個視窗讀取的資料是一致的 A:update psn set name ='zhangsan' where id = 1; A:select * from psn; B:select * from psn; --執行到此處發現兩個視窗讀取的資料不一致,B視窗中讀取不到更新的資料 A:commit; A:select * from psn;--讀取到更新的資料 B:select * from psn;--也讀取到更新的資料 --發現同一個事務中多次讀取資料出現不一致的情況 ``` ![](https://img2020.cnblogs.com/blog/2061063/202103/2061063-20210304103445634-1894743462.png) 6. 測試3:當使用repeatable read的時候(按照上面的步驟操作),就不會出現不可重複讀的問題,但是會出現幻讀的問題,也就是一個事務完成新增資料的操作時,另一個事務感知到了,但是並不會展示,僅僅感知 ```sql set session transaction isolation level repeatable read; A:start transaction; A:select * from psn; B:start transaction; B:select * from psn; --此時兩個視窗讀取的資料是一致的 A:insert into psn values(4,'sisi'); A:commit; A:select * from psn;--讀取到新增的資料 B:select * from psn;--讀取不到新增的資料 B:insert into psn values(4,'sisi');--報錯,無法插入資料 --此時發現讀取不到資料,但是在插入的時候不允許插入,出現了幻讀,設定更高級別的隔離級別即可解決 ``` ![](https://img2020.cnblogs.com/blog/2061063/202103/2061063-20210304103500168-741925148.png) 7. 總結:以上問題都沒有保證資料的一致性 #### 約束 constraint ##### 基本概念 1. 當我們建立表的時候,同時可以指定所插入資料的一些規則,比如說某個欄位不能為空值,某個欄位的值(比如年齡)不能小於零等等,這些規則稱為約束。約束是在表上強制執行的**資料校驗規則** 2. 支援下面五類完整性約束 1. NOT NULL非空 2. UNIQUE Key 唯一鍵 3. PRIMARY KEY 主鍵 4. FOREIGN KEY 外來鍵 5. CHECK 自定義檢查約束 ##### 建立約束的時機 1. 在建表的同時建立 2. 建表後建立 ##### 分類 約束從作用上分類,可以分成兩大類: 1. 表級約束:可以約束表中的任意一列或多列。可以定義除了Not Null以外的任何約束 2. 列級約束:只能約束其所在的某一列。可以定義任何約束 ###### 列級約束 列級約束: 從形式上看,在每列定義完後馬上定義的約束,在逗號之前就定義好了 ```sql carete table parent(c1 number primary key ); create table child (c number primary key , c2 number references parent(c1)); ``` ###### 表級約束 ```sql create table child( c number , c2 number , primary key (c2), foreign key(c2) references parent(c1)); ``` ##### 具體分類 ###### 主鍵約束( PRIMARY KEY) 1. 主鍵約束是資料庫中最重要的一種約束。在關係中,主鍵值不可為空,也不允許出現重複,即關係要滿足實體完整性規則 2. 注意: 1. 主鍵從功能上看相當於非空且唯一 2. 一個表中只允許一個主鍵 3. 主鍵是表中能夠唯一確定一個行資料的欄位 4. 主鍵欄位可以是單欄位或者是多欄位的組合 5. Oracle為主鍵建立對應的唯一性索引 3. 建議命名: 1. 約束\_表名_欄位 4. 主鍵可用下列兩種形式之一定義 1. 主鍵子句:在表的定義中加上如下子句 `primary key(列)` 2. 主鍵短語:在主屬性的定義之後加上`primary key字樣` ```sql create table t3( id number(4), constraint t3_pk primary key(id) ) ``` ###### 非空約束(NOT NULL) 1. 確保欄位值不允許為空 2. 只能在欄位級定義 ```sql CREATE TABLE employees( employee_id NUMBER(6), name VARCHAR2(25) NOT NULL, salary NUMBER(8,2), hire_date DATE CONSTRAINT emp_hire_date_nn NOT NULL ) ``` ###### 唯一性約束(UNIQUE) 1. 唯一性約束條件確保所在的欄位或者欄位組合不出現重複值 2. 唯一性約束條件的欄位允許出現空值 ```sql CREATE TABLE employees( id NUMBER(6), name VARCHAR2(25) NOT NULL UNIQUE, email VARCHAR2(25), salary NUMBER(8,2), hire_date DATE NOT NULL, CONSTRAINT emp_email_uk UNIQUE(email) ); ``` ###### CHECK 約束 1. Check約束用於對一個屬性的值加以限制 2. 在check中定義檢查的條件表示式,資料需要符合設定的條件 ```sql create table emp3 ( id number(4) primary key, age number(2) check(age > 0 and age < 100), salary number(7,2), sex char(1), constraint salary_check check(salary > 0) ) ``` ###### 關係模型的三類完整性規則 為了維護資料庫中的資料與現實世界的一致性,關係資料庫的資料與更新操作必須遵循下列三類完整性規則: 1. 實體完整性規則:這條規則要求關係中在組成主鍵的屬性上不能有空值 2. 參照完整性規則:這條規則要求“不引用不存在的實體”。例如: deptno是dept表的主鍵,而相應的屬性也在表emp中出現,此時deptno是表emp的外來鍵。在emp表中, deptno的取值要麼為空,要麼等於dept中的某個主鍵值 3. 使用者定義的完整性規則 :使用者定義的完整性規則反應了某一具體的應用涉及的資料必須滿足的語義要求 ###### 外來鍵約束( FOREIGN KEY) 1. 外來鍵是表中的一個列,其值必須在另一表的主鍵或者唯一鍵中列出 作為主鍵的表稱為“主表”,作為外來鍵的關係稱為“依賴表” 2. 外來鍵參照的是主表的主鍵或者唯一鍵 3. 對於主表的刪除和修改主鍵值的操作,會對依賴關係產生影響,以刪除為例:當要刪除主表的某個記錄(即刪除一個主鍵值,那麼對依賴的影響可採取下列3種做法: 1. RESTRICT方式:只有當依賴表中沒有一個外來鍵值與要刪除的主表中主鍵值相對應時,才可執行刪除操作 2. CASCADE方式:將依賴表中所有外來鍵值與主表中要刪除的主鍵值相對應的記錄一起刪除 3. SET NULL方式:將依賴表中所有與主表中被刪除的主鍵值相對應的外來鍵值設為空值 ```sql FOREIGN KEY (DEPTNO) REFERENCES DEPT(DEPTNO); ``` ##### 約束的新增和撤銷 約束的新增和撤銷 1. 新增: `alter table tablename add constraint con_name unique(col) ;` 2. 刪除 `alter table tablename drop constraint com_name [cascade] ;` #### 索引 ##### 基本概念 1. 索引是為了加快對資料的搜尋速度而設立的。索引是方案(schema)中的一個數據庫物件,與表獨立存放 2. 索引的作用:在資料庫中用來加速對錶的查詢,通過使用快速路徑訪問方法快速定位資料,減少了磁碟的I/O 3. Sql中的索引是非顯示索引,也就是在索引建立以後,在使用者撤銷它之前不會在用到該索引的名字,但是索引在使用者查詢時會自動起作用 4. 索引的建立有兩種情況: 1. 自動: 當在表上定義一個PRIMARY KEY 或者UNIQUE 約束條件時 2. 手動: 使用者可以建立索引以加速查詢 5. 開發中使用索引的要點: 1. 索引改善檢索操作的效能, 但降低資料插入、修改和刪除的效能。在執行這些操作時, DBMS必須動態地更新索引 2. 索引資料可能要佔用大量的儲存空間 3. 並非所有的資料都適合於索引。唯一性不好的資料(如省)從索引的到的好處不比具有更多可能值的資料(如姓名)從索引得到的好處多 4. 索引用於資料過濾和資料排序。如果你經常以某種特定的順序排序資料,則該資料可能是索引的備選 5. 可以在索引中定義多個列(如省加城市),這樣的索引只在以省加城市的順序排序時有用。如果想按城市排序,則這種索引沒有用處 ##### 使用 ###### 建立 `CREATE INDEX index ON table (column[, column]...); ` ###### 刪除 `DROP INDEX upper_last_name_idx; ` ##### 進階 ###### 不能命中索引的幾種方式 1. like 2. 呼叫函式 3. or ```sql select * from tablename where index_column = ? or not_column_name=?--不會走索引 select * from tablename where index_column1 = ? or not_column_name=? and index_column2=?--會直接遮蔽or...and之間的走 ``` 4. 索引!=(主鍵除外) 5. \> (主鍵除外) 6. 滿足的條件的值的型別與宣告索引時的型別不一致(主鍵除外) 7. order by(主鍵除外) ##### 注意事項: 1. 避免使用select 2. *count(1)或count(列)代替count(*) 3. 建立表時儘量使用char代替varchar 4. 表得欄位順序固定長度的欄位優先 5. 組合索引代替多個單列索引(經常使用多個條件查詢時) 6. 儘量使用短索引 7. 使用連線(join)代替子查詢 8. 連表注意型別需要一致 9. 索引雜湊值(重複少)不適合建立索引。例如:性別。 #### 觸發器 1. 首先:delimiter 設定sql語句的結束標誌,sql語句預設是“;”結束也就是:`delimiter ;`,可以修改為:`delimiter //`表示當遇到“//”,語句才算結束,可以恢復設定:`delimiter ;` 2. trigger用於在增、刪、改的前後觸發一系列動作 ```sql create trigger t1 on tablename before insert for each row; create trigger t1 on tablename after insert for each row; ``` 3. new/old用於表示插入、刪除、更新操作的行的資料 1. new表示新插入的資料行 ```sql delimiter // create trigger t1 befor insert on tablename for each row begin insert into t2(name) values(new.name); end // delimiter ; ``` 2. old表示即將被刪除的資料行 ```sql delimiter // create trigger t1 befor delete on tablename for each row begin insert into t2(name) values(old.name); end // delimiter ; ``` #### 儲存過程 用一個別名來描述多個sql語句的執行過程 1. 最簡單的使用 ```sql delimiter // create PROCEDURE p1() begin select * from userinfo; end // delimiter ; call p1(); ``` 2. 傳參(in, out, inout) 1. in 表示傳入的引數, 可以傳入數值或者變數,即使傳入變數,並不會更改變數的值,可以內部更改,僅僅作用在函式範圍內 ```sql delimiter // create procedure p2( in v1 int ) begin set v1 = 2 * v1; select v1; end // delimiter ; call p2(19); ---------------- delimiter // create procedure p6( in v int ) begin set v = 10; select v; end // delimiter ; call p6(10); set @v4 = 0; call p6(@v4); select @v4; -- 此時@v4依然為0 ``` 2. out 表示儲存執行儲存過程的返回結果,且引數只能是一個變數,且只能對其賦值(函式執行完以後也生效),不能在函式內獲取其值 ```sql delimiter // create procedure p3( out v int ) begin set v = 10; end // delimiter ; set @v1 = 0; # @varible_name 類似於定義一個區域性變數,跟session一樣 call p3(@v1); select @v1; ----------------------------- delimiter // create procedure p4( out v int ) begin set v = v + 5; -- 這兒有問題,不能這樣,只能直接賦值 select v; end // delimiter ; -- 這段程式碼是有問題的。 delimiter // create procedure p5( out v int ) begin set v = 5; -- 對的 select v; end // delimiter ; set @v3 = 0; call p5(@v3); create procedure name( in v1 int, out v2 int ) begin set v2 = v1; select v2; end call(num, num) ``` 3. inout 表示從外部傳入的引數經過修改後可以返回的變數,既可以使用傳入變數的值也可以修改變數的值(即使函式執行完) ```sql delimiter // create procedure p7( inout v int ) begin set v = 9999; select v; end // delimiter ; call p7(10); set @v5 = 0; call p7(@v5); select @v5; ------------------------------------ delimiter // create procedure p8( inout v int ) begin set v = v + 9999; select v; end // delimiter ; set @v6 = 1; call p8(@v6); select @v6; ``` 3. 總結: 1. in只可以讀取值/變數,不能更改 2. out不能讀,可以更改 3. inout既可以讀又可以更改 #### 往期精彩文章 1. [爆肝!!!!JavaSE知識點1.3w字總結](https://blog.csdn.net/weixin_45571140/article/details/113883981?spm=1001.2014.3001.5501) 2. [關於Java高併發程式設計你需要知道的“升段攻略”](https://blog.csdn.net/weixin_45571140/article/details/114240909?spm=1001.2014.300