1. 程式人生 > 其它 >初步學習Oracle

初步學習Oracle

一、Oracle前言

  • 資料定義語言(DDL):create drop alter

  • 資料操縱語言(DML):insert select delete update

  • 事務控制語言(TCL):commit savepoint rollback

  • 資料控制語言(DCL):grant revoke

--注意:建議Oracle程式碼不區分大小寫:建議儘量用大寫(因為寫進去的小寫最後會被轉換為大寫在去執行!)

--建議儘量每行程式碼的後面加一個分號,因為在PLSQL Developer中可以執行,但是在SQL Plus中卻執行不出來結果,另外一種情況下也執行不了!(全部選起來,再去點選執行按鈕會報錯)。

二、Oracle中建立表和刪除表以及新增約束和修改約束

建立表及約束:

create table student(
sno number not null primary key,
sname varchar2(30) not null unique,
ssex char(6) default '女',
sage number(3,0) check(sage>18 and sage<30),
saddress varchar2(50)
);
--刪除剛才建立的表
drop table student;
--插入一條資料
insert into student
(sno, sname, ssex, sage, saddress)
values
(1, 'aa', '男', 20, '教室');
--查詢
select * from student;
--刪除
delete student where sno=1;
--或者
delete from student where sno=1;
--修改
update student set sage = 21 where sno=1;

建立表及新增修改約束:

 --建立老師表
create table teacher(
tno number(10),
sno number,
name varchar(30)
);
--設定tno為主鍵
alter table teacher add constraint tno_pk primary key(tno);
--設定外來鍵
alter table teacher add constraint sno_fk foreign key(sno) references student(sno);
--修改名字可以為空約束
alter table student modify(sname null);
--多行新增
insert into student
(select 2,'張三','男',24,'長沙' from dual
union
select 3,'李四','男',25,'武漢' from dual
union
select 4,'王五','男',25,'武漢' from dual
);
--注意:多行插入也可以和MySQL一樣

三、偽表和偽列

偽表:

--dual:偽表
select 1+1 from dual;
select lower('SDA') from dual;

偽列:

--偽列
--rowid rownum
--rowid:唯一性
--rowid:讓每一條記錄都唯一起來。
--偽列上檢視前三條資料
select a.*,rownum from student a where rownum<4;
--或者
select a.*,rownum from student a where rownum<=3;
--注意:rownum只能小於或者小於等於,不能大於或單獨的等於,oracle沒有limit。

連線:

--||:連線符號,將兩列併入一列
select sname||sage from student;

四、Oracle中建立表空間和刪除

一、建立表空間:
--注意要用資料庫管理員的身份建立(scott的許可權不足)

--1.建立一個比較簡單的表空間
create tablespace stu1
--建立表空間名為stu
--tablespace:表空間的關鍵字
datafile 'd:\stu1.dbf'
--資料檔案儲存在d:/stu.dbf (檔案的字尾名為dbf)
--datafile:資料檔案
--注意:Oracle中的字串用單引號('')
size 100m
--大小為100m
--2.建立比較複雜的表空間
create tablespace stu
--建立表空間名為stu
--tablespace:表空間的關鍵字

datafile 'd:\stu.dbf'

size 100m

AUTOEXTEND ON NEXT 32M MAXSIZE UNLIMITED
--autoextend on:表空間大小不夠用時自動擴充套件
--next 32m 自動擴充套件增量為32MB
--MAXSIZE UNLIMITED :最大空間:無限制
LOGGING
--logging 是物件的屬性,建立資料庫物件時,oracle 將日誌資訊記錄到練級重做日誌檔案中。代表空間型別為永久型!
EXTENT MANAGEMENT LOCAL
--extent management local 代表管理方式為本地
SEGMENT SPACE MANAGEMENT AUTO;
--磁碟擴充套件管理方法:
--使用該選項時區大小由系統自動確定。由於 Oracle 可確定各區的最佳大小,所以區大小是可變的。
--刪除表空間
drop tablespace stu1

ORACLE中,表空間是資料管理的基本方法,所有使用者的物件要存放在表空間中,也就是使用者有空間的使用權,才能建立使用者物件.否則是不允許建立物件,因為就是想建立物件,如表,索引等,也沒有地方存放,Oracle會提示:沒有儲存配額.

因此,在建立物件之前,首先要分配儲存空間.分配儲存,就要建立表空間:

  建立表空間示例如下:

