oracle

2020-08-14 19:09:37

Oracle數據庫速查知識文件

專案介紹

該專案記錄了Oracle相關的速查知識彙總,主要涉及了oracle基礎使用、SQL基礎、oracle函數、oracle觸發器、oracle高階查詢、PL/SQL程式設計基礎、PL/SQL儲存過程等。若有新增,還將不斷新增中。

SQL基礎部分

1.簡介

Oracle Database,又名Oracle RDBMS,或簡稱Oracle,是甲骨文公司的一款關係數據庫管理系統。本課程主要介紹Oracle的SQL基礎,包括表空間的概念,如何登錄Oracle數據庫,如何管理表及表中的數據,以及約束的應用。爲後續課程的學習打下一個良好的基礎。

2.安裝好之後可以登錄系統賬戶

開啓sqlplus,輸入使用者名稱system或sys(後者有最高許可權)和自己設定的口令就可以登錄了。

3.使用者與表空間

系統使用者有哪些?

sys,system 前者高於後者,前者必須以管理員許可權登錄
sysman 操作企業管理的使用者,也是管理員使用者

scott 普通使用者

前三者使用者的密碼是安裝時設定的,scott的預設密碼是tiger

登錄通用語句:

[username/password][@server][as sysdba|sysoper]

如果是遠程登錄,則需要輸入IP地址。

也可以在前面加一個connect,比如connect as sysdba;

4.數據字典

(1)數據字典介紹

數據字典是Oracle存放有關數據庫資訊的地方,其用途是用來描述數據的。比如一個表的建立者資訊,建立時間資訊,所屬表空間資訊,使用者存取許可權資訊等。當使用者在對數據庫中的數據進行操作時遇到困難就可以存取數據字典來檢視詳細的資訊。

dba_開頭的是管理員才能 纔能檢視的數據字典,users_開頭的是都能檢視的數據字典。

數據字典或表前加上desc可以檢視他們的結構。

比如desc dba_users檢視數據字典的資訊。

select username from dba_users;

可以從數據字典裏面檢視使用者的名字。

(2)檢視使用者的數據字典dba_users

dba_users、user_users用來檢視不同許可權級別的數據字典。使用範例如:

select default_tablespace,temporary_tablespace from dba_users where username='SYSTEM';

(3)數據字典dba_data_files,檢視數據檔案的

select file_name from dba_data_files where tablespace_name = 'TEST1_TABLESPACE';

得到結果:

FILE_NAME
--------------------------------------------------------------------------------
D:\APP\HP\PRODUCT\11.2.0\DBHOME_1\DATABASE\TEST1FILE.DBF

類似的字典 dba_temp_files(檢視臨時表空間檔案的)

5.如何啓用scott使用者

預設情況下是鎖定的。
啓用語句:

alter user username(可以替換) account unlock;

6.表空間

(1)表空間介紹

表空間就是在數據庫中開闢的一個空間用來儲存我們的數據庫物件,一個數據庫可以由多個表空間構成。

表空間由一個或多個數據檔案構成,大小可以由使用者來定義。

表空間的分類:

  • 永久表空間
  • 臨時表空間
  • UNDO表空間

永久表空間主要儲存數據庫中要永久儲存的物件,表、檢視、儲存過程。臨時表空間儲存數據庫操作當中中間執行的過程,執行結束之後自動釋放掉,不進行永久性儲存。UNDO表空間用於儲存事務所修改數據的舊值,可以做回滾操作。

(2)如何檢視使用者的表空間?

數據字典:dba_tablespaces(針對管理員級別的使用者)、user_tablespaces(針對普通使用者的數據字典)

dba的表空間中,system用於管理員,也叫系統表空間,sysaux爲範例的輔助表空間,undotbs1用於儲存復原資訊的,temp用於儲存處理的表和索引資訊的臨時表空間,users用於儲存使用者建立的數據庫物件,example表空間等。

(3)如何設定使用者的預設或者臨時表空間

alter user username default|temporary tablespace tablespace_name;
alter user system default tablespace system;

(4)建立表空間

create [temporary] tabalspace tablespace_name tempfile|datafile 'xx.dbf' size xx;
create tablespace test1_tablespace datafile 'test1file.dbf' size 10M;
create temporary tablespace temptest1_tablespace tempfile 'tempfile1.dbf' size 10M;

(5)修改表空間的狀態

設定線上離線狀態
alter tablespace tablespace_name online|offline;  --離線狀態不能使用它

dba_tablespaces字典下面 下麪的status狀態可以檢視狀態。

select status from dba_tablespaces where tablespace_name = 'TEST1_TABLESPACE';
設定只讀或可讀寫狀態,一般是read write可讀寫的狀態
alter tablespace tablespace_name read only|read write;  --前提是表空間是一定是線上狀態

(6)增加數據檔案

alter tablespace tablespace_name add datafile 'xx.dbf' size xx;

新增後使用dba_data_files來查詢。

select file_name from dba_data_files where tablespace_name='TEST1_TABLESPACE';

(7)刪除數據檔案

alter tablespace tablespace_name drop datafile 'xx.dbf';  --注意不能刪除建立表空間時候的第一個檔案,如果需要刪除則必須要把表空間刪掉。

(8)刪除表空間

drop tablespace tablespace_name [including contents];  --如果需要把數據檔案也刪除則把後面加上。

7.數據表

(1)表的介紹

表是基本儲存單位,要把數據都存在表中,oracle中的表都是二維結構。
一行也可以叫做記錄,一列也可以叫做域或者欄位。
約定:要求每一列需要有相同的數據型別。
列名要是唯一的。
每一行的數據是唯一的。

(2)表中的數據型別

字元型
  • 固定長度型別:char(n)(max2000),nchar(n)(unicode格式,max1000,多數用來儲存漢字)
  • 可變長度型別:varchar2(n)(max4000),nvarchar2(n)(unicode格式,max2000)
數值型
  • number(p,s) p爲有效數位,s爲小數點後面的位數,s可正可負
  • float(n) 用來儲存二進制數據,二進制數據的1-126位,一般使用number
日期型
  • date 範圍爲公元前4712年1月1日到公元9999年12月31日,可以精確到秒
  • timestamp 可以精確到小數秒,一般用date型別
其他型別
  • blob 可存4G數據以二進制存放
  • clob 可存4G數據以字串存放

(3)如何管理表

建立表:
create table table_name(         --在同一個使用者下表明要是唯一的。
	column_name datatype,...
);

create table userinfo
  (id number(6,0),
  username varchar2(20),
  userpwd varchar2(20),
  email varchar2(30),
  regdate date);

建立完之後如果需要檢視欄位的資訊使用desc userinfo即可檢視。

(4)如何修改表的結構

新增欄位
alter table table_name add column_name datatype;

alter table userinfo add remarks varchar2(500);
更改欄位數據型別
alter table table_name modify column_name datatype;  --改長度或者更換數據型別

alter table userinfo modify remarks varchar2(400);
刪除欄位
alter table table_name drop column column_name;
修改欄位名
alter table table_name rename column column_name to new_column_name;
修改表名
rename table_name to new_table_name;

(5)刪除表

truncate table table_name;  --刪除表中的全部數據,沒有刪除表,比delete快很多。
drop table table_name;   數據和結構都刪掉。

(6)操作表中的數據

新增數據
insert into table_name (column1,column2,...) values (value1,value2,...);  --如果是所有欄位都新增值,則表明後面的小括號可以省略。

insert into userinfo values (1,'xxx','123','[email protected]',sysdate);  --sysdate可以獲取當前系統日期

