1. 程式人生 > >oracle個人學習筆記

oracle個人學習筆記

1>-----------------------------表空間-------------------------
1.1>建立表空間example
create tablespace 表空間名稱[example]
logging  
datafile 資料庫儲存位置['/opt/oracle/oradata/orcl/EPSSITE.dbf'] 
size 50m  [初始大小]
autoextend on  
next 50m maxsize 20480m  [每次增長,和最大佔有]  
extent management local;
1.2>檢視建立好的表空間
select default_tablespace, temporary_tablespace, d.username from dba_users d;

2>------------------------------使用者-------------------------------
2.1>建立使用者easysite並賦權
create user [使用者名稱稱]easysite identified by [密碼]easysite default tablespace [表空間]example;
grant connect,imp_full_database,resource,dba[高階許可權] to [給使用者賦權]easysite;
2.2>檢視資料庫使用者
select  * from dba_users;
2.3>刪除使用者
drop user 使用者名稱 cascade;---cascade 級聯
2.4>----------------------------許可權---------------------
2.4.1>-- 使用者許可權
-- 分配使用者 Sam 建立表,建立序列,建立儲存過程和建立檢視的許可權
grant create table,create sequence,create view,create procedure to [使用者]sam
-- 去除使用者建立檢視的許可權
revoke create view from sam;
-- 分配使用者 Sam 在表 tt 上的 select 許可權
grant select on tt to sam;
-- 去除使用者 Sam 在表 tt 上的 select 許可權
revoke select on tt from sam;
-- 分配表的 Select 許可權給所有使用者
grant select on tt to public;
-- 去除表的 Select 許可權給所有使用者
revoke select on tt from public;
2.4.2>-- 角色許可權
-- 分配角色 manager 建立表,建立序列的許可權
grant create table,create sequence to manager;
-- 去除角色 manager 建立檢視的許可權
revoke create table from manager;
-- 分配表的 Update 許可權給角色 Manager
grant update on tt to manager;
-- 去除表的 Update 許可權給角色 Manager
revoke update on tt from manager;

3>還原資料
imp 使用者名稱[easysite]/密碼[easysite] file=資料庫檔案位置[e:/easysite.dmp] full=y