CREATE TABLESPACE "SAMPLE"
LOGGING
DATAFILE D:\ORACLE\ORADATA\ORA92\LUNTAN.ora SIZE 5M
EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO

上面的語句分以下幾部分:

第一: CREATE TABLESPACE "SAMPLE"  建立一個名為 "SAMPLE" 的表空間.(對錶空間的命名,遵守Oracle 的命名規範就可了.)

ORACLE可以建立的表空間有三種類型:

(1)TEMPORARY: 臨時表空間,用於臨時資料的存放;

建立臨時表空間的語法如下:

CREATE TEMPORARY TABLESPACE "SAMPLE"......

(2)UNDO : 還原表空間. 用於存入重做日誌檔案.

建立還原表空間的語法如下:

CREATE UNDO TABLESPACE "SAMPLE"......

(3)使用者表空間: 最重要,也是用於存放使用者資料表空間

可以直接寫成: CREATE TABLESPACE "SAMPLE"

TEMPORARY 和 UNDO 表空間是ORACLE 管理的特殊的表空間.只用於存放系統相關資料.

第二: LOGGING

有 NOLOGGING 和 LOGGING 兩個選項,

NOLOGGING: 建立表空間時,不建立重做日誌.

LOGGING 和NOLOGGING正好相反, 就是在建立表空間時生成重做日誌.

用NOLOGGING時,好處在於建立時不用生成日誌,這樣表空間的建立較快,但是沒能日誌,資料丟失後,不能恢復,但是一般我們在建立表空間時,是沒有資料的,按通常的做法,是建完表空間,並匯入資料後,是要對資料做備份的,所以通常不需要表空間的建立日誌,因此,在建立表空間時,選擇 NOLOGGING,以加快表空間的建立速度.

第三: DATAFILE 用於指定資料檔案的具體位置和大小.

如: DATAFILE D:\ORACLE\ORADATA\ORA92\LUNTAN.ora SIZE 5M

說明檔案的存放位置是 D:\ORACLE\ORADATA\ORA92\LUNTAN.ora , 檔案的大小為5M.

如果有多個檔案,可以用逗號隔開:

DATAFILE D:\ORACLE\ORADATA\ORA92\LUNTAN.ora SIZE 5M,

D:\ORACLE\ORADATA\ORA92\dd.ora SIZE 5M

但是每個檔案都需要指明大小.單位以指定的單位為準如 5M 或 500K.

對具體的檔案,可以根據不同的需要,存放大不同的介質上,如磁碟陣列,以減少IO竟爭.

指定檔名時,必須為絕對地址,不能使用相對地址.

第四: EXTENT MANAGEMENT LOCAL 儲存區管理方法

在Oracle 8i以前,可以有兩種選擇,一種是在字典中管理(DICTIONARY),另一種是本地管理(LOCAL ),從9I開始,只能是本地管理方式.因為LOCAL 管理方式有很多優點.

在字典中管理(DICTIONARY): 將資料檔案中的每一個儲存單元做為一條記錄,所以在做DM操作時,就會產生大量的對這個管理表的Delete和Update操作.做大量資料管理時,將會產生很多的DM操作,嚴得的影響效能,同時,長時間對錶資料的操作,會產生很多的磁碟碎片,這就是為什麼要做磁碟整理的原因.

本地管理(LOCAL): 用二進位制的方式管理磁碟,有很高的效率,同進能最大限度的使用磁碟. 同時能夠自動跟蹤記錄臨近空閒空間的情況,避免進行空閒區的合併操作。

第五: SEGMENT SPACE MANAGEMENT

磁碟擴充套件管理方法:

SEGMENT SPACE MANAGEMENT: 使用該選項時區大小由系統自動確定。由於 Oracle 可確定各區的最佳大小,所以區大小是可變的。

UNIFORM SEGMENT SPACE MANAGEMENT:指定區大小,也可使用預設值 (1 MB)。

第六: 段空間的管理方式:

AUTO: 只能使用在本地管理的表空間中. 使用LOCAL管理表空間時,資料塊中的空閒空間增加或減少後,其新狀態都會在點陣圖中反映出來。點陣圖使 Oracle 管理空閒空間的行為更加自動化,併為管理空閒空間提供了更好的性,但對含有LOB欄位的表不能自動管理.

MANUAL: 目前已不用,主要是為向後相容.