查詢select * from userinfo;
又如

insert into userinfo (id,username,userpwd) values (2,'yyy','123');

(7)設定某欄位的預設值

建立表時新增

create table userinfo1(id number(6,0),regdate date default sysdate);  --使用default關鍵詞,雖然指定了預設值,但是在新增的時候還是要指定欄位名才行

在建立表以後新增預設值:

alter table userinfo modify email default '無';  --如果在新加記錄的時候不想要預設值了,則按正常的新增方式新增了就可以替換預設值了

(8)複製表數據

在建表時複製
create table table_new as select column1,...|* from table_old;  --可以選擇要複製的欄位也可以複製所有

如:

create table userinfo_new as select * from userinfo;  --userinfo是被複制的表
部分欄位複製如
create table userinfo_new1 as select id,username from userinfo;
在新增時複製
insert into table_new [(column1,...)] select column1,...|* from table_old;  --順序和數據型別要完全一致

insert into userinfo_new select * from userinfo;

又如

insert into userinfo_new (id,username) select id,username from userinfo;

(9)修改表的數據

update tabel_name set column1=value1,...[where conditions];
無條件更新:
update userinfo set userpwd = '111111';
有條件的更新:
update userinfo set userpwd='123456' where username ='xxx';

(10)刪除數據

只能以行爲單位來刪除數據
delete from table_name;   --刪除全部數據,效率慢些
delete from table_name [where conditions];
無條件刪除
delete from testdel;
有條件的刪除
delete from userinfo where username='yyy';

8.約束

(1)約束的介紹

約束的作用是定義規則(最重要),確保完整性。

(2)約束的種類

  • 非空約束
  • 主鍵約束
  • 外來鍵約束
  • 唯一約束
  • 檢查約束

(3)非空約束

在建立表時設定非空約束:
create table table_name(column_name datatype not null,...);

如:

create table userinfo_1 (id number(6,0),
                               username varchar2(20) not null,
                               userpwd varchar2(20) not null);
在修改表時新增非空約束:
alter table tabel_name modify column_name datatype not null;

alter table userinfo modify username varchar2(20) not null;  --在修改之前表裏面不要有任何數據
在修改表時去除非空約束:
alter table tabel_name modify column_name datatype null;

(4)主鍵約束

必不可少,確定每一行數據的唯一性。

一張表只能設計一個主鍵約束。

主鍵約束可以由多個欄位構成,稱爲聯合主鍵或者複合主鍵。

在建立表時設定主鍵約束:
create table table_name(column_name datatype primary key,...);

create table userinfo_p(id number(6,0) primary key,
       username varchar2(20),
       userpwd varchar2(20));

如果用約束的話:

constraint constraint_name primary key (column_name1,...);  --一般用來建立聯合主鍵

create table userinfo_p1(id number(6,0),
       username varchar2(20),
       userpwd varchar2(20),
       constraint pk_id_username primary key(id,username));

如果忘記了約束的名字,可以到user_constraints數據字典查詢constraint_name.

select constraint_name from user_constraints where table_name='USERINFO_P1';

如果沒有用約束來建立主鍵,則系統會自動命名約束的名稱,可以看這個:

select constraint_name from user_constraints where table_name='USERINFO_P';

結果爲:

CONSTRAINT_NAME
------------------------------
SYS_C0011189
在修改表時新增主鍵約束:
add constraint constraint_name primary key(column_name1,...);   --主鍵名一般以pk_開頭
alter table userinfo add constraint pk_id primary key(id);   --設定約束之前,如果已經有值了,必須唯一,且不能爲空。
更改約束的名稱,可以修改任何約束的名字
alter table table_name rename constraint old_name to new_name;
刪除主鍵約束:
alter table table_name disable|enable constraint constraint_name;   --禁用|啓用約束,不刪除

檢視狀態:

select constraint_name,status from user_constraints where table_name='USERINFO';
如果是完全刪除:
alter table table_name drop constraint constraint_name;
還有一種方法:
drop primary key[cascade];   --刪除主鍵約束,如果存在外來鍵約束,填寫cascade,可以把其他表中參照該主鍵約束的一起刪掉

(5)外來鍵約束

兩個表之中欄位關係的約束。

在建立表的時候設定外來鍵約束:
--分開建立時
create table table1(column_name datatype references table2(column_name),...);
--table2爲主表,table1爲從表,也叫主從表。主表當中的欄位必須是主表中的主鍵欄位,主從表的欄位要設定成同一個數據型別。在向設定了外來鍵約束的表輸入值的時候,從表中外來鍵欄位的值必須來自主表中的相應欄位的值,或者爲null值。
如建立主表:
create table typeinfo(typeid varchar2(10) primary key,
       typename varchar2(20));
建立從表:
create table userinfo_f(id varchar2(10) primary key,
       username varchar2(20),
       typeid_new varchar2(10) references typeinfo(typeid));
然後給主表插入數據:
insert into typeinfo values(1,1);
如果這樣給從表插入數據:
insert into userinfo_f(id,typeid_new) values (1,2);

則2在主表中沒有找到,會報錯。需要填寫

insert into userinfo_f(id,typeid_new) values (1,1);

纔可以,或者那個部分留空值:

insert into userinfo_f(id,typeid_new) values (2,null);
在建立表的時候設定外來鍵約束:
--定義完所有的欄位之後設定的約束
constraint constraint_name foreign key(column_name) references table_name(column_name) [on delete cascade];   
--後面的中括號是級聯刪除,表示主表當中的一條數據被刪除的時候,從表當中使用了這條數據的欄位所在的行也會被一起刪除掉,這樣確保了主從表數據的完整性。

如:

create table userinfo_f2 (id varchar2(10) primary key,
       username varchar2(20),
       typeid_new varchar2(10),
       constraint fk_typeid_new foreign key (typeid_new) references typeinfo(typeid));
如果新增級聯刪除:
create table userinfo_f3 (id varchar2(10) primary key,
       username varchar2(20),
       typeid_new varchar2(10),
       constraint fk_typeid_new1 foreign key (typeid_new) references typeinfo(typeid) on delete cascade);
在修改表時新增外來鍵約束:
alter table tabel_name add constraint constraint_name foreign key(column_name) references table_name(column_name) [on dedelete cascade];
刪除外來鍵約束
禁用外來鍵約束:
disable|enable constraint constraint_name;
徹底刪除外來鍵約束:
drop constraint constraint_name;

(6)唯一約束

作用是保證欄位的唯一性,和主鍵約束的區別是,主鍵約束必須是非空的,而唯一約束允許有一個空值。主鍵約束在一張表中只能有一個,唯一約束可以有多個。

在建立表時設定唯一約束:
create table tabel_name(column_name datatype unique,...);
在表級設定唯一約束:
constraint constraint_name unique(column_name);   --如果需要設定多個欄位爲唯一約束,要寫多個constraint子句。
在修改表時新增唯一約束:
add constraint constraint_name unique(column_name);
刪除唯一約束:

禁用:

disable|enable constraint constraint_name;

完全刪除:

drop constraint constraint_name;

(7)檢查約束

檢查約束,讓表當中的值更具有實際意義,能夠滿足一定的條件,具有實際意義。

在建立表時設定檢查約束:
create table tabel_name(column_name datatype check(expression),...);

如:

create table userinfo_c (id varchar2(10) primary key,
       username varchar2(20),
       salary number(5,0) check(salary>0));

比如輸入insert into userinfo_c values(1,'aaa',-50);就會報錯。