4>備份資料[d:\oracle 目錄需要先建立好]
exp user/
[email protected]
[例項名] file=[檔案路徑]d:\oracle\example.tmp log=[日誌路徑]d:\oracle\example.log 第一課:客戶端 1. Sql Plus(客戶端),命令列直接輸入:sqlplus,然後按提示輸入使用者名稱(scott ),密碼(tiger)。 2. 從開始程式執行:sqlplus,是圖形版的sqlplus. 3. http://localhost:5560/isqlplus Toad:管理, PlSql Developer: ------------------------------------------------------------- 第二課:更改使用者 1. sqlplus sys/bjsxt as sysdba 2. alter user scott account unlock;(解鎖) show user 檢視當前使用者 conn scott/tiger 更改使用者 -------------------------------------------------------------- 第三課:table structure 1. 描述某一張表:desc 表名 2. select * from 表名 ---------------------------------------------------------------- 第四課:select 語句: 1.計算資料可以用空表(dual):比如:select 2*3 from dual(sqlserver不成立) select sysdate from dual 查詢當前日期 2.select ename,sal*12 annual_sal from emp;與select ename,sal*12 "annual sal" from emp;區別,加雙引號保持原顯示方式包括大小寫。如果不加 寫成annual sal會出錯。而且會都顯示為大寫。(sql server 加不加雙引號都是大小寫不變) 3. select ename || "abcd" 如果連線字串中含有單引號,用兩個單引號代替一個單引號。(相當於sql server的+) 如果兩個單引號是ename'abcd' 如果是單引號是enameabcd ------------------------------------------------------------------------------------------ 第五課:distinct select deptno from emp; select distinct deptno from emp; select distinct deptno from emp; select distinct deptno ,job from emp 去掉deptno,job兩者組合的重複。更多的項,就是這麼多項的組合的不重複組合。 -------------------------------------------------------------------------------------- 第六課:Where select * from emp where deptno =10; select * from emp where deptno <>10;不等於10 select * from emp where ename ='bike'; select ename,sal from emp where sal between 800 and 1500 (>=800 and <=1500) 空值處理: select ename,sal,comm from emp where comm is (not) null; select ename,sal,comm from emp where ename ( not)in ('smith','king','abc'); select ename from emp where ename like '_A%';_代表一個字母,%代表0個或多個字母. 如果查詢%,+代表一個或者多個 可用轉義字元.\%. 還可以用escape '$'比如:select ename from emp where ename like '%$a%' escape '$';select ename from emp where ename like '\%a%' ---------------------------------------------------------------------------------------- 第七課: orderby select * from dept; select * from dept order by dept desc;(預設:asc) select ename,sal,deptno from emp order by deptno asc,ename desc; ---------------------------------------------------------------------------------------- 第八課: sql function1: select ename,sal*12 annual_sal from emp where ename not like '_A%' and sal>800 order by sal desc; select lower(ename) from emp; select ename from emp where lower(ename) like '_a%';等同於 select ename from emp where ename like '_a%' or ename like '_A%'; select substr(ename,2,3) from emp;從第二字元截,一共截三個字元. select chr(65) from dual 結果為:A select ascii('a') from dual 結果為:65 select round(23.652,1) from dual; 結果為: 23.7 select round(23.652,-1) from dual; 20 select to_char(sal,'$99_999_999') from emp; select to_char(sal,'L99_999_999') from emp;人民幣符號,L:代表本地符號 這個需要掌握牢: select birthdate from emp; 顯示為: BIRTHDATE ---------------- 17-12月-80 ---------------- 改為: select to_char(birthdate,'YYYY-MM-DD HH:MI:SS') from emp; 顯示: BIRTHDATE ------------------- 1980-12-17 12:00:00 ------------------- select to_char(sysdate,'YYYY-MM-DD HH24:MI:SS') from dual; //也可以改為:HH12 TO_CHAR(SYSDATE,'YY ------------------- 2007-02-25 14:46:14 to_date函式: select ename,birthdate from emp where birthdate > to_date('1981-2-20 12:34:56','YYYY-MM-DD HH24:MI:SS'); 如果直接寫 birthdate>'1981-2-20 12:34:56'會出現格式不匹配,因為表中的格式為: DD-MM月-YY. select sal from emp where sal>888.88 無錯.但 select sal from emp where sal>$1,250,00; 會出現無效字元錯誤. 改為: select sal from emp where sal>to_number('$1.250.00','$9,999,99'); 把空值改為0 select ename,sal*12+nvl(comm,0) from emp; 這樣可以防止comm為空時,sal*12相加也為空的情況. ------------------------------------------------------------------------------------------ 第九課: Group function 組函式 max,min,avg ,count,sum函式 select to_char(avg(sal),'99999999,99') from emp; select round(avg(sal),2) from emp; 結果:2073.21 select count(*) from emp where deptno=10; select count(ename) from emp where deptno=10; count某個欄位,如果這個欄位不為空就算一個. select count(distinct deptno) from emp; select sum(sal) from emp; ------------------------------------------------------------------------------------------ 第十課: Group by語句 需求:現在想求,求每個部門的平均薪水. select avg(sal) from emp group by deptno; select deptno,avg(sal) from emp group by deptno; select deptno,job,max(sal) from emp group by deptno,job; 求薪水值最高的人的名字. select ename,max(sal) from emp;出錯,因為max只有一個值,但等於max值的人可能好幾個,不能匹配. 應如下求: select ename from emp where sal=(select max(sal) from emp); Group by語句應注意, 出現在select中的欄位,如果沒出現在組函式中,必須出現在Group by語句中. ----------------------------------------------------------------------------------------- 第十一課: Having 對分組結果篩選 Where是對單條紀錄進行篩選,Having是對分組結果進行篩選. select avg(sal),deptno from emp group by deptno having avg(sal)>2000; 查詢工資大於1200僱員,按部門編號進行分組,分組後平均薪水大於1500,按工薪倒充排列. select * from emp where sal>1200 group by deptno having avg(sal)>1500 order by avg(sal) desc; ------------------------------------------------------------------------------------------ 第十二課:子查詢 誰掙的錢最多(誰:這個人的名字, 錢最多) select 語句中巢狀select 語句,可以在where,from後. 問那些人工資,在平均工資之上. select ename,sal from emp where sal>(select avg(sal) from emp); 查詢每個部門掙錢最多的那個人的名字. select ename ,deptno from emp where sal in(select max(sal) from ename group by deptno) 查詢會多值. 應該如下: select max(sal),deptno from emp group by deptno;當成一個表.語句如下: select ename, sal from emp join(select max(sal) max_sal,deptno from emp group by deptno) t on(emp.sal=t.max_sal and emp.deptno=t.deptno); 每個部門的平均薪水的等級. 分析:首先求平均薪水(當成表),把平均薪水和另外一張表連線. ------------------------------------------------------------------------------------------- 第十四課:self_table_connection 把某個人的名字以及他的經理人的名字求出來(經理人及這個人在表中同處一行) 分析:首先求出這個人的名字,取他的編號,然後從另一張表與其相對應編號,然後找到經理的名字. select e1.ename ,e2.ename from emp e1,emp e2 where e1.mgr= e2.empno. empno編號和MGR都是編號. ------------------------------------------------------------------------------------------ 第十15課: SQL1999_table_connections select ename,dname,grade from emp e,dept d, sqlgrade s where e.deptno = d.deptno and e.sql between s.losal and s.hisal and job<>'CLERK'; 有沒有辦法把過濾條件和連線條件分開來? 出於這樣考慮,Sql1999標準推出來了.有許多人用的還是 舊的語法,所以得看懂這種語句. select ename,dname from emp,dept;(舊標準). select ename,dname from emp cross join dept;(1999標準) select ename,dname from emp,dept where emp.deptno=dept.deptno (舊) select ename,dname from emp join dept on(emp.deptno = dept.deptno); 1999標準.沒有Where語句. select ename,dname from emp join dept using(deptno);等同上句,但不推薦使用. select ename,grade from emp e join salgrade s on(e.sal between s.losal and s.hisal); join 連線語句, on過濾條件。連線,條件一眼分開。如果用Where語句較長時,連線語句和過濾語句混在一起。 三張表連線: slect ename,dname, grade from emp e join dept d on(e.deptno=d.deptno) join salgrade s on(e.sal between s.losal and s.hisal) where ename not like '_A%'; 把每張表連線 條件不混在一起,然後資料過濾條件全部區分開來。讀起來更清晰,更容易懂一點。 select e1.ename,e2.ename from emp e1 join emp e2 on(e1.mgr = e2.emptno); 左外連線:會把左邊這張表多餘資料顯示出來。 select e1.ename,e2,ename from emp e1 left join emp e2 on(e1.mgr =e2.empno);left 後可加outer 右外連線:會把右邊這張表多餘資料顯示出來。 select ename,dname from emp e right outer join dept d on(e.deptno =d.deptno); outer可以取掉。 即把左邊多餘資料,也把右邊多餘資料拿出來,全外連線。 select ename,dname from emp e full join dept d on(e.deptno =d.deptno); 16-23 課:求部門平均薪水的等級 A.求部門平均薪水的等級。 select deptno,avg_sal,grade from (select deptno,avg(sal) avg_sal from emp group by deptno)t join salgrade s on(t.avg_sal between s.losal and s.hisal) B.求部門平均的薪水等級 select deptno,avg(grade) from (select deptno,ename, grade from emp join salgrade s on(emp.sal between s.losal and s.hisal)) t group by deptno C.那些人是經理 select ename from emp where empno in(select mgr from emp); select ename from emp where empno in(select distinct mgr from emp); D.不準用組函式,求薪水的最高值(面試題) select distinct sal from emp where sal not in( select distinct e1.sal from emp e1 join emp e2 on (e1.sal<e2.sal)); E.平均薪水最高的部門編號 select deptno,avg_sal from (select avg(sal)avg_sal,deptno from emp group by deptno) where avg_sal= (select max(avg_sal)from (select avg(sal) avg_sal,deptno from emp group by deptno) ) F.平均薪水最高的部門名稱 select dname from dept where deptno= ( select deptno from (select avg(sal)avg_sal,deptno from emp group by deptno) where avg_sal= (select max(avg_sal)from (select avg(sal) avg_sal,deptno from emp group by deptno) ) ) G.求平均薪水的等級最低的部門的部門名稱 組函式巢狀 如:平均薪水最高的部門編號,可以E.更簡單的方法如下: select deptno,avg_sal from (select avg(sal) avg_sal,deptno from emp group by deptno) where avg_sal = (select max(avg(sal)) from emp group by deptno) 組函式最多巢狀兩層 分析: 首先求 1.平均薪水: select avg(sal) from group by deptno; 2.平均薪水等級: 把平均薪水當做一張表,需要和另外一張表連線salgrade select deptno,grade avg_sal from ( select deptno,avg(sal) avg_sal from emp group by deptno) t join salgrade s on(t.avg_sal between s.losal and s.hisal) 上面結果又可當成一張表。 DEPTNO GRADE AVG_SAL -------- ------- ---------- 30 3 1566.66667 20 4 2175 10 4 2916.66667 3.求上表平均等級最低值 select min(grade) from ( select deptno,grade,avg_sal from (select deptno,avg(sal) avg_sal from emp group by deptno)t join salgrade s on(t.avg_sal between s.losal and s.hisa) ) 4.把最低值對應的2結果的那張表的對應那張表的deptno, 然後把2對應的表和另外一張表做連線。 select dname ,deptno,grade,avg_sal from ( select deptno,grade,avg_sal from (select deptno,avg(sal) avg_sal from emp group by deptno)t join salgrade s on(t.avg_sal between s.losal and s.hisal) ) t1 join dept on (t1.deptno = dept.deptno) where t1.grade = ( select deptno,grade,avg_sal from (select deptno,avg(sal) avg_sal from emp group by deptno) t join salgrade s on(t.avg_sal between s.losal and s.hisal) ) ) 結果如下: DNAME DEPTNO GRADE AVG_SAL -------- ------- -------- -------- SALES 30 3 1566.6667 H: 檢視(檢視就是一張表,一個子查詢) G中語句有重複,可以用檢視來簡化。 給scott賦檢視許可權 conn sys/bjsxt as sysdba; grant create table,create view to scott; conn scott/tiger 建立檢視: create view v$_dept_avg-sal_info as select deptno,grade,avg_sal from ( select deptno,avg(sal) avg_sal from emp group by deptno)t join salgrade s on 9t.avg_sal between s.losal and s.hisal) 然後 select * from v$_dept_avg-sal_info 結果如下: DEPTNO GRADE AVG_SAL -------- ------- ---------- 30 3 1566.66667 20 4 2175 10 4 2916.66667 然後G中查詢可以簡化成: select dname,t1.deptno,grade,avg_sal from v$_dept_avg-sal_info t1 join dept on9t1.deptno =dept.deptno) where t1.grade= ( select min(grade) from v$_dept_avg-sal_info t1 ) --------------------------------------------------------------------------------------- 第28-29課:建立表: constraint:後面新增約束 寫欄位後面屬於欄位約束 如名字和郵箱組合不能重複做不到 create table stu ( id number(6) primary key, 主鍵約束 不能為空值 name varchar2(20) constraint stu_name_nn not null, 非空約束 sex number(1), age number(3), sdate date, grade number(2) default 1, class number(4) references class(id),外來鍵約束 email varchar2(50) unique 唯一約束 但是插入空值沒問題 ) 或者 email varchar2(50) unique, constraint stu_id_pk primary key(id), 主鍵約束 constraint stu_class_fk foreign key(本表字段名) references 外表名(外表欄位名), 外來鍵約束 constraint stu_name_email_uni unique(email,name) 表級約束 唯一約束 ------------------------------------------------------------------------------------------ 第30課: 修改表結構 alter table stu add(addr varchar2(100)); 新增欄位 alter table stu modify(addr varchar2(150)); 修改欄位 alter table stu drop(addr); 刪除欄位 alter table drop constraint(stu_class_fk); 刪除約束條件 rollback; 資料恢復 alter table stu add constraint stu_class_fk foreign key(本表字段名) references class(id); 新增新的外來鍵 drop table stu; 刪除表 ------------------------------------------------------------------------------------------ 第32課: 資料字典表 desc user_tables; 查詢使用者下的表的欄位 select table_name from user_tables; 查詢表名 select view_name from user_views; 查詢檢視 select constraint_name,table_name from user_constraints; 查詢約束 desc user_constraints; 約束描述查詢 desc dictionary; 資料字典的名字和描述 select table_name from dictionary; 查詢所有資料字典表 ------------------------------------------------------------------------------------------ 第33課:索引 檢視 -------------------------------------------------------------------------------------- 索引 create index idx_stu_email on stu(email,class)/stu(email); 建立索引(通過索引欄位去查詢,會效率高,但是插入修改時效率不高,反而會低) drop index idx_stu_email; 刪除索引 select index_name from user_indexes; 查詢索引 加主鍵或者唯一約束 會自動建立出索引 如果是欄位組合 會自動建立出組合索引 ------------------------------------------------------------------------------------- 檢視 select view_name from user_views; 查詢檢視 給scott賦檢視建立許可權 conn sys/bjsxt as sysdba; grant create table,create view to scott; conn scott/tiger 建立檢視: create view v$_dept_avg-sal_info as select deptno,grade,avg_sal from ( select deptno,avg(sal) avg_sal from emp group by deptno)t join salgrade s on 9t.avg_sal between s.losal and s.hisal) 然後 select * from v$_dept_avg-sal_info drop view v$_dept_avg-sal_info; 刪除檢視 缺點: 如果表結構改了 檢視也要修改 增加了維護 功能: 1 簡化查詢 2 查詢某些資訊(安全性) 必須有用的時候再去建立檢視 檢視一般只負責查詢 --------------------------------------------------------------------------------------- 第34課:自增 create sequence seq; 建立序列 select sequence seq; 查詢序列 select seq.nextval from dual; insert into article values(seq.nextval,'1','2'); drop sequence seq; 刪除序列 --------------------------------------------------------------------------------------- 第35課:三正規化(實際問題實際分析) 1. 表要有主鍵 列不可分,也不能重複 如姓名 不需要分成姓和名 也不要將姓名和年齡組合為一個列 還有 比如有出生年月不需要再寫年齡列 如果寫了 就屬於重複了 2. 不能存在部分依賴 比如 主鍵是學號和圖書編號組合(2個以上) 那麼姓名依賴與學號 那麼就屬於部分依賴 解決方法 建立第三張表 存學號和圖書編號 但是不儲存姓名圖書名稱等資訊 3. 不能存在傳遞依賴 也就是 除主鍵以外其它欄位全部依賴於主鍵 ---------------------------------------------------------------------------------------- 第38--46課:PLSQL 1. begin dbms_output.put_line('HelloWorld!'); 相當於system.out.print(); end; 不列印 建立 set serveroutput on; 想列印要先啟用 begin dbms_output.put_line('HelloWorld!'); 相當於system.out.print(); end; 2. declare 定義變數 declare v_name varchar2(20); 變數名用v_開頭 begin v_name := 'myname'; dbms_output.put_line(v_name); end; ----------------------------------------- declare v_num number := 0; 變數名用v_開頭 begin v_num := 2/v_num; dbms_output.put_line(v_num); exception 異常處理 when others then dbms_output.put_line('error'); end; 3.變數宣告 declare v_temp number(1); v_count binary_integer := 0; v_sal number(7,2) := 4000.00; v_date date := sysdate; v_pi constant number(3,2) := 3.14; constant 相當於 final 常量 v_valid boolean := false; v_name varchar2(20) not null := 'MyName'; 不能取空值 begin dbms_output.put_line('v_temp value:' || v_temp); || 字串連線符 end; dbms_output.put_line 不能列印boolean值 如果想判斷用if else ---變數宣告的規則 1. 變數名不能夠使用保留字,如from select 等 2. 第一個字元必須是字母 3. 變數名最多包含30個字元 4. 不要與資料庫的表或者列同名 5. 每一行只能宣告一個變數 ---常用變數型別 1. binary_integer: 整數,主要用來計數而不是用來表示欄位型別 2. number:數字型別 3. char:定長字串 4. varchar2:變長字串 5. date:日期 6. long:長字串,最長2GB 7. boolean:布林型別,可以取值為true flase和null值(建議給個值 不要用Null) ---假如宣告變數v_empno number(7,2) 如果表中修改了 那麼宣告也需要修改 如果想讓宣告的根據表中的自動修改 用如下命令: ---變數宣告,使用%type屬性 declare v_empno number(4); v_empno2 emp.empno%type; 1. 表名.欄位名%type; v_empno3 v_empno2%type; 2. 變數名%type; begin dbms_output.put_line('Test'); end; 4. 複合變數(Table變數型別(表示陣列) Record變數型別(類似於java的類)) ---Table變數型別 declare 關鍵字 型別名字type_table_ 型別 由binary_integer作為索引 type type_table_emp_empno is table of emp.empno%type index by binary_integer; v_empnos type_table_emp_empno; 宣告變數 begin v_empnos(0) := 7369; v_empnos(2) := 7839; v_empnos(-1) := 9999; dbms_output.put_line(v_empnos(-1)); end; ---Record變數型別 declare type type_record_dept is record ( deptno dept.deptno%type, dname dept.dname%type, loc dept.loc%type ); v_temp type_record_dept; begin v_temp.deptno := 50; v_temp.dname := 'aaa'; v_temp.loc := 'bj'; dbms_output.put_line(v_temp.deptno || ' ' || v_temp.dname); end; ---如果用以上 那麼表新增欄位 上面需要跟著新增 如何使用表的欄位自動建立 如下 ---使用%rowtype宣告record變數 declare v_temp dept%rowtype; begin v_temp.deptno := 50; v_temp.dname := '111'; v_temp.loc := 'bj'; dbms_output.put_line(v_temp.deptno || ' ' || v_temp.dname); end; 5.PL SQL中使用sql --------------------select--------------------- declare v_ename emp.ename%type; v_sal emp.sal%type; begin; select ename,sal into v_ename,v_sal from emp where empno=7369; dbms_output.put_line(v_ename || ' ' || v_sal); end; 在plsql中 如果使用select,必須返回一條記錄,並且只能返回一條記錄,select裡面必須有into ---plsql中使用%rowtype declare v_emp emp%rowtype; begin; select * into v_emp from emp where empno=7369; dbms_output.put_line(v_emp.ename); end; -------------------insert into----------------------- declare v_deptno dept.deptno%type := 50; v_dname dept.dname%type := 'aaa'; v_loc dept.loc%type := 'bj'; begin insert into dept2 values(v_deptno,v_dname,v_loc); commit; end; ------------------update------------------------------ declare v_deptno emp.deptno%type := 50; v_count number; begin update emp set sal = sal/2 where deptno = v_deptno; select deptno into v_deptno from emp where empno = 7369;有一條被影響 select count(*) into v_count from emp; 也是一條記錄被影響 dbms_output.put_line(sql%rowcount || '條記錄被影響');查詢影響行數 sql為關鍵字 commit; end; 6.ddl begin 固定說明馬上執行 這是兩個單引號 execute immediate 'create table T(nnn varchar2(20) default ''aaa'')'; end; ------------------------if--------------------------- ---取出7369的薪水,如果<1200,則輸出'low',如果<2000則輸出'middle',否則輸出'high' declare v_sal emp.sal%type; begin select sal into v_sal from emp where empno=7369; if(v_sal < 1200) then dbms_output.put_line('low'); elsif(v_sal < 2000) then elsif 要看清。。 dbms_output.put_line('middle'); else dbms_output.put_line('high'); end if; end; -----------------------迴圈-------------------------- 1. 相當於java do while declare i binary_integer := 1; begin loop dbms_output.put_line(i); i := i + 1; exit when(i >= 11); end loop; end; 2. 相當於java while declare j binary_integer := 1; begin while j<11 loop dbms_output.put_line(j); j := j + 1; end loop; end; 3. begin for k in 1..10 loop dbms_output.put_line(k); 列印1---10 end loop; for k int reverse 1..10 loop dbms_output.put_line(k); 列印 10---1 end loop; end; -------------------------------- 7.錯誤處理 declare v_emp number(4); begin select empno into v_temp from emp where deptno = 10; exception when too_many_rows then dbms_output.put_line('有太多記錄'); when others then dbms_output.put_line('error'); end; declare v_temp number(4); begin select empno into v_temp from emp where empno = 222; exception when no_data_found then dbms_output.put_line('沒資料'); end; -----------利用異常表----------- ---建立異常表 create table errorlog ( id number primary key, errcode number, errmsg varchar2(1024), errdate date ); ----建立序列 create sequence seq_errorlog_id start with 1 increment by 1; ---異常使用異常表 declare v_deptno dept.deptno%type := 10; v_errcode number; v_errmsg varchar2(1024); begin delete from dept where deptno = v_deptno; commit; exception when others then rollback; 事務回滾 v_errcode := SQLCODE; v_errmsg := SQLERRM; insert into errorlog values(seq_errorlog_id.nextval,v_errcode,v_errmsg,sysdate); commit; end; ----查詢異常 異常編號都是負數 select * from errorlog; ----查詢日期 select to_char(errdate,'YYYY-MM-DD HH24:M1:SS') from errorlog; ---------------------------------------遊標----------------------------------------------- ----第47--48課 --遊標 declare cursor c is select * from emp; v_emp c%rowtype; begin open c; fetch c into v_emp; dbms_output.put_line(v_emp.ename); close c; end; ---loop迴圈 declare cursor c is select * from emp; v_emp c%rowtype; begin open c; loop fetch c into v_emp; exit when (c%notfound); dbms_output.put_line(v_emp.ename); end loop; close c; end; ---while迴圈 declare cursor c is select * from emp; v_emp emp%rowtype; begin open c; fetch c into v_emp; while(c%fond) loop dbms_output.put_line(v_emp.ename); fetch c into v_emp; end loop; close c; end; --for迴圈 declare cursor c is select * from emp; begin for v_emp in c loop dbms_output.put_line(v_emp.ename); end loop; end --帶引數的遊標 declare cursor c(v_deptno emp.deptno%type, v_job emp.job%type) is select ename,sal from emp where deptno = v_deptno and job = v_job; begin for v_temp in c(30,'CLERK') loop dbms_output.put_line(v_temp.ename); end loop; end; --可更新的遊標 declare cursor c is select * from emp2 for update; begin for v_temp in c loop if(v_temp.sal < 2000) then update emp2 set sal = sal*2 where current of c; elsif(v_temp.sal = 5000) then delete from emp2 where current of c; end if; end loop; commit; end; PL/SQL中用遊標查詢多條記錄 PL/SQL遊標為程式提供了從資料庫中選擇多行資料,然後對每行資料單獨進行處理的方法,它為Oracle提供了一種指示和控制SQL處理的各個階段的方法。我將認為您已經對PL/SQL有一定的瞭解。通過本文,您將學會: 遊標的建立 遊標的處理 定義和使用遊標屬性 一、 什麼是遊標 Oracle使用兩種遊標:顯式遊標和隱式遊標。不管語句返回多少條紀錄,PL/SQL為使用的每一條UPDATE、DELETE和INSERT等SQL命令隱式的宣告一個遊標。(要管理SQL語句的處理,必須隱式的 給它定義一個遊標。)使用者宣告並使用顯示遊標處理SELECT語句返回的多條記錄。顯示的定義遊標一種結構,它使使用者能夠為特定的語句指定記憶體區域,以便以後使用。 二、 遊標的作用 當PL/SQL遊標查詢返回多行資料時,這些記錄組被稱為活動集。Oracle將這種活動集儲存在您建立的顯示定義的已命名的遊標中。Oracle遊標是一種用於輕鬆的處理多行資料的機制,沒有遊標,Oracle開發人員必須單獨地、顯式地取回並管理遊標查詢選擇的每一條記錄。 遊標的另一項功能事,它包含一個跟蹤當前訪問的記錄的指標,這使您的程式能夠一次處理多條記錄。 三、 使用顯示遊標的基本方法 步驟如下: 宣告遊標 開啟遊標 從遊標中取回資料 關閉遊標 1、宣告遊標 宣告遊標的語法如下: DECLARE cursor_name Is SELECT statement 其中,cursor_name是您給遊標指定的名稱;SELECT statement是給遊標活動集返回記錄的查詢。 宣告遊標完成了下面兩個目的: 給遊標命名; 將一個查詢與遊標關聯起來。 值得注意的是,必須在PL/SQL塊的宣告部分宣告遊標;給遊標指定的名稱是一個未宣告的識別符號,而不是一個PL/SQL變數,不能給遊標名稱賦值,也不能將它用在表示式中。PL/SQL塊使用這個名稱來引用遊標查詢。 例:DECLARE CURSOR c1 Is SELECT VIEW_NAME FROM ALL_VIEWS WHERE ROWNUM<=10; 另外還可以在遊標定義語句中宣告遊標的引數,例: CURSOR c1(view _nbr number) Is SELECT VIEW_NAME FROM ALL_VIEWS WHERE ROWNUM<= view _nbr; 遊標引數只對相應的遊標是可見的,不能在遊標範圍之外引用該遊標的引數。如果試圖這樣做,Oracle將返回一個錯誤,指出該變數沒有定義。 2、開啟遊標 開啟遊標的語法如下: OPEN cursor_name; 其中cursor_name是您以前定義的遊標名稱。 開啟遊標將啟用查詢並識別活動集,可是在執行遊標取回命令之前,並沒有真正取回記錄。OPEN命令還初始化了遊標指標,使其指向活動集的第一條記錄。遊標被開啟後,直到關閉之前,取回到活動集的所有資料都是靜態的,換句話說,遊標忽略所有在遊標開啟之後,對資料執行的SQL DML命令(INSERT、UPDATE、DELETE和SELECT)。因此只有在需要時才打開它,要重新整理活動集,只需關閉並重新開啟遊標即可。 3、從遊標中取回資料 FETCH命令以每次一條記錄的方式取回活動集中的記錄。通常將FETCH命令和某種迭代處理結合起來使用,在迭代處理中,FETCH命令每執行一次,遊標前進到活動集的下一條記錄。 FETCH命令的語法: FETCH cursor_name INTO record_list; 其中,cursor_name是前面定義的遊標的名稱;record_list是變數列表,它接受活動集中的列。FETCH命令將活動集的結果放置到這些變數中。 執行FETCH命令後,活動集中的結果被取回到PL/SQL變數中,以便在PL/SQL塊中使用。每取回一條記錄,遊標的指標就移向活動集的下一條記錄。 例: FETCH C1 INTO VNAME; WHILE C1%FOUND LOOP DBMS_OUTPUT.PUT_LINE(TO_CHAR(C1%ROWCOUNT)||' '||VNAME); END LOOP; 其中,使用屬性'%FOUND'使得當FETCH到達活動集的結尾時,不會引發異常。其它屬性及含義見下表: 屬性 含量 %FOUND 布林型屬性,當最近一次該記錄時成功返回,則值為TRUE %NOTFOUND 布林型屬性,它的值總與%FOUND屬性的值相反 %ISOPEN 布林型屬性,當遊標是開啟時返回TRUE %ROWCOUNT 數字型屬性,返回已從遊標中讀取的記錄數 屬性 含量 %FOUND 布林型屬性,當最近一次該記錄時成功返回,則值為TRUE %NOTFOUND 布林型屬性,它的值總與%FOUND屬性的值相反 %ISOPEN 布林型屬性,當遊標是開啟時返回TRUE %ROWCOUNT 數字型屬性,返回已從遊標中讀取的記錄數 4、關閉遊標 CLOSE語句關閉以前開啟的遊標,使得活動集不確定。當用戶的程式或會話結束時,Oracle隱式關閉遊標。遊標被關閉後,就不能對它執行任何操作了,否則將引發異常。 CLOSE語句的語法是: CLOSE cursor_name; 其中,cursor_name是以前開啟的遊標的名稱。 完整的程式程式碼如下: DECLARE CURSOR C1 IS SELECT VIEW_NAME FROM ALL_VIEWS WHERE ROWNUM<=10 ORDER BY VIEW_NAME; VNAME VARCHAR2(40); BEGIN OPEN C1; FETCH C1 INTO VNAME; WHILE C1%FOUND LOOP DBMS_OUTPUT.PUT_LINE(TO_CHAR(C1%ROWCOUNT)||''||VNAME); END LOOP; END; ……CLOSE C1; 四、 小結 遊標是一種結構,能夠以一次一條記錄的方式處理多行查詢的結果.為每條DML語句建立隱式遊標,而顯式遊標是由使用者建立的,以便處理返回多條記錄的查詢。而且,通過消除反覆地分析程式碼,遊標提高了程式碼的處理速度。 ------------------------------儲存過程--------------------------------- ---第49--50課 --建立儲存過程 執行如果有錯誤會提示 建立的儲存過程帶有編譯錯誤 但是不提示哪有錯誤 如果想檢視 執行show error即可 create or replace procedure p ---這裡相當於declare is cursor c is select * from emp2 for update; begin for v_temp in c loop if(v_temp.sal < 2000) then update emp2 set sal = sal*2 where current of c; elsif(v_temp.sal = 5000) then delete from emp2 where current of c; end if; end loop; commit; end; select * from emp2; ---執行儲存過程 begin p; end; exec p; ---執行儲存過程 ---帶引數的儲存過程 ---建立儲存過程 create or replace procedure p (v_a in number, v_b number, v_ret out number, v_temp in out number) ---第一個為傳入引數 第三個為傳出引數 第四個為傳入傳出引數 is begin if(v_a>v_b) then v_ret := v_a; else v_ret := v_b; end if; v_temp := v_temp + 1; end; --定義變數 declare v_a number := 3; v_b number := 4; v_ret number; v_temp number := 5; ---執行儲存過程 begin p(v_a,v_b,v_ret,v_temp); dbms_output.put_line(v_ret); dbms_output.put_line(v_temp); --函式 ---建立函式 create or replace function sal_tax (v_sal number) return number is begin if(v_sal < 2000) then return 0.10; elsif(v_sal < 2750) then return 0.15; else return 0.20; end if; end; --執行函式 select sal_tax(sal) from emp; ----------------------觸發器---------------- create table emp2)log ( uname varchar2(20), action varchar2(10), atime date ); ---建立觸發器 create or replace trigger trig after insert or delete or update on emp2 for each row begin if inserting then insert into emp2_log values(USER,'insert',sysdate); elsif updating then insert into emp2_log values(USER,'update',sysdate); elsif deleting then insert into emp2_log values(USER,'delete',sysdate); end if; end; ---刪除觸發器 drop trigger trig; create or replace trigger trig after update on dept for each row begin update emp set deptno = :NEW.deptno where deptno = :OLD.deptno; end; --有了這個觸發器 就可以執行 update emp set deptno=10 where deptno=99; 先出發觸發器才檢查約束條件 select * from emp; rollback; ------------樹狀結構展示------------ ---第52---53課 drop table article; create table article ( id number primary key, cont varchar2(4000), pid number, isleaf number(1),--0代表非葉子節點,1代表葉子節點 alevel number(2) ); insert into article values(1,'螞蟻大戰大象',0,0,0); insert into article values(2,'大象被打趴下了',1,0,1); insert into article values(3,'螞蟻也不好過',2,1,2); insert into article values(4,'瞎說',2,0,2); insert into article values(5,'沒有瞎說',4,1,3); insert into article values(6,'怎麼可能',1,0,1); insert into article values(7,'怎麼沒有可能',6,1,2); insert into article values(8,'可能性是很大的',6,1,2); insert into article values(9,'大象進醫院了',2,0,2); insert into article values(10,'護士是螞蟻',9,1,3); commit; 螞蟻大戰大象 大象被打趴下了 螞蟻也不好過 瞎說 沒有瞎說 大象進醫院了 護士是螞蟻 怎麼可能 怎麼沒有可能 可能性是很大的 ----------------使用儲存過程展示樹狀結構------------- create or replace procedure p (v_pid article.pid%type) is cursor c is select * from article where pid = v_pid; begin for v_article in c loop dbms_output.put_line(v_article.cont); if(v_article.isleaf = 0) then p (v_article.id); end if; end loop; end; ---以上寫法 順序會輸出正確 但是沒有縮排 create or replace procedure p (v_pid article.pid%type, v_level binary_integer) is cursor c is select * from article where pid = v_pid; v_preStr varchar2(1024) := ''; begin for i in 1..v_level loop v_preStr := v_preStr || '*****'; ----如果使用空格 貌似會自動消除 end loop; for v_article in c loop dbms_output.put_line(v_preStr || v_article.cont); if(v_article.isleaf = 0) then p (v_article.id, v_level + 1); end if; end loop; end; ---以上寫法可以實現縮排