第七: 指定塊大小. 可以具體指定表空間資料塊的大小.

建立例子如下:

1 CREATE TABLESPACE "SAMPLE"

2 LOGGING

3 DATAFILE D:\ORACLE\ORADATA\ORA92\SAMPLE.ora SIZE 5M,

4 D:\ORACLE\ORADATA\ORA92\dd.ora SIZE 5M

5 EXTENT MANAGEMENT LOCAL

6 UNIFORM SEGMENT SPACE MANAGEMENT

7* AUTO

表空間已建立。

要刪除表空間,可以

DROP TABLESPACE SAMPLE;

五、Oracle中建立角色賦權和收權

--建立角色、賦權、收權時注意要用資料庫管理員的身份建立(scott的許可權不足)

--1.建立一個簡單的角色
create user sb
--建立一個使用者:使用者名稱為sb
identified by 123
--該賬號的密碼為123

--2.建立一個帶有表空間的角色
create user sc
--建立一個使用者:使用者名稱為sc
identified by 456
--該賬號的密碼為456
default tablespace stu
--預設表空間為:stu

--把CONNECT、RESOURCE角色授予使用者sb
GRANT CONNECT,RESOURCE TO sb;
--允許使用者檢視 EMP 表中的記錄
GRANT SELECT ON emp TO sb;
--允許使用者更新 EMP 表中的記錄
GRANT UPDATE ON emp TO sb;

--撤銷使用者epet的RESOURCE角色
REVOKE RESOURCE FROM sb;

--常用系統預定義角色
--CONNECT:臨時使用者。
--RESOURCE:更為可靠和正式的使用者。
--DBA:資料庫管理員角色,擁有管理資料庫的最高許可權。

六、PL/SQL

--列印Hello World
begin
dbms_output.put_line('Hello World1');//輸出語句
dbms_output.put_line('Hello World2');
end;

--利用宣告變數實現查詢7369的所有資訊
--%type:取現有的資料表中的資料的型別
--%rowtype:取表中一行的資料型別
declare
eid emp.empno%type:=7369; //將emp表中的empno列的資料型別賦給eid,並給eid賦值為7369
emprow emp%rowtype; //將emp表中的一行賦給emprow
begin
select * into emprow from emp where empno=eid; //從emp表中取出一行,並賦值給emprow
dbms_output.put_line('編號為'||eid||'的員工姓名為'||emprow.ename);
end;

斐波那契數列

--斐波那契數列

--loop迴圈
declare
a number:=1;
b number:=0;
c number:=0;
i number:=1;
begin
loop
c:=a+b;
a:=b;
b:=c;
i:=i+1;
exit when i>6;
end loop;
dbms_output.put_line(c);
end;

--while迴圈
declare
a number:=1;
b number:=0;
c number:=0;
i number:=1;
begin
while(i<=6)loop
c:=a+b;
a:=b;
b:=c;
i:=i+1;
end loop;
dbms_output.put_line(c);
end;

--for迴圈
declare
a number:=1;
b number:=0;
c number:=0;
i number:=1;
begin
for i in 1..30
loop
c:=a+b;
a:=b;
b:=c;
end loop;
dbms_output.put_line(c);
end;
--if-else語句
--查詢員工編號為7369的薪水,如果薪水大於600輸出高薪水,如果小於600底薪水
declare
eid number(10):=7369;
sal emp.sal%type;
begin
select sal into sal from emp where empno=eid;
if sal>600 then
dbms_output.put_line('高薪水');
else dbms_output.put_line('底薪水');
end if;
end;

--查詢員工編號為7369的薪水,如果薪水大於1500輸出高薪水,如果小於1500-900中等薪水,
--小於900底薪水
declare
eid number(10):=7369;
sal emp.sal%type;
begin
select sal into sal from emp where empno=eid;
if(sal>1500) then
dbms_output.put_line('高薪水');
elsif(sal>900) then
dbms_output.put_line('中等薪水');
else dbms_output.put_line('底薪水');
end if;
end;

--case
--查詢員工編號為7369的工資等級。注意:只能為固定值
--800 A 950 B 1100 C else no
--方法一:
declare
eid number(10):=7369;
sal emp.sal%type;
begin
select sal into sal from emp where empno=eid;
case sal
when '800' then dbms_output.put_line('A');
when '950' then dbms_output.put_line('B');
when '1100' then dbms_output.put_line('C');
else dbms_output.put_line('no');
end case;
end;