在表級設定檢查約束:
constraint constraint_name check(expression);

如:

create table userinfo_c1(id varchar2(10) primary key,
       username varchar2(20),
       salary number(5,0),
       constraint ck_salary check(salary>0));
在修改表時新增檢查約束:
add constraint constraint_name check(expression);
刪除檢查約束:

禁用:

disable|enable constraint constraint_name;

刪除:

drop constraint constraint_name;

(8)總結五個約束

  • 非空約束
  • 主鍵約束:每張表只能有一個,可以由多個欄位構成
  • 外來鍵約束:涉及兩個表之間的關係
  • 唯一約束
  • 檢查約束

在建立表時設定約束:
只有非空約束只能在列級設定約束,不能在表級設定約束,其他的都是兩者都可以的。非空約束是沒有名字的。

在修改表時新增約束,也是隻有非空約束不同,修改表時用的語句是

alter table talbe_name modify column_name datatype not null;

更改約束的名稱:數據字典(user_constraints檢視名稱)

rename constraint old_name to new_name;

刪除約束,非空約束較特殊

alter table tabel_name modify column_name datatype null;

其他的如果是禁用的話使用

disable|enable constraint constraint_name;

如果要永久刪除可以用

drop constraint constraint_name;

刪除主鍵約束還能用

drop primary key;

9.基本查詢

(1)查詢基本語句

select [distinct] column_name1,...|* from table_name [where conditions];  --distinct可以不顯示重複的行。

(2)在SQL*PLUS中設定格式

column column_name heading new_name;  

col username heading 使用者名稱;   --執行成功的話不會有回顯
--column可以簡寫成col,設定新的欄位名(別名),使用select語句來查詢的時候就可以看到變化了,但使用desc看結構還依然不變化。

設定結果顯示的格式:

column column_name format dataformat;

注意:字元型別只能設定它的長度。 --字元格式用a開頭,後面跟它要的長度。

col username format a10;

如果是數值型別用,9表示一位數位,比如

col salary format 9999.9;

可以保留4位元數和一位小數。
如果

col salary format 999.9;

但如果數據中有四位的數,超過這個長度的就用#####表示了,與excel一致。

如果使用col salary format $9999.9;則數位前面加了美元符號。

清除之前設定過的格式:

column column_name clear;

col salary clear;

(3)查詢表中的所有欄位

select * from table_name;

查詢指定的欄位:比如

select username,salary from users;

(4)給欄位設定別名

不會更改欄位的名字,可以爲多個欄位設定別名

select column_name as new_name,... from table_name;  --其中as可以省略,但最好加上

select id as 編號, username as 使用者名稱, salary 工資 from users;

檢視唯一值:

select distinct username as 使用者名稱 from users;

(5)運算子和表達式

運算子大家都比較熟悉了,而表達式=運算元+運算子組成。

oracle中的運算元可以有變數、常數、欄位。

運算子有算術運算子(+、-、*、/),比較運算子(>,>=,<,<=,=,<>都是用在where條件裏面的,兩個數進行比較得到的結果是布爾型別的,真或者假),邏輯運算子(and,or,not)

在select語句中使用運算子

在查詢結果中,給每個員工的工資加上200元,但數據本身沒變。

select id,username,salary+200 from users;

使用比較運算子:

查詢工資高於800元的員工的姓名;

select username from users where salary > 800;

使用邏輯運算子:

select username from users where salary > 800 and salary <>1800.5;
select username from users where salary > 800 or salary <>1800.5;

(6)帶條件的查詢

select salary from users where username='aaa';
select username,salary from users where id=3;

多條件如

select * from users where username='aaa' or salary<=2000 and salary>800;

邏輯運算子的優先順序順序:not,and,or

比較運算子優先順序高於邏輯運算子

not的例子:

select * from users where not(username='aaa');

(7)模糊查詢

like關鍵字,也可以歸入比較運算子當中。

萬用字元的使用(_表示一個字元,%表示0到多個任意字元)

select * from users where username like 'a%';  --以a開頭的行
select username from users where username like '%a%';   --含有a的

(8)範圍查詢

between…and --表示從什麼到什麼之間。查詢結果是含頭又含尾的區間。

如果不在這個之間的,在它們前面加上not

select * from users where salary not between 800 and 2000;

in/not in 後面跟着小括號,裏面是一個列表的值,一個具體的值。

select * from users where username in ('aaa','bbb');
select * from users where username not in ('aaa','bbb');

(9)對查詢結果排序

select...from...[where...] order by column1 desc/asc,...  --desc爲降序排列,asc升序

(10)case…when語句

case column_name when value1 then result1,...[else result] end;

select username,case username when 'aaa' then '計算機部門'
    when 'bbb' then '市場部門' else '其他部門' end as 部門
    from users;

另一種形式:

case when column_name=value1 then result1,...[else result] end;

select username,case when username='aaa' then '計算機部門'
    when username='bbb' then '市場部門' else '其他部門' end as 部門
    from users;

select username,case when salary<800 then '工資低' when salary>5000 then '工資高' end as 工資水平 from users;

(11)decode函數的使用

decode(column_name,value1,result1,...,defaultvalue)

select username,decode(username,'aaa','計算機部門','bbb','市場部門','其他') as 部門 from users;

10.其他一些實用命令

  • 可以使用host cls來清屏。
  • 檢視使用者show user。
  • 使用上下箭頭可以選擇歷史輸入記錄來使用。

=====================================================================================

Oracle函數部分

1.函數的作用

  • 方便數據的統計
  • 處理查詢結果

2.函數的分類

  • 數值函數
  • 字元函數
  • 日期函數
  • 轉換函數

3.數值函數

四捨五入

round(n[,m])
  • 省略m:0
  • m>0:小數點後m位
  • m<0:小數點前m位

select round(23.4),round(23.45,1),round(23.45,-1)from dual;

取整函數

ceil(n)  --取最大值
floor(n) --取最小值
select ceil(23.45),floor(23.45) from dual;

結果:

CEIL(23.45) FLOOR(23.45)
----------- ------------
         24           23

常用計算

abs(n)   --取絕對值

select abs(23.45),abs(-23),abs(0) from dual;

=====

mod(m,n)  --取餘數

select mod(5,2) from dual;

=====

power(m,n)  --取m的n次冪

select power(2,3),power(null,2) from dual;

=====

sqrt(n)   --求平方根

select sqrt(16) from dual;

=====

三角函數

sin(n),asin(n)
cos(n),acos(n)
tan(n),atan(n)   --提供弧度參數

select sin(3.124) from dual;

4.字元函數

大小寫轉換函數

upper(char)   --轉換爲大寫
lower(char)   --轉換爲小寫
initcap(char)  --首字母大寫

select upper('abde'),lower('ADe'),initcap('asd') from dual;

獲取子字元

substr(char,[m[,n]])   --獲取子字元,分別是從哪取,從哪個位置開始取以及取出多少位,n省略時,從m的位置擷取到結束,m從1開始如果m寫0也是從第一個字元開始。如果m爲負數時,從字串的尾部開始擷取

select substr('abcde',2,3),substr('abcde',2),substr('abcde',-2,1) from dual;

獲取字串長度函數

length(char) --會包含空格的長度

select length('acd ') from dual;

字串連線函數

concat(char1,char2)   --與||作用一樣

select concat('ab','cd') from dual;

去除子串函數

trim(c2 from c1)   --代表從c1中去除c2字串,就是子文字替換,要求c2中只能是一個字元

select trim ('a' from 'abcde') from dual;

=====

