Oracle數據庫
數據庫簡單來講就是一個存放數據的倉庫,並存放在計算機中,實現數據的持久化,數據庫的中數據要按照一定的格式來存放,並可以實現多個用戶的數據共享。Oracle數據庫是基於標準SQL語言的數據庫產品
數據庫DataBase包含5部分:
- 數據庫管理系統 DataBaseManagementSystem
- 數據庫應用系統 DataBaseAplicationSystem
- 數據庫管理員 DataBaseAdministrator
- 最終用戶 FinalUser
- 數據庫系統 DataBaseSystem
重要的NET文件配置:
listener.ora:監聽器配置(服務器端):通過增加客戶端的IP,端口,協議來監聽客戶端,客戶端就有訪問此數據庫的權限
tnsnames.ora:本地配置(客戶端):通過增加服務端的IP,端口,協議來訪問對應的服務端,前提是服務端口已經配置好了監聽你的權限,否則無法訪問
Tips:數據庫中的oradata/orcl(全局數據庫名稱)文件放置的是你自己存放好的數據
交互式操作使用SQL語句:
數據庫表 table
索引 index
視圖 view
序列 sequence
同義詞 synonym
表空間 tablespace
批處理操作使用PL/SQL編程(屬於ORACLE SQL的擴展語句):
存儲過程 procedure
函數 function
觸發器 trigger
包 package
一般我們使用的最多的SQL語句是數據庫表table,表與表之間的關係有三種
- 一對一:一個員工編號對應一個員工
- 一對多:一個部門對應多個員工
- 多對多:一個員工可能做了多個項目,那麼一個項目下面可能又有很多員工分工完成
SQL(Structured Query Language)語句
DQL(數據查詢語言)
select(查詢)
DML(數據操作語言)
insert(插入元素內容)、update(修改或更新元素內容)、delete(刪除元素內容)
DDL(數據定義語言)
create(創建表結構)、alter(更改表結構)、drop(刪除表結構)
DCL(數據控制語言)
grant(授予權限)、revoke(撤銷權限)
需要區分的是DML(數據操作語言)和DDL(數據定義語言)都有修改,刪除功能
但是數據操作語言主要是針對表中的數據,而數據定義語言主要是針對數據庫對象(表、索引、視圖、觸發器、存儲過程、函數、表空間等)
DQL(數據查詢語言)
DQL中的關鍵字只有select,但是確實這四種語句中最常用也最爲複雜的語句,要了解查詢語句首先需要了解表中的一些概念
關係:整個二維表
關係名:表格名稱:例如員工信息表(EMP)
元組:行數據(記錄):類似於一個員工對象中存放的信息
屬性:列數據(字段)
屬性名:列名稱(字段名):每一列字段的名稱,例如name,age等
主鍵:唯一確定元組的屬性組(關鍵字):類似於Map集合中的鍵值,有唯一性
域:屬性的取值範圍:就是一個屬性的上限下限範圍
那麼列舉我們常用的簡單的select查詢操作
簡單查詢語句:
select * from emp;//查詢員工表所有數據
select * from dept;//查詢部門表所有數據
select empno, ename, sal from emp;//從員工表中查詢員工號,員工姓名和工資
使用算術表達式查詢:
select empno, ename, sal, sal*12 from emp//查詢員工號,員工姓名和年工資
字段別名:
select empno, ename "Ename", sal*12 "Anual Salary" from emp;//查詢員工號和年工資
那麼table中顯示工資的字段就不再是salary*12而是Anual Salary,增強了可讀性,字段別名的命名方式有三種:
1.sal * 12 Anual Salary
2.sal * 12 “Anual Salary”
3.sal * 12 as Anual Salary
注意: 別名如果含有空格或其他特殊字符或大小寫敏感,需用雙引號括起來
否則可能會讀取失敗,當然as可以省略,不過加上as也變相的增強了可讀性
連接運算符:
select ename || ' is a ' || job from emp;
使用上述方式可以將 ename和job這兩個字段合併成一個字段,配合字段別名會有意想不到的效果
select ename || ' is a ' || job as SelfInfo from emp;
注意:
1.ORACLE數據庫中的 + 只有算數運算的功能,連接兩個字符串的功能仍需要 || 來實現
2.ORACLE數據庫中" "中括起來的內容只能是字段別名,字符串需要使用’ '括起來
消除重複:
select distinct job,deptno from emp;//查找員工的職位和部門編號字段並去除重複
注意:
Distinct是對所有字符的組合去重
排序:
select ename, sal from emp order by sal desc;//查找員工的姓名和工資字段並按照工資升序排序
select * from emp order by deptno asc, sal desc;//先按照部門的號碼升序排序,再按照工資降序排序
注意:
1.asc(ascend)爲升序,desc(descend)爲降序
2.默認排序方式爲升序
3.需要對哪個信息排序就要在後面加對應的關鍵字,並用逗號隔開
查詢具體指定信息:
此時需要使用到關鍵字where,where後面加上需要查找的條件
select * from emp where hiredate = '23 1月 1982';//查找入職日期爲1982/1/23的員工信息
-- 查找員工的姓名,職位,工資字段的信息,並滿足工資在2000-4000區間並按照工資大小排序
select ename, job, sal from emp where sal > 2000 and sal < 4000 order by sal;
select ename, deptno from emp where deptno = 10 or deptno = 20;
select * from emp where job != 'MANAGER';//查找職位不爲'MANAGER'的員工信息
select * from emp where comm is not null;//查找comm不等於null的員工信息
注意:
1.ORACLE中日期有自己的格式:例如1982/1/23的格式是23 1月 1982,並且要用’ '括起來
2.ORACLE中的與邏輯運算符不是&&而是and
3.ORACLE中的與邏輯運算符不是||而是or
Tips:
1.sal > 2000 and sal < 4000 也可以替換爲 sal between 2000 and 4000
2.deptno = 10 or deptno = 20 也可以替換爲 deptno in (10,20)
3.job != ‘MANAGER’ 也可以替換爲 job <> ‘MANAGER’ 或者 not in ‘MANAGER’
模糊運算符:
此時需要使用到關鍵字like,主要用於模糊查找(不具體的查找)
select * from emp where ename like '%A';//查找員工姓名最後一個字母爲A的的員工信息
select * from emp where ename like 'A%';//查找員工姓名第一個字母爲A的的員工信息
select * from emp where ename like '%A%';//查找員工姓名包含字母爲A的的員工信息
select * from emp where ename like '_A%';//查找員工姓名第二個字母爲A的的員工信息
這裏涉及到ORACEL數據庫的通配符概念:
%:表示0個或者多個字母,和正則表達式不一樣,正則中有一個類似的表達式 X* 表示的是X的值可以有0個或者多個,而這裏指代的是0個或者多個不同或者相同的字母
_: 表示任意的一個字母
注意:以上字符如果不當作通配符使用需要轉義,例如’%_%’ escape ‘’,這就代表一個 ’ _ '字符的意思
Oracle數據庫函數
Oracle函數就和Java中方法的意思差不多,函數只是取出庫中值的副本進行處理,並不改變庫中數據本身的值
Oracle函數包含了兩大類 - 單行函數 - 多行函數
單行函數 | 多行函數 |
---|---|
數字函數,日期函數,字符函數,轉換函數,通用函數 | 聚合函數 |
單行函數
數字函數
數字函數和Java的java.lang.Math類中很多方法類似
對元素取絕對值:
select abs(sal) as Salary from emp;//
向上取整和向下取整:
select ceil(10.1) as Salary from dual;//向上取整
select floor(-10.1) as Salary from dual;//向下取整
冪:
select power(10,3) as Salary from dual;//10的3次冪
四捨五入:
select round(123.1234,2) as Salary from dual;//保留小數點後兩位並四捨五入
開方:
select sqrt(9) from dual;//對9開方
字符函數
Concat:將兩個字符串連接起來,用 || 也可以實現這個功能
select concat('I ','love you') as Message from dual;
Lower/Upper:將字符串全部小寫/全部大寫
select lower(ename), sal as ename from emp;
Initcap: 首字母大寫,其他字母小寫
select initcap(ename), sal as ename from emp;
Replace: 替換字符串中的某一個字符爲另一個字符
select replace ('He love you','He','I') as MSG from dual;//輸出I love you
日期函數
Add_months: 返回原始date加上指定月數後的日期
select hiredate,add_months(hiredate,12) from emp where empno = 7844;
Months_between: 返回兩個日期相差的月份值
select months_between('3 5月 2008','3 5月 2005') from dual;
轉換函數
轉換函數分爲自動類型轉換函數和強制類型轉換函數
select 10 + '20' from dual
輸出的結果爲30,這說明Oracle數據庫中存在着隱式類型轉換,但是建議寫上轉換函數,避免產生歧義
- to_number() : 強制轉爲數字類型
- to_char(): 強制轉爲字符類型
- to_date(): 強制轉爲日期類型
to_date()函數是可以指定日期格式的,這一點和Java中的Dataformat類有些相似
select to_date('2010/12/12','yyyy/mm/dd') from dual;
注意:
1.字符轉爲數字中的字符串必須是有效的數字字符串
2.數字類型不能直接轉爲日期類型,需要以char爲媒介,因此轉換函數之間是可以互相嵌套的
3.to_date()中如果要進行格式轉換不能包含中文!
其他函數
NVL: 如果exp1的值爲null,則返回exp2的值,否則返回exp1的值
-- 查詢員工編號,姓名,職位,年薪(工資*12 +獎金)
select empno, ename, job, sal*12 + nvl(comm,0) as AnualSal from emp;
NVL2: 如果exp1的值不爲null,則返回exp2的值,exp2爲努力了則返回exp3的值(用的不多)
-- 以下結果和上面的結果一樣
select empno, ename, job, NVL2(comm,sal*12 + comm, sal*12) as AnualSal from emp;
多行函數
聚合函數
聚合函數見名知意,就是通過函數將多行聚合爲一行。那麼我們常用的幾種函數有
max(): 求最大值
min(): 求最小值
sum(): 求和
avg(): 求平均值
另外還有一個很重要的語句叫分組語句 group by(分組)
案例:現在我們有個需求,需要按照部門編號分組並展示每一個部門員工的最高工資,最低工資,部門總工資,部門平均工資,並按照部門編號升序排序
select deptno,
max(nvl(sal,0)) as maxsalary, //求最大值
min(nvl(sal,0)) as minsalary, //求最小值
sum(nvl(sal,0)) as totalsalary, //求和
round(avg(nvl(sal,0)),2) as avgsalary, //求平均值,並且保留小數後2位數四捨五入
count(*) from emp group by deptno order by deptno; //按照部門編號分組並按部門編號升序排序
注意:
1.出現在select列表中的字段,若不是包含在多行字段中,那麼該字段必須同時在group by 子句中。
就如deptno不在select例表中,所以就必須在group by 子句中。
2.包含在group by子句中的字符則不必須出現在select列表中。這個也很好理解,也就是說deptno如果已經在group by 子句中了,那麼也可以出現在select列表中,或者不出現。
3.group by 後面允許出現多個字段
select deptno, mgr max(sal) from emp group by deptno, mgr;//先按照部門分組,再按照經理編號分組
4.having關鍵字
假設我們需要按照部門分組並且統計每一個部門有多少個人數,那麼此時就不能使用where來篩選
select deptno, count(*) from emp group by deptno having count(*) > 3;
注意:
where 後面不能加多行函數(例如sum(),avg()),having後面可以加上多行函數
where: 分組之前的篩選條件,寫在group by 之前,用來過濾行
having: 分組之後的篩選條件,寫在group by 之後,用來過濾組
DML(數據操作語言)
插入語句:
記錄插入
全值插入:insert into 表名 values(值1,值2…)
部分插入:insert into 表名(字段1,字段2…) values(值1,值2…)
注意: 字段的個數和值的個數,類型,順序三者要一致
結果集插入
// emp2和emp1的結構、個數、順序要完全一致
insert into emp2 select * from emp1;
// 插入的表中含有哪些元素,被插入的表中必須申明這些元素
insert into emp2(empno,ename) select empno,ename from emp1;
修改語句:
update 表名 set 字段名 = 修改的值
update emp set sal = 3500, comm = 500 where empno = 7521;//修改員工的工資和獎金
需要修改多個字段的時候用逗號隔開即可
刪除語句:
delete [from] 表名 [where…]
delete * from emp where enam = 'SCOTT';//刪除某個員工的記錄
Oracle數據庫還提供了另一個刪除關鍵字truncate table,叫做截斷表,使用的方法是一樣的,但是兩者有本質的區別
面試題:
Oracle數據庫中delete和truncate的區別和聯繫?
相同點:
都可以刪除表中的數據
不同點:
1.delete語句後面可以根where子句
2.truncate table語句效率比delete更高
3.delete有日誌記錄,纔會有回滾操作,truncate沒有日誌記錄,所以刪除之後不能撤掉操作。
多表聯合查詢
目前使用最多的兩個多表聯合查詢的版本分別是SQL92版本和SQL99版本
SQL92版本
笛卡爾積查詢:
select empno, ename, job, sal, dname from emp,dept;
假設左表的記錄有X條,右表的記錄有Y條,那麼根據笛卡爾積查詢到的結果爲X*Y。但是實際情況下,左表的記錄中的某一個字段和右表中的某一個字段是相同的,那麼此刻我們想要的結果沒有那麼多,比如說員工表中有部門ID,一個員工對應了一個部門,員工表有4個參數,部門表3個參數,我們預想的是聯合表有4行值,但是笛卡爾積查詢後有12條,最終查詢到的結果沒有意義。因此這種查詢很少會用到。
等值連接:
select empno, job , sal , dname from emp,
dept where emp.deptno = dept.deptno;
注意:
1.等值連接只和值有關係,跟名稱沒有關係( 比如說 emp.deptno 完全可以替換成 emp.no 和 dept.deptno 做匹配) ,不過爲了後期好區分,建議還是將相關聯的字段取相同的名字。
2.當select後面需要查詢的子句字段中包含了where後面的等值字段時,我們需要指定這個字段是屬於哪一個表的(比如 emp.deptno 或者 dept.deptno 指代不同表的相同值)
3.如果表的名字很長,我們也可以給表取別名(比如 emp e 或者 dept d,和字段別名命名差不多)
案例:查詢部門爲20的員工名稱和部門名稱
select ename, dname from emp e, dept d
where e.deptno = d.deptno//連接條件
and d.deptno = 20;//篩選條件
非等值連接:
//查詢員工的工資等級並列出員工姓名,工資和等級
select ename, sal, grade
from emp e, salgrade s
where e.sal > s.losal and e.sal < s.hisal
外連接:
使用外連接可以看到參與連接的某一方不滿足連接條件的記錄,就好比部門編號一共有4個10、20、30、40,但是表中的員工數據目前只有10、20、30,如果我想要將40的數據列舉出來,那麼就要使用外連接
左外連接:查詢左表所有匹配信息和右表中所有信息
右外連接:查詢右表所有匹配信息和左表中所有信息
下面這個案例使用的是左外連接,原因是dept表中的deptno的個數比emp中的多
select * from emp e, dept d
where e.deptno(+) = d.deptno;
自連接:
假設員工表中有這樣的兩條信息1.員工編號 2.經理編號,而經理編號實則又是員工編號,那麼如何在同一張表中將員工的信息和經理的信息放在同一列,就要使用到自連接。自連接的邏輯很簡單,就是將一張表分爲兩張表來使用。
select e1.empno, e1.ename, e2.ename from emp e1, emp e2
where e1.mgr = e2.empno;
SQL99版本
交叉連接(笛卡爾積):
select * from emp cross join dept;//功能和92版本一樣,寫法不相同
on連接(等值連接):
select * from emp e join dept d on e.deptno = d.deptno;
自然連接:
自然連接和等值連接的區別:
1.相同字段名的名稱一定要相同,也就是說要有同名列作爲連接條件
2.不能起別名
3.同名列中的數據類型不同,則會出錯
4.當有多個同名列時,自然連接必須要滿足多個條件纔會有結果,求出來的是兩個表中所有相同列匹配到的交集
USING連接:
假設員工表和部門表中有兩列相同屬性,順序和名稱的字段
deptno和loc(部門所在地)
select * from empno join deptno using(deptno,loc);
通過這種方式我們可以添加兩個字段名來進行分析,求出來的是我們指定的字段名的字段值匹配到的交集,這種方式和自然連接有些類似但不完全一樣。
USING連接和自然連接的區別
比自然連接更加靈活多變,自然連接求出來的是兩個表中所有相同列匹配到的交集,而USING連接可以指定的字段名去匹配
外連接:
相較於92版本更加了全外連接獲取兩個表中所有指定數據,並且完善了left和right,使用其中任何一個都可以達到相似的效果
左外連接:獲取左表中所有數據和右表中的匹配數據
select * from emp e left join dept d on e.deptno = d.deptno
右外連接:獲取右表所有數據和左表中的匹配數據
select * from emp e right join dept d on e.deptno = d.deptno
全外連接:獲取左表所有數據和右表中所有數據
select * from emp e full join dept d on e.deptno = d.deptno
三表聯合查詢
三表查詢的前提是三個表中兩兩之間要有相同數據,類型的字段,作爲互連條件
案例: 查詢姓名是MARCO的學生學了哪個老師的哪門課程
SQL92:
select sid, sname, sex, age, tname, cname
from student s, teacher t, course c
where s.tid = t.tid and t.cid = c.cid //連接條件
and s.sname = 'MARCO';//篩選條件
SQL99:
select sid, sname, sex, age, tname, cname from student s
join teacher t on s.tid = t.tid //連接條件
join course c on t.cid = c.cid//連接條件
where s.sname = 'MARCO'; //篩選條件
通過上述比較發現SQL92相對來說較爲簡潔,SQL99的語法更加清晰,用 join…on 作爲連接條件,where 作爲篩選條件區分開來,不過使用的話還是看個人喜好。
子查詢
案例:
>> 列出薪金高於公司平均薪金的所有員工。
select * from emp
where sal > nvl((select avg(sal) from emp),0);//子查詢
>> 列出與“SCOTT”從事相同工作的所有員工。
select * from emp
where job = (select job from emp where ename);//子查詢
子查詢步驟:
1.先查詢子查詢(例如我可以先用select語句查詢到員工的平均工資作爲一個篩選後的結果)
2.將子查詢的結果作爲主查詢的判斷輔助條件
3.最終需要的是主查詢的結果,子查詢可以是多重嵌套,不過嵌套越多,查詢的效率越低
以上的案例都是子查詢中的一個類型,叫單行子查詢 ,這裏我們就要涉及到子查詢的分類了
單行查詢:查詢的結果只有一行(例如select avg(sal) from emp) 的結果是員工工資平均值,只有一個數值)
多行查詢:查詢的結果有多行記錄(見以下詳解)
多行子查詢
多行子查詢的結果一般會有多個結果,例如select sal from emp where job = 'SALESMAN'
的結果可能會有多個
但是where後面作比較的只能對應一個值。
那麼我們就可以用到all和any關鍵字(實則上可以用max(),min()合理替換)
ALL: 和子查詢返回的所有值來比較(也就是說> ALL 表示大於所有值,即大於我們的最大值)
select * from emp where sal < all(select sal from emp where job = 'SALESMAN');
ANY:和子查詢返回的任意值來比較(也就是說> ANY 表示至少大於一個值,即大於我們的最小值)
select * from emp where sal < any(select sal from emp where job = 'SALESMAN');
案例:
查詢部門20中職務同部門10的僱員一樣的僱員信息
select * from emp
where job in (select job from emp where deptno = 10)//這裏可能會產生多行的結果,所以用in
and deptno = 20;
查詢每個部門平均薪水的等級
select d.deptno,d.dname,round(t.sal_avg,2),grade
from salgrade s,(select deptno,avg(sal) sal_avg from emp group by deptno) t,dept d
where t.deptno = d.deptno//連接條件
and t.sal_avg >= s.losal//篩選條件
and t.sal_avg < = s.hisal
order by t.sal_avg
子查詢注意事項:
1.子查詢必須使用()括住
2.除非進行分頁查詢分析,否則不要在子查詢中使用ORDER BY 子句
3.子查詢可以放在where子句以及from子句後面,當放在from子句後的話,可以把查詢結果當作另一個表來使用
數據庫常用對象
用戶 User
權力大小: 角色 > 權限
打個比方老師就是一個角色,老師有點名的權限,有監考的權限,因此一個角色可能會有多個權限,也就是說角 色是權限的集合,實際開發的時候,直接給用戶角色,我們先來引入數據庫的常見角色
數據庫角色:
DBA:管理員角色
CONNECT:登錄角色
RESOUCE:資源角色
步驟
創建用戶: create user 用戶名 Identified by 密碼
授予角色或者權限:
grant connect to marco //授予臨時用戶角色
grant resouce to marco//授予正式用戶角色
grant dba to marco//授予管理員角色(==這個角色只能由sys來授予==,一般不去授予)
注意:
1.普通用用戶是不能給自己授權的
2.一次性可以授予多個權限(例如:grant connect,resouce to marco)
撤銷權限
revoke RESOURSE from marco ;
刪除用戶
drop user marco;
表(Table)
製表格式:
create table 表名 (
字段1 數據類型,
字段2 數據類型,
字段3 數據類型,
...
字段n 數據類型
)
Oracle的數據類型
字符類型
- 固定字符類型 Char
Char(10):字節長度爲10的字符串
如果數據長度不夠總長度,數據庫會默認用空格補齊 - 可變字符類型 Varchar2
Varchar2(10): 字節長度爲10的字符串
如果數據長度不夠,將不夠的部分截取 - 可變字符類型 Nvarchar2
Nvarchar2(10):字符長度爲10的字符串
如果數據長度不夠,將不夠的部分截取
以上三種字符類型的最長字節長度都是4000,一般比較常用的是Varchar2,一般客戶註冊時輸入賬號密碼的時候是不知道後臺
Varchar和Varchar2的區別
1.varchar是標準sql語句中的,而varchar2是oracle提供的獨有的數據類型。
2.varchar對於漢字佔兩個字節,對於英文是一個字節,佔的內存小,varchar2都是佔兩個字節。
3.varchar對空串不處理,varchar2將空串當做null來處理。
4.varchar最大長度是2000,varchar2最大長度是4000
數字類型
- 整型
number(3): 3位整數 -999~999 - 浮點型
number(5,2): 5代表總長,2是小數點之後的部位
如果存儲超過了小數規定的位數,會進行四捨五入,並保留規定的小數的位數
如果括號中什麼都不寫number()默認的情況下,精度爲38位,取值在1-38之間
日期類型
Date :存儲日期和時間 在Java的類中對應的是 java.sql.Date(該類是Java.util.Date的子類)
Timestamp:比date更精確(可以精確到時分秒)
LOB
BLOB:存儲二進制對象,如圖像、音頻和視頻文件 (實際開發,存儲的都是多媒體的地址)
CLOB:存儲字符格式的大型對象
Oracle的約束(Constraint)
1.主鍵約束primary key:列數據唯一且不能爲空,主鍵可以包含表的一列(可以在字段定義)或者多列(必須在表級定義)
2.非空約束not null:值不能爲空
3.唯一約束unique: 字段(列)值必須唯一
4.檢查約束check: 某列取值範圍限制、格式限制等
5.外鍵約束foreign key: 用於兩表間建立關係,需要指定引用主表的那列,外鍵通常用來約束兩個表之間的數據關係,定義外鍵的那張表稱爲子表,另一張表稱爲主表。在表的創建過程中,應該先創建主表,後創建子表。
主鍵約束
要求學生的學號不能爲空且必須唯一
sid varchar2(5) primary key//字段級約束寫法
constraint pk_students_sid primary key(sid)//表級約束寫法
非空約束
要求學生姓名不能爲空
sname varchar2(20) not null//字段級約束寫法
唯一約束
要求email必須是唯一的
email varchar(50) unique//字段級約束寫法
constraint uk_students_email unique(email)//表級約束寫法
檢查約束
要求性別必須爲男或者女
sex varchar2(6) check(sex = 'men' or sex = 'women')//字段級約束寫法
constraint ck_students_sex check(sex = 'men' or sex = 'women')//表級約束寫法
外鍵約束
假設現在有兩張表,一張班級表(主表),一張學生表(子表),通過班級編號cid將兩個表關聯起來
通過約束讓學生表中cid必須在班級表的cid規定的範圍之內,這就叫做外鍵約束
constraints fk_students_cid foreign key(cid) reference clazz (cid);
注意:
1.子表中的cid類型、長度要和主表中的cid一致,但是名稱可以不一樣
2.必須先創建主表,再創建子表,因爲子表的數據是被關聯的,若主表數據不存,子表的數據就不能引用主表的
3.插入數據的時候要先給主表插入,再給子表插入數據
4.必須先刪除子表,再刪除主表
5.Oracle支持級聯刪除,意思就是將主表的記錄刪除了,子表被關聯的記錄跟着就被刪除了
6.Oracle支持set null,意思就是將主表的記錄刪除了,子表被關聯的外鍵那一列置爲null
7.外鍵約束可以爲多個,且外鍵約束可以爲null
補充:外鍵的級聯cascade刪除和set null置空刪除
constraints fk_students_cid foreign key(cid) reference clazz(cid) on delete set cascade
constraints fk_students_cid foreign key(cid) reference clazz(cid) on delete set null
這兩方式的區別就是當使用cascade刪除主表外鍵關聯值時,子表關聯的外鍵的所有信息將一併被刪除
當使用set null刪除主表外鍵關聯值時,子表的外鍵關聯字段將置爲null,這種做法相對來講比較合理,當然還是要根據需求要進行選擇
約束還分爲字段級約束和表級約束
字段級約束
約束直接寫在字段之後,系統會自動的給每一個約束起名字,所以如果發生錯誤,程序員不方便去查看到底是哪個約束出現了錯誤,但是這種方法相對來說很簡單
例如:sid varchar2(5) primary key
表級約束
所有的約束全都寫在所有的字段後面,程序員可以自己給表取名字,因此發生錯誤了,程序員可以知道問具體出現在哪個地方,但是這種方法相對來說比較複雜
例如:constraints pk_students_sid primary key(sid);
注意:
1.一個表最多隻能有一個主鍵
2.一個主鍵可以包含多個字段(因此我們可以把需要用到主鍵約束的字段全部放在主鍵約束的括號中)
3.只有表級約束才能寫聯合主鍵(約束多個字段)
constraints pk_students_sid_sname primary key(sid, sname);
4.一個字段可以寫多個約束
5.唯一約束可以爲空,而且可以多個爲空(打個比方,如果郵箱設置了unique,如果多個成員都沒有寫有郵箱,也是被允許的)
6.not null只能寫在字段(列)級約束中,不能寫在表約束
約束的完整性
域完整性約束(非空+檢查):代表字段(列)的約束,一般是約束列的規則
實體完整性約束(主鍵+唯一):一般是約束行的規則
引用完整性約束(外鍵約束):表和表之間的約束
表的操作
除了之前提到的create創建表,還有以下表操作
刪除表:
drop table students;
添加一列:
alter table students add habits varchar2(50);
添加多列:
alter table students add habits varchar2(50) add qqNumber varchar2(20);
刪除一列:
alter table students drop column qqNumber;
刪除多列:
alter table students drop column(habits ,qqNumber);
添加約束:
alter table students add constraints pk_students_habits primary key(habits);
刪除約束:
alter table students drop constraints pk_students_habits;
序列(Sequence)
我們的每張表基本本上都會設一個主鍵,用來區分每條記錄沒有重複,但是客戶在輸入的時候並不知道自己的輸入的數據是否重複,並且如果輸入了重複,會報錯,因此爲了保證主鍵這一列永遠不會重複(讓系統自動生成主鍵),我們可以使用序列來解決。使用序列(一種對數字類型做自增或者自減的操作)。
創建序列
create sequence seq_1 //默認序列,初始值爲1,增量爲1
查詢序列
select seq1.nextval from dual;//查看下一個值
select seq1.currval from dual;//查看當前值
使用序列
當我們使用insert語句的使用就要使用序列
insert into student values(seq1.nextval,'marco','men',18);//此處的seq1.nextval就替代了手動輸入學號
刪除序列
drop sequence seq_1/
注意: 當序列中包含序列編號的行被刪除之後,那麼這個序列將永久刪除,這個編號將不會再出現
索引(Index)
索引就好比是字典的目錄,按照索引來查找時,查找的速度會更快,數據庫會默認的給主鍵或者Unique去創建索引,因此爲我們按照主鍵/Unique值來查找數據速度會更快。當我們不想按照索引查找,想使用其他字段查找數據並且達到和主鍵一樣的效果,就可以手動去添加索引。
create index index_1 on student(sname)//給student表的sname字段創建索引
注意: 當使用查詢語句select的時候索引纔會生效
索引的結構
索引默認採用的是m階B樹結構(balance tree of order m),是一種平衡樹
樹根
樹幹
樹枝
樹葉: 數據全部集中在葉子節點
ROWID的格式:
數據對象編號 | 文件編號 | 塊編號 | 行編號 |
---|---|---|---|
AAABnl | AAF | AAAAAP | AAA |
假如我們對student表中的sname創建了索引,當我們去查詢sname的時候,會先通過索引表找到索引,索引是按照B樹結構,分區塊範圍查找,假設我們要查找的sname的索引爲30,那麼我們查找數據的順序如下
找到區段中對應的索引,最後再找到我們要查詢字段的ROWID,通過ROWID定位到數據。因此我們對數據做查詢,實則是查詢它的ROWID。
索引的缺點
1.索引會單獨的佔用內存空間,消耗空間資源
2.當我們執行了delete或者insert語句之後,DBMS後臺要對索引做大量的位移維護操作
建立索引的場景
1.主鍵(Primary key)和唯一鍵(Unique)
2.數據重複率較低的字段可以建立索引,比如電話,郵箱
3.經常查詢的字段可以建立索引
4.需要經常排序的字段可以建立索引
5.聯合字段索引,例如省+市,必須查詢到多個字段的時候纔會起作用
create index index_m on map(province,city);//聯合查詢
注意:
1.表的數據是按照ROWID排序的
2.根據ROWID查詢某條數據,查詢的速度最快
ROWNUM
rownum(僞列): 也就是假的列,不是數據表中原本的列
Oracle可以跨用戶訪問,前提是你必須是DBA角色
select e.* from SCOTT.emp e
案例:查詢員工中工資前三的工資
select rownum, e.* from (
select * from SCOTT.emp order by sal desc) e
注意:
1.rownum支持 <,<=,不支持 >,>=
2.rownum支持 = , 但是隻支持 = 1,因爲指針只能從1開始
3.rownum雖然不支持 > ,但是rownum取得別名可以支持 > ,這個比較難理解,舉個栗子 :查詢員工表中工資6-10的工資(三層分頁查詢)
1.查詢最裏層數據並按照數據排序,生成一個臨時的表
2.第二層按照最裏層的結果集查詢一個rownum,並給它起一個別名,並按照相應需求操作(比如 <= 10)
3.最外層按照第二層的結果查詢你所需要的字段,並且在where子句中對第二層的rownum的別名做 >= 操作
select e2.* from (
select rownum r2,e1.* from (
select e0.* from SCOTT.emp e0 order by sal desc) e1
where rownum <= 10) e2
where r2 >= 6
視圖(View)
創建新視圖:
creat view name
as .....(查詢到的表)
視圖的作用:
1.封裝複雜的sql語句,方便下次調用
2.可以做表的權限劃分
視圖的特點:
1.視圖是一張虛擬的表,但表能做的所有操作,視圖一樣也能操作
2.修改視圖的數據會連帶的影響到原表數據,因此開發中我們會將視圖設爲只讀視圖,防止數據被隨意篡改,只需要在創建視圖語句的末尾加上with read only
create view view_4 as
select * from emp
with read only;//只讀
3.刪除視圖不會影響表的數據,但是刪除表視圖的數據也就不復存在,視圖是基於表而存在的
事務(Transaction)
事務是一個操作序列。這些操作要麼都成功,要麼都失敗,是一個不可分割的工作單位,是數據庫環境中的邏輯工作單位。事務是爲了保證數據庫的完整性
就以取錢爲例子 對應的就是DML中的update語句
1.插卡
2.數錢的數目,按確定(查詢語句)
3.取款 (修改語句)
update account set money = money - 1000//取錢
4.退卡
這個時候如果停電了,但是錢已經被扣除了,這個時候該如何處理呢?
答案就是rollback回滾
當執行sql語句的時候,如果出現異常,表示sql有誤,那麼就讓他
進入到catch語句中對事物進行rollback()。如果沒有出現異常,表示sql語句正常執行,在代碼的最後執行commit() 提交數據即可。
事務的開啓:
執行DML語句時
事務的結束:
1.commit(提交),rollback(回滾)的時候
2.當執行create,drop,alter,grant語句的時候,事務自動提交
3.當正常關閉sql窗口時,事務commit,當異常關閉時,事務rollback
事務的四大特點:
1.atomicity(原子性):事務內的操作是一個整體,要麼都成功,要麼都失敗
2.consistency(一致性):當事務中的一個操作失敗了,所有更改的數據必須回滾到修改前的狀態
3.isolation(隔離性):事務查看數據是,數據所處的狀態,要麼是另一個事務修改數據前的狀態,要麼是修改後的狀態,是無法看到中間狀態的
4.durability(持久性):事務完成後,對於系統的影響是持久性的
事務的隔離級別
髒讀: 當一個事務正在多次修改某個數據,而在這個事務中這多次的修改都還未提交,這時一個併發的事務來訪問該數據,就會造成兩個事務得到的數據不一致。
不可重複讀: 不可重複讀是指在對於數據庫中的某個數據,一個事務範圍內多次查詢卻返回了不同的數據值,這是由於在查詢間隔,被另一個事務修改並提交了。
幻讀: 幻讀是事務非獨立執行時發生的一種現象。例如事務T1對一個表中所有的行的某個數據項做了從“1”修改爲“2”的操作,這時事務T2又對這個表中插入了一行數據項,而這個數據項的數值還是爲“1”並且提交給數據庫。
因此,當某一個時間段,只有一個用戶操作數據庫的某個表時候,不會出現上述問題,效率會降低,但是安全性會提高。