函式遞迴

--遞迴實現1+2+3+4加到100的和
create or replace function test01(n in number)
return number is
begin
if n=1 then return 1;
else return (n+test01(n-1));
end if;
end test01;

select test01(100) from dual;
drop function test01;

--遞迴求出第21位 1,1,2,3,5,8,13,21...(此處非遞迴)
create or replace function test02(n in number)
return number is
a number(10):=1;
b number(10):=0;
c number(10):=0;
begin
for i in 1..n
loop
c:=a+b;
a:=b;
b:=c;
end loop;
return c;
end test02;

select test02(6) from dual;
drop function test02;

--1.編寫一個函式,要求能將阿拉伯數字(a,b,c,d,e,f,g,h,i)分別替換為
--(1,2,3,4,5,6,7,8,9),非數字全部替換為0,禁止使用replace
create or replace function test03(str in varchar2)
return varchar2 is
newStr varchar2(100):='';
r varchar2(2):='';
begin
for i in 1..length(str)
loop
select substr(str,i,1) into r from dual;
case r
when 'a' then newStr:=newStr||1;
when 'b' then newStr:=newStr||2;
when 'c' then newStr:=newStr||3;
when 'd' then newStr:=newStr||4;
when 'e' then newStr:=newStr||5;
when 'f' then newStr:=newStr||6;
when 'g' then newStr:=newStr||7;
when 'h' then newStr:=newStr||8;
when 'i' then newStr:=newStr||9;
else newStr:=newStr||0;
end case;
end loop;
return newStr;
end test03;

select test03('abcdklgasngoeirg;ajldgqeoihoiqehglds') from dual;
drop function test03;

--2.要求編寫函式,要求能將傳進來的字串反序輸出,比如'abcdef',要求輸出為'fedcba'
create or replace function test04(str in varchar2)
return varchar2 is
newStr varchar2(100):='';
r varchar2(1):='';
begin
for i in 1..length(str)
loop
newStr:=substr(str,i,1)||newStr;
end loop;
return newStr;
end test04;

select test04('123456789') from dual;
drop function test04;

異常

--系統自帶異常
--no_data_found、too_many_rows......
--8.編寫一個程式塊,接受一個僱員名,從emp表中顯示該僱員的工作崗位與薪水,
--若輸入的僱員名不存在,顯示“該僱員不存在”資訊。
declare
ejob emp.job%type;
esal emp.sal%type;
ename1 emp.ename%type:='SMITH';
begin
select job,sal into ejob,esal from emp where ename=ename1;
dbms_output.put_line('工作崗位:'||ejob);
dbms_output.put_line('薪水:'||esal);
exception when no_data_found then dbms_output.put_line('該僱員不存在');
end;
--自定義異常
declare
eid emp.empno%type:=7369;
esal emp.sal%type;
mye exception; --宣告異常
begin
select sal into esal from emp where empno=eid;
if esal>2500 then
dbms_output.put_line('不錯不錯');
else
raise mye; --拋異常
end if;
exception when mye then --處理異常
dbms_output.put_line('加工資');
end;

--
declare
n_s number(5);
e_my exception;
pragma exception_init(e_my,-20001);
begin
select count(ename) into n_s from emp where ename like 'S%';
if n_s=0 then
raise e_my;
end if;
dbms_output.put_line('數量是'||n_s);
exception
when e_my then
dbms_output.put_line('人員為空');
end;

遊標

--5.某公司要根據僱員的職位來加薪,公司決定按下列加薪結構處理:
-- Designation Raise
-----------------------
-- Clerk 500
-- Salesman 1000
-- Analyst 1500
-- Otherwise 2000
--編寫一個程式塊,接受一個僱員名,從emp表中實現上述加薪處理。
declare
ejob emp.job%type;
esal emp.sal%type;
cursor myr(enames emp.ename%type) is select job,sal from emp where ename=enames for update of ename;
begin
open myr('SMITH');
fetch myr into ejob,esal;
case ejob
when 'CLERK' then
update emp set sal=(esal+500) where current of myr;
dbms_output.put_line('加薪後的薪水:'||(esal+500));
when 'SALESMAN' then
update emp set sal=(esal+1000) where current of myr;
dbms_output.put_line('加薪後的薪水:'||(esal+1000));
when 'ANALYST' then
update emp set sal=(esal+1500) where current of myr;
dbms_output.put_line('加薪後的薪水:'||(esal+1500));
-- when 'OTHERWISE' then dbms_output.put_line('加薪後的薪水:'||sal+2000);
else
update emp set sal=(esal+2000) where current of myr;
dbms_output.put_line('加薪後的薪水:'||(esal+2000));
end case;
close myr;
end;