ltrim(c1[,c2])    --從c1中去除c2,從左邊開始去除,要求第一個就是要去除的字元,有多少個重複的該字元就會去除多少次

select ltrim('ababaa','a') from dual;

=====

rtrim(c1[,c2])    --從c1中去除c2,要求右側第一個就是要去除的字元,有多少個重複的該字元就會去除多少次

=====

trim(c1)   --代表去除首尾的空格,刪首尾空,同理ltrim和rtrim只有一個參數時。

=====

replace(char,s_string[,r_string])  --替換函數,省略第三個參數則用空白替換

select replace('abcde','a','A') from dual;
select replace('abcde','c') from dual;
select replace('abced','ab','A') from dual;

5.日期函數

系統時間

sysdate 預設格式:DD-MON-RR 天-月-年

日期操作

add_months(date,i)  --用於新增指定的月份,返回在指定的日期上新增的月份,i可以是任意整數,如果i是負數,則是在原有的值上減去該月份了

select add_months(sysdate,3),add_months(sysdate,-3) from dual;

=====

next_day(date,char)  --第二個參數指定星期幾,在中文環境下輸入星期X即可,返回下一個周幾是哪一天。

select next_day(sysdate,'星期一') from dual;

=====

last_day(date)   --用於返回日期所在月的最後一天

select last_day(sysdate) from dual;

=====

month_between(date1,date2)  --計算兩個日期之間間隔的月份,前者減後者

select months_between('20-5月-15','10-1月-15') from dual;

=====

extract(date from datetime)   --返回相應的日期部分

select extract(year from sysdate) from dual;   --可以改month或者day
select extract(hour from timestamp '2015-10-1 17:25:13') from dual;

=====

用於擷取日期時間的trunc函數

用法:trunc(欄位名,精度)

具體範例:

在表table1中,有一個欄位名爲sysdate,該行id=123,日期顯示:2016/10/28 15:11:58

1、擷取時間到年時,sql語句如下:

select trunc(sysdate,'yyyy') from table1 where id=123;  --yyyy也可用year替換

顯示:2016/1/1

2、擷取時間到月時,sql語句:

select trunc(sysdate,'mm') from table1 where id=123;

顯示:2016/10/1

3、擷取時間到日時,sql語句:

select trunc(sysdate,'dd') from table1 where id=123;

顯示:2016/10/28

4、擷取時間到小時時,sql語句:

select trunc(sysdate,'hh') from table1 where id=123;

顯示:2016/10/28 15:00:00

5、擷取時間到分鐘時,sql語句:

select trunc(sysdate,'mi') from table1 where id=123;

顯示:2016/10/28 15:11:00

6、擷取時間到秒暫時不知道怎麼操作

7、不可直接用trunc(sysdate,‘yyyy-mm-dd’),會提示「精度說明符過多」

8.如果不填寫第二個參數,則預設到DD,包含年月日,不包含時分秒。

6.轉換函數

to_char(date[,fmt[,params]])  --date爲需要轉換的日期,fmt爲轉換的格式,params爲轉換的語言(通常預設會自動選擇,可以省略,與安裝語言一致)

預設格式:DD-MON-RR

可以定義的格式:

  • YY YYYY YEAR
  • MM MONTH
  • DD DAY
  • HH24 HH12
  • MI SS
select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual;

=====

to_date(char[,fmt[,params]])

select to_date('2015-05-22','yyyy-mm-dd') from dual;   --注意顯示的時候仍然按照時間的預設格式來顯示

=====

to_char(number[,fmt])

fmt列表:

  • 9:顯示數位並忽略前面的0
  • 0:顯示數位,位數不足,用0補齊
  • .或D:顯示小數點
  • ,或G:顯示千分位
  • $:美元符號
  • S:加正負號(前後都可以)
select to_char(12345.678,'$99,999.999') from dual;
select to_char(12345.678,'s99,999.999') from dual;

=====

to_number(char[,fmt])

fmt是轉換的格式,可以省略

select to_number('$1,000','$9999') from dual;

7.一些課堂案例

在查詢中使用函數

  • 在員工資訊表中查詢員工的生日
substr(char[,m[,n]])
  • 將員工資訊表中的年齡欄位與10取餘數
  • 取員工入職的年份
  • 查詢出5月份入職的員工資訊

=====================================================================================

Oracle高階查詢部分

1.簡介

本部分需要有如下兩個部分的基礎

  • 《oracle數據庫開發必備利器之SQL基礎》
  • 《oracle數據庫開發利器之函數》

2.分組查詢

(1)什麼是分組函數

分組函數作用於一組數據,並對一組數據返回一個值。
結構:

select [column,] group function(column),...
from table
[where condition]
[group by column]
[order by column];

(2)常見的分組函數

avg 求平均值 和 sum 求和
  • 求出員工的平均工資和工資的總和
  • 求出員工工資的最大值和最小值
  • 求出員工的總人數
  • distinct關鍵字求出部門數
select count(distinct deptno) from emp;
min 最小值
max 最大值
count 求個數
wm_concat 行轉列

select deptno 部門號,wm_concat(ename) 部門中員工的姓名 from emp group by deptno;

(3)分組函數與空值

  • 舉例1:統計員工的平均工資
select sum(sal)/count(*) 一,sum(sal)/count(sal) 二,avg(sal) 三 from emp;

結果一樣

  • 舉例二:統計員工的平均獎金
select sum(comm)/count(*) 一,sum(comm)/count(comm) 二,avg(comm) 三 from emp;

二和三結果一樣,一不一樣,因爲在獎金列裏面含有空值,count的時候數數不一樣

所以分組函數會自動忽略空值,可以在分組函數中使用nvl函數來使分組函數無法忽略空值

select count(*),count(nvl(comm,0)) from emp;

(4)分組數據

group by 子句

  • 求出員工表中各個部門的平均工資
    注意:在select列表中所有未包含在組函數(就是彙總計算xxx的列)中的列都應該包含在group by子句中,但包含在group by子句中的列不必包含在select列表中
select avg(sal) from emp group by deptno;

使用多個列分組

select deptno,job,sum(sal) from emp group by deptno,job order by deptno;

(5)非法使用組函數

要求所用包含於select列表中,而未包含於組函數中的列都必須包含於group by子句中。

select deptno,count(ename)
from emp;

這裏的deptno沒有包含在group by子句中,所以會報錯。

(6)過濾分組

  • 求平均工資大於2000的部門,having子句的使用
    在group by後加[having group_condition]
select deptno,avg(sal) from emp group by deptno having avg(sal) > 2000;

注意不能在where子句中使用組函數(注意)。

可以在having子句中使用組函數。

如果在能使用where的場景下,從SQL優化的角度來看,儘量使用where效率更高,因爲having是在分組的基礎上過濾分組的結果,而where是先過濾,再分組。要處理的記錄數不同。所以where能使分組記錄數大大降低,從而提高效率。

(7)在分組查詢中使用order by子句

  • 範例:求每個部門的平均工資,要求顯示:部門號,部門的平均工資,並且按照工資升序排列
    可以按照:列、別名、表達式、序號進行排序
select deptno,avg(sal) from emp group by deptno order by avg(sal);
select deptno,avg(sal) 平均工資 from emp group by deptno order by 2;  --也可以填寫序號

(8)分組函數的巢狀

  • 範例:求部門平均工資的最大值
select max(avg(sal)) from emp group by deptno;

(9)group by語句的增強

  • 按部門、不同的職位顯示工資的總額;同時按部門,統計工資總額;統計所有員工的工資總額。
select deptno,job,sum(sal) from emp group by rollup(deptno,job);

結果:

DEPTNO JOB         SUM(SAL)
------ --------- ----------
    10 CLERK           4541
    10 MANAGER         6455
    10 PRESIDENT       9711
    10                20707
    20 CLERK           8235
    20 ANALYST        12360
    20 MANAGER       7032.5
    20              27627.5
    30 CLERK         4117.5
    30 MANAGER         6895
    30 SALESMAN       18648
    30              29660.5
                      77995

rollup就可以實現上述的效果。小計、總計的效果,可以用在報表裏面。

再次優化,先執行:

break on deptno skip 2

再執行上面的程式碼即可。

(10)sqlplus的報表功能

ttitle col 15 '我的報表' col 35 sql.pno    --15表示空15列,sql.pno表示報表頁碼
col deptno heading 部門號   --設定別名
col job heading 職位
col sum(sal) heading 工資總額
break on deptno skip 1		--deptno只顯示一次,部門間間隔一行

結果:

              我的報表                     1
    部門號 職位        工資總額
---------- --------- ----------
        10 CLERK           4541
           MANAGER         6455
           PRESIDENT       9711
                          20707

        20 CLERK           8235
           ANALYST        12360
           MANAGER       7032.5
                        27627.5


              我的報表                     2
    部門號 職位        工資總額
---------- --------- ----------
        30 CLERK         4117.5
           MANAGER         6895
           SALESMAN       18648
                        29660.5

                          77995

3.多表查詢

(1)簡介

按數據庫設計原則,員工表中只有部門的編號資訊,部門的詳細資訊會存放在部門表中。

什麼是多表查詢:就是從多個表中獲取數據。

前提是有一個外來鍵約束來表示員工是哪個部門的,有個一個部門號來聯結。

(2)笛卡爾集

有了它纔有多表查詢的存在。笛卡爾集的列數等於每張表列數的相加,行數等於每張表的行數相乘。比如emp*dept有六列六行。裏面的每一條記錄不一定都是對的。多表查詢就是要從笛卡爾集中選擇出正確的記錄。需要一個連線條件,比如部門號相等。有了連線條件,就能避免使用笛卡爾全集。在實際執行環境下,應提供where連線條件,避免使用笛卡爾全集。連線條件至少有要連線表數-1個。

建立笛卡爾集可以使用全連線:
FULL JOIN

(3)連線的型別

  • 等值連線
  • 不等值連線
  • 外連線
  • 自連線

(4)等值連線

select e.empno,e.ename,e.sal,d.dname from emp e,dept d where e.deptno=d.deptno;

(5)不等值連線

SELECT e.empno,e.ename,e.sal,s.grade FROM emp e,salgrade s WHERE e.sal BETWEEN s.losal AND s.hisal;

(6)外連線

SELECT d.deptno 部門號,d.dname 部門名稱,COUNT(e.empno) 人數 FROM emp e,dept d WHERE e.deptno=d.deptno GROUP BY d.deptno,d.dname;   --漏了一個部門

核心:通過外連線,把對於連線條件不成立的記錄,仍然包含在最後的結果中。

左外連線(LEFT [OUTER] JOIN):當連線條件不成立的時候,等號左邊的表仍然被包含

右外連線(RIGHT [OUTER] JOIN):當連線條件不成立的時候,等號右邊的表仍然被包含

因此上述表達式改爲:

改爲右外連線 方法是在相反的方向的等值連線結尾加上(+),比如右外連線就是加在左邊的最後。

SELECT d.deptno 部門號,d.dname 部門名稱,COUNT(e.empno) 人數 FROM emp e,dept d WHERE e.deptno(+)=d.deptno GROUP BY d.deptno,d.dname;

或者寫成:

SELECT d.deptno 部門號,d.dname 部門名稱,COUNT(e.empno) 人數 FROM emp e,dept d WHERE e.deptno right join d.deptno GROUP BY d.deptno,d.dname;

得到結果:

部門號 部門名稱               人數
------ -------------- ----------
    10 ACCOUNTING              3
    40 OPERATIONS              0
    20 RESEARCH                5
    30 SALES                   6

(7)自連線

  • 作用:通過別名,將同一張表視爲多張表(核心) INNER JOIN

SELECT e.ename 員工姓名,b.ename 老闆姓名 FROM emp e,emp b WHERE e.mgr=b.empno;
自連線存在的問題

儘管是查詢一張表,但本質上仍然是多表查詢,會產生笛卡爾集。

可以通過這個看笛卡爾集有多少條記錄select count(*) from emp e,emp b;表越多,次方越多。比如員工表中有一億條記錄,如果看成三張表,就有一億的立方的笛卡爾集,所以自連線不適合查詢大表。

  • 所以要使用解決方法: 層次查詢 (單表查詢,只有在一張表時纔不會查詢笛卡爾集,在某些情況下可以取代自連線)。

  • 層次查詢的原理:可以把前面的結果變成分level的一棵樹。這棵樹的根是沒有上司的king,也就是mgr就是NULL。
    如:

SELECT level,empno,ename,sal,mgr FROM emp CONNECT BY PRIOR empno=mgr START WITH mgr IS NULL ORDER BY 1;
  • 自連線的優點:結果直觀。缺點:不適合操作大表。

  • 層次查詢的優點:適合單表查詢,不會產生笛卡爾集。缺點:並沒有自連線那麼直觀。

4.子查詢

(1)子查詢介紹

爲什麼要學習子查詢:子查詢可以解決不能一步求解的問題

  • 範例:查詢工資比scott高的員工資訊

子查詢的語法:其實也就是select語句的巢狀

select select_list
from table
where expr operator
	(select select_list
	from table);

select * from emp where sal > (select sal from emp where ename='SCOTT');

(2)子查詢注意的十個問題

  • 子查詢語法中的小括號

語法中一定要有小括號,不然是錯的。

  • 子查詢的書寫風格

該換行的換行,該縮排的索引,可以便於閱讀。

  • 可以使用子查詢的位置:where,select,having,from

select後面使用,要求一定要只返回一條記錄,要是單行子查詢才行,多行子查詢不行。

SELECT empno,ename,sal,(SELECT job FROM emp WHERE empno=7839) 第四列
FROM emp;

在having後面使用:

SELECT deptno,AVG(sal)
FROM emp
GROUP BY deptno
HAVING AVG(sal) > (SELECT MAX(sal)
                  FROM emp
		WHERE deptno=30);

在from後面放置:

非常的重要,很多問題都是在from後面方式子查詢來解決的

SELECT * from(SELECT empno,ename,sal FROM emp);
  • 不可以使用子查詢的位置:group by

SELECT AVG(sal)
FROM emp
GROUP BY (SELECT deptno FROM emp);   --會報錯,這裏不允許出現子查詢表達式
  • 強調:from後面的子查詢,比較特殊,比較重要

SELECT *
FROM (SELECT empno,ename,sal,sal*12 annsal FROM emp);
  • 主查詢和子查詢可以不是同一張表

SELECT * FROM emp WHERE deptno=
                  (SELECT deptno
		FROM dept
		WHERE dname='SALES');

多表查詢程式碼:

SELECT e.*							
FROM emp e,dept d
WHERE e.deptno=d.deptno AND d.dname='SALES';

哪種查詢方式好呢?從理論上來講,儘量使用多表查詢比較好,因爲子查詢需要對數據庫存取兩次,而多表查詢只需要對數據庫存取一次。但實際情況下有可能不一樣,因爲多表查詢的笛卡爾集可能很大所以慢了。

  • 一般不在子查詢中,使用排序;但在Top-N分析問題中,必須對子查詢排序