select * from emp
--6.編寫一個程式塊,將emp表中僱員名全部顯示出來。
declare
enames varchar(30);
cursor myr is select ename from emp;
begin
open myr;
loop
fetch myr into enames;
exit when myr%notfound;
dbms_output.put_line(enames);
end loop;
close myr;
end;


--7.編寫一個程式塊,將emp表中前5人的名字顯示出來。
declare
enames varchar(30);
cursor myr is select ename from emp
where rownum<=5;
begin
open myr;
loop
fetch myr into enames;
exit when myr%notfound;
dbms_output.put_line(enames);
end loop;
close myr;
end;

--2. 使用For迴圈,接受一個部門號,從emp表中顯示該部門的所有僱員的姓名,工作和薪水。
declare
--enames emp.ename%type;
--ejob emp.job%type;
--esal emp.sal%type;-
cursor myr(eid emp.deptno%type) is select ename,job,sal from emp where deptno=eid;
begin
for i in myr(30)
loop
--fetch myr into enames,ejob,esal;
dbms_output.put_line(i.ename||'::'||i.job||'::'||i.sal);
--dbms_output.put_line(enames||'::'||ejob||'::'||esal);
end loop;
end;


select * from emp;

--3. 使用帶引數的遊標,實現第2題。
declare
--enames emp.ename%type;
--ejob emp.job%type;
--esal emp.sal%type;-
cursor myr(eid emp.deptno%type) is select ename,job,sal from emp where deptno=eid;
begin
for i in myr(30)
loop
--fetch myr into enames,ejob,esal;
dbms_output.put_line(i.ename||'::'||i.job||'::'||i.sal);
--dbms_output.put_line(enames||'::'||ejob||'::'||esal);
end loop;
end;


--4.編寫一個PL/SQL程式塊,從emp表中對名字以“A”或“S”開始的所有僱員按他們基本薪水的10%給他們加薪。
declare
nums number(10):=0;
cursor myr is select * from emp where ename like 'A%' or ename like 'S%' for update
of ename;
begin
for i in myr
loop
nums:=i.sal*1.1;
update emp set sal=nums where current of myr;
end loop;
end;

select * from emp;
--5. emp表中對所有僱員按他們基本薪水的10%給他們加薪,如果所增加後的薪水大於5000盧布,則取消加薪。
declare
nums number(10);
cursor myr is select * from emp for update;
begin
for i in myr
loop
nums:=i.sal*1.1;
if nums<=5000 then
update emp set sal=nums where current of myr;
end if;
end loop;
end;

遊標巢狀

--遊標巢狀
--for迴圈
declare
cursor myr1 is select deptno from dept;
cursor myr2(deptno1 dept.deptno%type) is select ename from emp where deptno=deptno1;
begin
for i in myr1
loop
for j in myr2(i.deptno)
loop
dbms_output.put_line(i.deptno||':'||j.ename);
end loop;
end loop;
end;

--loop迴圈
declare
deptno1 dept.deptno%type;
enames emp.ename%type;
cursor myr1 is select deptno from dept;
cursor myr2(deptno2 dept.deptno%type) is select ename from emp where deptno=deptno2;
begin
open myr1;
loop
fetch myr1 into deptno1;
exit when myr1%notfound;
open myr2(deptno1);
loop
fetch myr2 into enames;
exit when myr2%notfound;
dbms_output.put_line(deptno1||' '||enames);
end loop;
close myr2;
end loop;
close myr1;
end;

REF遊標和動態SQL

--遊標巢狀
--for迴圈
declare
cursor myr1 is select deptno from dept;
cursor myr2(deptno1 dept.deptno%type) is select ename from emp where deptno=deptno1;
begin
for i in myr1
loop
for j in myr2(i.deptno)
loop
dbms_output.put_line(i.deptno||':'||j.ename);
end loop;
end loop;
end;