比如找到員工表中工資最高的前三名。

rownum行號,是一個僞列,表上沒有這一列,當做一些特殊操作的時候,oracle自動加上。行號需要注意的問題:行號永遠按照預設的順序生成;行號只能使用<,<=,不能使用>或者>=這樣的符號。

SELECT ROWNUM,empno,ename,sal
FROM (SELECT * FROM emp ORDER BY sal DESC)
WHERE ROWNUM<=3;
  • 一般先執行子查詢,再執行主查詢;但相關子查詢例外

相關子查詢的表必須設定一個別名,然後把主查詢的內容傳入到子查詢中進行查詢。

SELECT empno,ename,sal,(SELECT AVG(sal) FROM emp WHERE deptno=e.deptno) avgsal
FROM emp e
WHERE sal > (SELECT AVG(sal) FROM emp WHERE deptno=e.deptno);

這裏就把主查詢e表中的部門號傳入子查詢中進行查詢了。

  • 單行子查詢只能使用單行操作符;多行子查詢只能使用多行操作符
單行操作符:=、>、>=、<、<=、<>

SELECT * FROM emp
WHERE job = (SELECT job FROM emp WHERE empno=7566)
AND sal > (SELECT sal FROM emp WHERE empno=7782);

又如

SELECT * FROM emp
WHERE sal = (SELECT MIN(sal) FROM emp);

SELECT deptno,MIN(sal)
FROM emp
GROUP BY deptno
HAVING MIN(sal) > (SELECT MIN(sal)
                  FROM emp
		WHERE deptno=20);

非法使用單行子查詢:

select empno,ename from emp where sal=(select min(sal)
		from emp
		group by deptno);    --因爲子查詢返回了不止一行,所以是非法使用單行子查詢。
多行操作符:in(等於列表中的任意一個)、any(和子查詢返回的任意一個值比較)、all(和子查詢返回的所有值比較)

in:

SELECT * FROM emp 
WHERE deptno IN (SELECT deptno FROM dept WHERE dname='SALES' OR dname='ACCOUNTING');

又如

SELECT e.* FROM emp e,dept d
WHERE e.deptno=d.deptno AND (d.dname='SALES' OR d.dname='ACCOUNTING');

any:

SELECT * FROM emp
WHERE sal > ANY(SELECT sal FROM emp WHERE deptno=30);

等價於

SELECT * FROM emp
WHERE sal > (SELECT min(sal) FROM emp WHERE deptno=30);

all:

SELECT * FROM emp
WHERE sal > ALL(SELECT sal FROM emp WHERE deptno=30);

等價於:

SELECT * FROM emp
WHERE sal > (SELECT MAX(sal) FROM emp WHERE deptno=30);
  • 注意:子查詢中是null值的問題

單行子查詢中返回空值,要使用in之類的關鍵字,等於號的話永遠爲空。

多行子查詢中,如查詢不是老闆的員工
如:

SELECT * FROM emp
WHERE empno NOT IN (SELECT mgr FROM emp);   --會不返回結果,因爲當子查詢中包含空值的時候,不能使用not in,因爲not in等同於不等於所有(永遠爲假)。

所以修改爲:

SELECT * FROM emp
WHERE empno NOT IN (SELECT mgr FROM emp
               WHERE mgr IS NOT NULL);

5.綜合範例

(1)案例一

  • 分頁查詢顯示員工資訊:顯示員工號,姓名,月薪
  • 每頁顯示四條記錄
  • 顯示第二頁的員工
  • 按照月薪降序排列
  • 注意:rownum只能使用<,<=不能使用>,>=,因爲oracle數據庫是一個行式數據庫,取了第一行才能 纔能取第二行,所以行號永遠從1開始,所以比如rownum>=5這樣的條件永遠爲假。

所以分頁查詢:

SELECT r,empno,ename,sal
FROM(SELECT ROWNUM r,empno,ename,sal
from(SELECT ROWNUM,empno,ename,sal FROM emp ORDER BY sal DESC) e1
WHERE ROWNUM<=8) e2
WHERE r>=5;

(2)案例二

  • 找到員工表中薪水大於本部門平均薪水的員工

SELECT e.empno,e.ename,e.sal,d.avgsal
FROM emp e,(SELECT deptno,AVG(sal) avgsal FROM emp GROUP BY deptno) d
WHERE e.deptno=d.deptno AND e.sal>d.avgsal;   --多表查詢

如果需要查詢執行計劃看效能的話,則在語句前面加上EXPLAIN PLAN FOR

執行一遍之後,執行select * from table(dbms_xplan.display);即可檢視效能分析,看消耗的CPU的多少來判定效能的優劣。

(3)案例三

  • 按部門統計員工人數,按照規定格式輸入,已知員工的入職年份在80,81,82,87年之中。
SELECT COUNT(*) Total,
       SUM(DECODE(to_char(hiredate,'yyyy'),'1980',1,0)) "1980",
       SUM(DECODE(to_char(hiredate,'yyyy'),'1981',1,0)) "1981",
	SUM(DECODE(to_char(hiredate,'yyyy'),'1982',1,0)) "1982",
	SUM(DECODE(to_char(hiredate,'yyyy'),'1987',1,0)) "1987"
FROM emp;

使用子查詢方法:

SELECT
(SELECT COUNT(*) FROM emp) Total,
(SELECT COUNT(*) FROM emp WHERE to_char(hiredate,'yyyy')='1980') "1980",
(SELECT COUNT(*) FROM emp WHERE to_char(hiredate,'yyyy')='1981') "1981",
(SELECT COUNT(*) FROM emp WHERE to_char(hiredate,'yyyy')='1982') "1982",
(SELECT COUNT(*) FROM emp WHERE to_char(hiredate,'yyyy')='1987') "1987"
FROM dual;

(4)練習

新建兩個表,然後按要求查到相關的內容

第一個表:

CI_ID                STU_IDS
-------------------- --------------------------------------------------------------------------------
1                    1,2,3,4
2                    1,4

表結構:

Name    Type          Nullable Default Comments 
------- ------------- -------- ------- -------- 
CI_ID   VARCHAR2(20)                            
STU_IDS VARCHAR2(100) Y  

第二個表:

STU_ID               STU_NAME
-------------------- --------------------
1                    張三
2                    李四
3                    王五
4                    趙六

表結構:

Name     Type         Nullable Default Comments 
-------- ------------ -------- ------- -------- 
STU_ID   VARCHAR2(20)                           
STU_NAME VARCHAR2(20) Y  

提示:

1.需要進行兩個表的連線查詢,爲兩個表都取別名

2.使用instr(a,b)函數,該函數的含義爲:如果字串b在字串a的裏面,則返回的是b在a中的位置,及返回值大於0

3.需要用到分組查詢

4.使用wm_concat(cols)函數對學生姓名用逗號進行拼接

--結果查詢語句
SELECT ci_id,wm_concat(stu_name) stu_name 
FROM pm_stu,pm_ci 
WHERE INSTR(stu_ids,stu_id)>0 
GROUP BY ci_id;

得到正確結果:

CI_ID                STU_NAME
-------------------- --------------------------------------------------------------------------------
1                    張三,趙六,王五,李四
2                    張三,趙六

同時學會了一個,如果在oracle中,需要實現如果表已經存在則先刪除表的操作,寫法爲:

--如果已經存在表則先刪除表
DECLARE
  k NUMBER;