--loop迴圈
declare
deptno1 dept.deptno%type;
enames emp.ename%type;
cursor myr1 is select deptno from dept;
cursor myr2(deptno2 dept.deptno%type) is select ename from emp where deptno=deptno2;
begin
open myr1;
loop
fetch myr1 into deptno1;
exit when myr1%notfound;
open myr2(deptno1);
loop
fetch myr2 into enames;
exit when myr2%notfound;
dbms_output.put_line(deptno1||' '||enames);
end loop;
close myr2;
end loop;
close myr1;
end;


--REF遊標
--1、REF遊標分為強型別和弱型別

--2、強型別
--查詢emp表中所有的資料
declare
type myr1 is ref cursor return emp%rowtype;
myr2 myr1;
enames emp%rowtype;
begin
open myr2 for select * from emp;
loop
fetch myr2 into enames;
exit when myr2%notfound;
dbms_output.put_line(enames.ename);
end loop;
close myr2;
end;

--3、弱型別
--查詢emp表中所有的資料
declare
type myr1 is ref cursor;
myr2 myr1;
emps emp%rowtype;
begin
open myr2 for select * from emp;
loop
fetch myr2 into emps;
exit when myr2%notfound;
dbms_output.put_line(emps.ename);
end loop;
close myr2;
end;


--4、動態sql案例
declare
sal1 emp.sal%type:=1500;
sal2 emp.sal%type:=2000;
type myr1 is ref cursor;
myr2 myr1;
emps emp%rowtype;
begin
open myr2 for 'select * from emp where sal>:1 and sal<:2 order by sal desc'
using sal1,sal2;
loop
fetch myr2 into emps;
exit when myr2%notfound;
dbms_output.put_line(emps.ename);
end loop;
close myr2;
end;


select ename from emp where sal>1500 and sal<2000;


select * from scott.student;


七、SQL高階

同義詞

--同義詞
--私有同義詞和公有同義詞
--建立一個同義詞
create synonym emm for scott.emp;
--刪除同義詞
drop synonym emm;
--建立一個同義詞
create or replace synonym a for scott.emp;
--運用
select * from a;
--建立一個公有的同義詞
grant create public synonym to scott;
create or replace public synonym b for scott.emp;
create or replace public synonym c for scott.emp;
select * from b;
select * from c;
--授權
grant drop public synonym to scott;
drop public synonym b;
--收權
revoke drop public synonym from scott;

序列

--序列
create sequence aa
start with 1
increment by 1
maxvalue 100
minvalue 1
--查詢序列
select aa.nextval from dual;
--檢視當前值
select aa.currval from dual;
--刪除序列
drop sequence aa;
--修改序列
alter sequence aa maxvalue 1000;
--序列使用
create table stu(
sid number,
names varchar2(10)
);

insert into stu values(aa.nextval,'zzz');
select * from stu;
drop table stu;

檢視、索引

--檢視
create or replace view bb
as
select * from stu;

create or replace force view cc
as
select * from stu;

drop view aa;
drop view cc;

--索引
create index dd on stu(sid);
drop index dd;

儲存過程

--儲存過程
--不帶引數儲存過程
create or replace procedure getname
as
enames varchar2(30);
begin
select ename into enames from emp where empno=7369;
dbms_output.put_line(enames);
end;

--呼叫
begin
getname;
end;
call getname();
drop procedure getname;

--帶引數的儲存過程
--根據員工編號查詢的名字。
create or replace procedure getnames(eno number)
as
enames varchar2(30);
begin
select ename into enames from emp where empno=eno;
dbms_output.put_line(enames);
exception when no_data_found then
dbms_output.put_line('此人不存在');
when others then
dbms_output.put_line('有錯!');
end;

--呼叫
begin
getnames(131);
end;
call getnames(131);

--in和out引數(只能用begin end;呼叫)
--根據編號查詢名字(名字要返回出來,儲存過程中不列印)
create or replace procedure selectname(eid in number ,enames out varchar2)
as
enames1 varchar2(30);
begin
select ename into enames1 from emp where empno=eid;
enames:=enames1;
end;

--呼叫
declare
eid number(6):=7369;
ename varchar2(30);
begin
selectname(eid,ename);
dbms_output.put_line(ename);
end;


--c.in out 引數
--實現a 和b的值交換。
create or replace procedure selectname(a in out number,b in out number)
as
c number(4);
begin
c := a;
a := b;
b := c;
end;