BEGIN
	select count(*) INTO k from all_tables where table_name='PM_CI';
	IF k=1 THEN
		execute IMMEDIATE 'DROP TABLE pm_ci';
	END IF;
END;
/

其中查詢的表名和drop的表名變成你要檢測的表名即可。

=====================================================================================

PL/SQL程式設計基礎部分

1.爲什麼要學PL/SQL程式設計

使用PLSQL語言操作Oracle數據庫的效率最高。

之前用sql語句是命令式的語言,但如果案例是複雜的,比如需要分條件來做不同的事情的,就需要PL/SQL效率會更高,不需要用其他的程式語言。

  • PL/SQL介紹

全稱是Procedure Language/SQL,是oracle對sql語言的過程化擴充套件

指在SQL命令語言中增加了過程處理語句(如分支、回圈等),使SQL語言具有過程處理能力。

(1)是sql的擴充套件,支援sql語句。

(2)是程序導向的語言。

2.語句塊通用格式

declare
    --說明部分(變數說明、遊標申明、例外說明)
begin
    --程式體(DML語句)
    dbms_output.put_line('Hello World');
exception
    --例外處理語句
end;
/
/    --這個正斜槓用來退出前面的程式碼編寫並且執行語句
--檢視程式包的結構
desc 程式包名字

3.開啓輸出開關

set serveroutput on

4.不同數據庫中SQL擴充套件

  • Oracle:PL/SQL
  • DB2:SQL/PL
  • SQL Server:Transac-SQL(T-SQL)

5. PL/SQL的說明部分

  • 定義基本變數
    型別:char,varchar2,date,number,boolean,long

舉例:名字在片面,變數是在後面,:=爲賦值符號不是單=號

var1      char(15);
married   bollean := true;
psal      number(7,2);  --說明有兩位小數
  • 定義參照型變數
my_name emp.ename%type;  --參照ename的型別,ename是啥型別變數就是啥型別

第二種賦值方式:

select ename,sal into pename,psal from emp where empno=7839;

這裏的into就可以賦值,是一一對應的。

  • 定義記錄型變數
emp_rec emp%rowtype;   
--取表中一行的型別,作爲變數的型別,可以理解爲陣列,如果需要取用到列裏面的某一行,就像如下寫法:
emp_rec.ename := 'ADAMS';   --ename是列的名字。

6. PL/SQL的流程控制語句

(1)if語句:

情況一

if 條件 then 語句1;
語句2;
end if;

情況二

if 條件 then 語句序列1;
else 語句序列2;
end if;

情況三

if 條件 then 語句;
elsif 語句 then 語句;    --特別注意下elsif
else 語句;
end if;

(2)while回圈:

while total <= 25000 loop
...
total := total + salary;
end loop;

(3)loop回圈:

--在控制遊標的時候比較簡單
loop
exit[when 條件];
......
end loop;

(4)for回圈:

for i in 1..3 loop   --表示連續區間用這種寫法
語句序列;
end loop;

7.遊標

(1)遊標的引入背景

select如果返回的結果有多行的話就會出錯,所以需要引入遊標,遊標cursor就是一個結果集。也叫遊標。

(2)遊標的語法

cursor 遊標名 [(參數名 數據型別[,參數名 數據型別]...)] is select 語句;

cursor c1 is select ename from emp;

此外,遊標是可以帶參數的。

(3)遊標的一些操作

  • 開啓遊標:
open c1;(開啓遊標執行查詢)
  • 關閉遊標:
close c1;(關閉遊標釋放資源)
  • 取一行遊標的值:
fetch c1 into pename; (取一行到變數中)
  • fetch的作用:

(1)把當前指針指向的記錄返回;

(2)將指針指向下一條記錄。

(4)遊標的屬性

  • %found(遊標能取到內容返回true,否則false)
  • %notfound(與前者相反)
  • %isopen:判斷遊標是否開啓
  • %rowcount:影響的行數,不是總行數,比如遊標取走了10行的數據,那麼這個值就是10

(5)遊標的限制

預設情況下,oracle數據庫只允許在同一個對談中開啓300個遊標

  • 修改遊標數的限制:
alter system set open_cursors=400 scope=both; 

scope是範圍,取值有三個:both, memory(只更改當前範例), spfile(只更改參數檔案,數據庫需要重新啓動)

8.例外

(1)例外的概念

例外是程式設計語言提供的一種功能,用來增強程式的健壯性和容錯性。

(2)例外的分類

  • 系統例外
  • 自定義例外

(3)系統例外

  • no_data_found 沒有找到數據,select語句沒有找到結果的時候
  • too_many_rows select…into語句匹配多個行
  • zero_divide 被零除
  • value_error 算術或轉換錯誤
  • timeout_on_resource 在等待資源時發生超時(分佈式數據庫的存取會用到)

(4)自定義例外

定義變數,型別是exception

使用raise關鍵字拋出自定義例外

9.程式設計方法

瀑布模型:

需求分析
	設計1.概要設計2.詳細設計
		編碼Coding
			測試Testing
				上線

以上步驟就像水流一下,最忌諱一上來就編碼。

想明白SQL語句、變數。

變數:1.初始值是多少2.最終值如何得到

10.其他小技巧:

  • 使用||符號來連線文字字串。
  • –表示單行註釋,/* */表示多行輸入
  • 單個等於號表示判斷。
  • plsql中大小寫不敏感。
  • then語句相當於一個大括號,後面的語句可以一起被處理,比如如下寫法:
when zero_divide then dbms_output.put_line('1:0不能做被除數');
                          dbms_output.put_line('2:0不能做被除數');

這裏兩句話都會被列印出來。

  • 把握一個原則:能不操作數據庫就不操作數據庫,比單單加減乘除的計算慢。

=====================================================================================

Oracle觸發器部分

1.觸發器的概念

觸發器是一個特殊的儲存過程。是一個與表相關聯的、儲存的PL/SQL程式。

作用:每當一個特定的數據操作語句(insert、update、delete,注意沒有select)在指定的表上發出時,oracle自動地執行觸發器中定義的語句序列。

2.觸發器的型別

  • 語句級的觸發器

在指定的操作語句操作之前或之後執行一次,不管這條語句影響了多少行。

語句級觸發器針對表,只會觸發一次

  • 行級的觸發器

觸發語句作用的每一條記錄都被觸發。在行級觸發器中使用:old和:new僞記錄變數,識別值的狀態。如果有for each row就表示行級觸發器。

insert into emp10 select * from emp where deptno=10;

會查出3條記錄。

行級觸發器針對行,有多少條記錄就觸發多少次。

3.第一個觸發器

每當成功插入新員工後,自動列印一句話,「成功插入新員工」。單詞trigger

例如:

create trigger saynewemp
after insert
on emp
declare
begin
	dbms_output.put_line('成功插入新員工');
end;
/

4.觸發器的具體應用場景

(1)複雜的安全性檢查 --比如週末不允許操作數據庫

(2)數據的確認 --漲後的工資大於漲前的工資

(3)數據庫審計 --跟蹤表上所做的數據操作,什麼時間什麼人操作了什麼數據,操作的人是什麼。基於值的審計

(4)數據的備份和同步 --異地備份,把主數據的數據自動同步到備數據庫中

5.建立觸發器的語法

create [or replace] trigger 觸發器名
{before|after}
{delete|insert|update [of 列名]}
on 表名
[for each row [when 條件]]
plsql塊

6.觸發器的案例

  • 觸發器案例一:禁止在非工作時間插入數據
  • 觸發器案例二:漲工資不能越漲越少 :old:new的使用要注意。
  • 觸發器案例三:建立基於值的觸發器
  • 觸發器案例四:數據庫的備份和同步 --利用觸發器實現數據的同步備份,多用於異地分佈式數據庫
    還能使用快照備份,快照備份是非同步備份,而觸發器是同步備份,沒有延時的
    =====================================================================================

Oracle儲存過程部分

1.儲存過程模板公式

create [or replace] PROCEDURE 過程名(參數列表)
AS
PLSQL子程式體; (關鍵字可以小寫)(如果不傳參,則參數列表的小括號也可以省略)

這個PLSQL子程式體;一般爲:

begin
	程式碼...
end;
/

如果寫的是儲存函數,那麼這裏的PROCEDURE需要改成FUNCTION,而且必須在參數列表和AS之間新增一句:RETURN 函數值型別。而且需要在子程式體需要返回的時候寫return 返回值

寫好之後先編譯,然後呼叫、執行。

as後面跟的是說明部分,相當於declare。

as也可以寫成is。

呼叫方式有兩種:

(1)exec 過程名();

(2)

begin
    呼叫語句;
end;
/

2.入參

在參數列表中,如果是輸入參數,可以寫入eno in number,in是關鍵,in前面是變數名,後面是變數型別。

3.出參

如果是輸出參數,寫eno out number,out是關鍵,out前面是變數名,後面是變數型別。

儲存過程和儲存函數都可以有out參數。

他們都可以有多個out參數。

儲存過程可以通過out參數來實現返回值。

4.小例子

查詢某個員工姓名、月薪和職位

create or replace procedure queryempinform(eno in number,
			pename out varchar2,
			psal   out number,
			pjob   out varchar2)
as
begin
	--得到該員工的姓名、月薪和職位
	select ename,sal,empjob into pename,psal,pjob from emp where empno=eno;
end;
/

5.在out參數中使用遊標案例

案例:查詢某個部門中所有員工的所有資訊。

包頭(負責宣告包中的結構):

CREATE OR REPLACE PACKAGE MYPACKAGE AS
	type empcursor is ref cursor;
	procedure queryEmpList(dno in number,empList out empcursor);
END MYPACKAGE;

注意:包頭中也可以不定義儲存過程,只定義遊標那一行。

包體(負責寫需要實現包頭中宣告的所有方法):

CREATE OR REPLACE PACKAGE BODY MYPACKAGE AS
	procedure queryEmpList(dno in number,empList out empcursor) AS
	BEGIN
		--開啓遊標型別(是一個集合,意味着可以返回許多資訊的集合)
		open empList for select * from emp where deptno=dno;
	END queryEmpList;
END MYPACKAGE;

注意:包體裏面的儲存過程也可以不寫在包體內部也可以一樣呼叫包頭中定義的遊標。

6.其他小知識點

  • 參數列表可以換行,也可以在關鍵字之間多加空格。
  • 如果是沒有參數的就是儲存過程,如果有參數就是儲存函數。儲存函數可以有一個返回值,可以用return子句進行返回。
  • 我們的原則是,如果只需要一個返回值,則用儲存函數。如果沒有返回值,用儲存過程,如果需要有多個返回值,則使用儲存過程,在參數中使用out參數。
  • 單行註釋使用「–註釋內容」,多行註釋使用「/* 註釋內容 */」。
  • 偵錯的時候授予許可權:

哪個許可權沒有就到sqlplus輸入如下程式碼:

grant 要調的許可權(中間用逗號分隔) to 使用者名稱;
  • 如果在計算中可能會有空值的話需要使用nvl預空函數。
    =====================================================================================

其他獨立知識點

一些不知道插進過去的哪些筆記的筆記就放在這裏吧~

簡單EXISTS和 NOT EXISTS講解和案例

select * from A where exists(select * from B where A.a=B.a)

爲例,
exists表示,對於A中的每一個記錄,如果,在表B中有記錄,其屬性a的值與表A這個記錄的屬性a的值相同,則表A的這個記錄是符合條件的記錄,

如果是NOT exists,則表示如果表B中沒有記錄能與表A這個記錄連線,則表A的這個記錄是符合條件的記錄。

而且必須在參數列表和AS之間新增一句:RETURN 函數值型別。而且需要在子程式體需要返回的時候寫return 返回值。**

寫好之後先編譯,然後呼叫、執行。

as後面跟的是說明部分,相當於declare。

as也可以寫成is。

呼叫方式有兩種:

(1)exec 過程名();

(2)

begin
    呼叫語句;
end;
/

2.入參

在參數列表中,如果是輸入參數,可以寫入eno in number,in是關鍵,in前面是變數名,後面是變數型別。

3.出參

如果是輸出參數,寫eno out number,out是關鍵,out前面是變數名,後面是變數型別。

儲存過程和儲存函數都可以有out參數。

他們都可以有多個out參數。

儲存過程可以通過out參數來實現返回值。

4.小例子

查詢某個員工姓名、月薪和職位

create or replace procedure queryempinform(eno in number,
			pename out varchar2,
			psal   out number,
			pjob   out varchar2)
as
begin
	--得到該員工的姓名、月薪和職位
	select ename,sal,empjob into pename,psal,pjob from emp where empno=eno;
end;
/

5.在out參數中使用遊標案例

案例:查詢某個部門中所有員工的所有資訊。

包頭(負責宣告包中的結構):

CREATE OR REPLACE PACKAGE MYPACKAGE AS
	type empcursor is ref cursor;
	procedure queryEmpList(dno in number,empList out empcursor);
END MYPACKAGE;

注意:包頭中也可以不定義儲存過程,只定義遊標那一行。

包體(負責寫需要實現包頭中宣告的所有方法):

CREATE OR REPLACE PACKAGE BODY MYPACKAGE AS
	procedure queryEmpList(dno in number,empList out empcursor) AS
	BEGIN
		--開啓遊標型別(是一個集合,意味着可以返回許多資訊的集合)
		open empList for select * from emp where deptno=dno;
	END queryEmpList;
END MYPACKAGE;

注意:包體裏面的儲存過程也可以不寫在包體內部也可以一樣呼叫包頭中定義的遊標。

6.其他小知識點

  • 參數列表可以換行,也可以在關鍵字之間多加空格。
  • 如果是沒有參數的就是儲存過程,如果有參數就是儲存函數。儲存函數可以有一個返回值,可以用return子句進行返回。
  • 我們的原則是,如果只需要一個返回值,則用儲存函數。如果沒有返回值,用儲存過程,如果需要有多個返回值,則使用儲存過程,在參數中使用out參數。
  • 單行註釋使用「–註釋內容」,多行註釋使用「/* 註釋內容 */」。
  • 偵錯的時候授予許可權:

哪個許可權沒有就到sqlplus輸入如下程式碼:

grant 要調的許可權(中間用逗號分隔) to 使用者名稱;
  • 如果在計算中可能會有空值的話需要使用nvl預空函數。
    =====================================================================================

其他獨立知識點

一些不知道插進過去的哪些筆記的筆記就放在這裏吧~

簡單EXISTS和 NOT EXISTS講解和案例

select * from A where exists(select * from B where A.a=B.a)

爲例,
exists表示,對於A中的每一個記錄,如果,在表B中有記錄,其屬性a的值與表A這個記錄的屬性a的值相同,則表A的這個記錄是符合條件的記錄,

如果是NOT exists,則表示如果表B中沒有記錄能與表A這個記錄連線,則表A的這個記錄是符合條件的記錄。