--呼叫
declare
a number(4):=10;
b number(4):=20;
begin
selectname(a,b);
dbms_output.put_line('原來a為10,a:'||a);
dbms_output.put_line('原來6為20,b:'||b);
end;

--總結:
--in引數:只作為引數傳進去。
--out引數:返回的結果。
--in out引數:既要作為引數傳進去,又要作為結果返回出來。

--儲存過程的呼叫
--begin end;可以呼叫所有的儲存過程
--call只能呼叫帶引數的儲存過程。呼叫無引數的時要加().不建議使用。容易和建立的()混淆。

觸發器

--不能刪除李文才
--建立觸發器
create or replace trigger tridel --建立觸發器
after delete--什麼操作
on stuInfo--表
for each row --行觸發
begin
--條件
if(:old.stuName='李文才') then
raise_application_error(-20004,'該生不能刪除!');
end if;
end;

--序列
create sequence a
start with 0
increment by 1
maxvalue 2000
minvalue 0

create table s3(
no number(6),
name varchar2(30)
)

insert into s3(name) values('cc')

--建立觸發器
create or replace trigger triInsert
before insert
on s3
for each row
begin
:new.no:=a.nextval;
end;

select * from s3;
--禁用觸發器
alter trigger triInsert disable
--啟用
alter trigger triInsert enable
--刪除觸發器
drop trigger triInsert


--觸發器
--表級觸發器
create or replace trigger modify_stu
before insert or update or delete on student
begin
if deleting then
raise_application_error(-20001,'該表不允許刪除資料');
elsif updating then
raise_application_error(-20002,'該表不允許修改資料');
elsif inserting then
raise_application_error(-20003,'該表不允許插入資料');
end if;
end;

--行級觸發器
--after
--建立觸發器:將對student表的操作都記錄到stu_log表中(update of 用於指定一個
--或多個欄位,指定欄位被更新時才會觸發觸發器)
create or replace trigger modify_stu
after insert or delete or update of stu_name
on student
for each row
begin
if inserting then
insert into stu_log values(1,'insert',sysdate,:new.stu_name);
elsif deleting then
insert into stu_log values(2,'delete',sysdate,:old.stu_name);
elsif updating then
insert into stu_log values(3,'update_old',sysdate,:old.stu_name);
insert into stu_log values(4,'update_new',sysdate,:new.stu_name);
end if;
end;

--before
--建立觸發器:實現id的隱式自增
create or replace trigger modify_stu
before insert on student
for each row
declare
next_id number;
begin
select seq_test.nextval into next_id from dual;
:new.id :=next_id;
end;

程式包

--程式包
--分為兩部分:規範、主體
--規範
--1.程式包(函式和儲存過程)
--儲存過程(根據編號查名字)
--函式(根據編號查名字)
--規範部分
create or replace package pg is--或者as 建立程式包規範
procedure noname(eid number);--宣告儲存過程
function selectname(eid number) return varchar2;--宣告函式
end pg;--結束程式包規範
--主體
create or replace package body pg is--建立程式包主體
procedure noname(eid number)--完成儲存過程的主體
is
enames varchar2(30);
begin
select ename into enames from emp where empno=eid;
dbms_output.put_line(enames);
end;
--函式
function selectname(eid number) return varchar2--完成函式體
is
enames varchar2(30);
begin
select ename into enames from emp where empno=eid;
return enames;
end;
end pg;

--刪除規範
drop package pg;
--刪除主體
drop package body pg;

--執行順序問題:先執行規範,再執行主體。

--呼叫儲存過程
call pg.noname(7369);
begin
pg.noname(7369);
end;
--呼叫函式
select pg.selectname(7369) from dual;


--2.程式包(儲存過程和遊標巢狀使用)
--根據編號查詢
--規範
create or replace package pb is
cursor c_emp(eid number) return emp%rowtype;--遊標宣告
procedure pro;--根據編號查詢
end pb;

--主體
create or replace package body pb is
cursor c_emp(eid number) return emp%rowtype --宣告遊標
is
select * from emp where empno=eid;
procedure pro--宣告儲存過程
is
emprow emp%rowtype;
begin
open c_emp(7369);
fetch c_emp into emprow;
dbms_output.put_line(emprow.ename);
close c_emp;--結束遊標
end;--結束儲存過程
end pb;--結束程式包


--呼叫
begin
pb.pro;
end;