日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

大型数据库

發布時間:2025/3/15 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 大型数据库 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

over(order by salary) 按照salary排序進行累計,order by是個默認的開窗函數

over(partition by deptno)按照部門分區

?

?

如何使用Oracle Round 函數 (四舍五入)
描述 : 傳回一個數值,該數值是按照指定的小數位元數進行四舍五入運算的結果。
SELECT ROUND( number, [ decimal_places ] ) FROM DUAL
參數:
number : 欲處理之數值
decimal_places : 四舍五入 , 小數取幾位 ( 預設為 0 )
Sample :
select round(123.456, 0) from dual; 回傳 123
select round(123.456, 1) from dual; 回傳 123.5

?

ratio_to_report主要完成對百分比的計算,語法為
ratio_to_report(exp) over()
也就是根據over窗口函數的作用區間,求出作用區間中的單個值在整個區間的總值的比重
比如要求scott用戶下emp表中每個員工的工資占本部門的比重
select ename,sal,deptno,ratio_to_report(sal) over(partition by deptno) ratio from emp;

?

select deptno,

ename,

sal,

sum(sal) over (partition by deptno order by sal, ename) cum_sal,

round(100*ratio_to_report(sal) over (partition by deptno), 1) pct_dept,

round(100*ratio_to_report(sal) over (), 1) pct_over_all

from emp order by deptno, sal;

?

?

Oracle 的體系結構

?

Oracle的服務由數據庫和實例組成

?

實例就是一組操作系統進程(或者是一個多線程的進程)和一些內存,這些進程可以操作數據庫。數據庫只是一個文件集合(包括數據文件、控制文件、重做日志文件)。

實例可以在任何時間點裝載和打開一個數據庫。實際上,準確地講,實例在其整個生存期中最多能裝載和打開一個數據庫!

連接數據庫實例: 建立用戶連接和創建會話

?

?

?

物理存儲結構包括存儲在磁盤上的數據文件、控制文件、重做日志文件

?

內存結構:SGA和PGA

SGA:System Global Area是Oracle Instance的基本組成部分,在實例啟動時分配;系統全局域SGA主要由三部分構成:共享池、數據緩沖區、日志緩沖區等包括兩個可選的(大型池和java池)。

SGA_MAX_SIZE指的是可動態分配的最大值﹐而SGA_TARGET是當前已分配的最大SGA。

?

共享池:Shared Pool用于緩存最近被執行的SQL語句和最近被使用的數據定義,主要包括:Library cache(共享SQL區)和Data dictionary cache(數據字典緩沖區)。? 共享SQL區是存放用戶SQL命令的區域,數據字典緩沖區存放數據庫運行的動態信息。內存大小由參數SHARED_POOL_SIZE指定。Library cache(共享SQL區)存儲了最近使用的SQL和PL/SQL語句。數據字典緩沖區是最近在數據庫中使用的定義的集合。

緩沖區高速緩存:Database Buffer Cache用于緩存從數據文件中檢索出來的數據塊,可以大大提高查詢和更新數據的性能。塊的大小由參數DB_BLOCK_SIZE決定。

重做日志緩沖區:redo log buffer cache 記錄了在數據庫數據塊中做的所有改變。

大型池:Large Pool是SGA中一個可選的內存區域,它只用于shared server環境。

Java池:Java Pool為Java命令的語法分析提供服務。

?

PGA:Process Global Area是為每個連接到Oracle database的用戶進程保留的內存。

?

?

進程是操作系統中的一種機制,它可執行一系列的操作步。

Oracle進程中有三類:用戶進程,服務進程,后臺進程

用戶進程: 當用戶請求連接oracle服務時啟動。它必須首先建立一個連接,它不能和oracle 服務直接交互。

?

服務進程:可以直接和oracle 服務進行交互。

?

后臺進程:

DBWR??數據庫寫入程序

該進程執行將緩沖區寫入數據文件,是負責緩沖存儲區管理的一個OR

ACLE后臺進程。

?

?

?

?

LGWR?日志寫入程序?

該進程將日志緩沖區寫入磁盤上的一個日志文件,它是負責管理日志

緩沖區的一個ORACLE后臺進程。

在數據庫寫入程序之前

?

?

SMON?系統監控

該進程實例啟動時執行實例恢復,還負責清理不再使用的臨時段。

?

?

PMON??進程監控

該進程在用戶進程出現故障時執行進程恢復,負責清理內存儲區和釋

放該進程所使用的資源。

?

CKPT?檢查點?

該進程在檢查點出現時,對全部數據文件的標題進行修改,指示該檢

查點。

使用檢查點的原因:

檢查點確保在內存中頻繁改變的數據塊可以正常的寫入數據文件

可以快速的進行實例的恢復

?

ARCH?歸檔

該進程將已填滿的在線日志文件拷貝到指定的存儲設備。當日志是為

ARCHIVELOG使用方式、并可自動地歸檔時ARCH進程才存在。?

Oracle的邏輯結構表明了數據庫的物理結構是如何被使用的

數據庫->表空間->段->區->數據塊

?

表空間:

保留相關數據庫對象的組

Oracle數據庫中典型表空間包括

SYSTEM表空間

DATA表空間

USER表空間

TOOLS表空間

TEMP表空間

?

數據庫的控制空間分配

為數據庫用戶設置空間配額

備份或恢復數據

?

段:定義為分配給邏輯數據庫結構的擴展區集合

不同類型的段:

數據段

索引段

回滾段

臨時段

?

?

?

?

?

?

?

模式:所謂模式是指一系列邏輯數據結構或對象的集合。

模式與用戶相對應,一個模式只能被一個數據庫用戶所擁有,并且模式的名稱和用戶的名稱相同。

Oracle數據庫中并不是所有的對象都是模式對象。表,索引,約束,索引,視圖,序列,存儲過程,同義詞,用戶自定義數據結構,數據庫連接。而表空間,用戶,角色,目錄,概要文件及上下文等數據庫對象不屬于任何模式,稱為非模式對象。

?

?

Oracle語句的處理過程

解析->優化->行資源生成->執行

解析:對提交的語句進行語法和語義檢查

將已經提交的語句分解,判定屬于那種類型,并在其上執行各種檢驗操作

語法檢查:正確表述,符合SQL規則

語義檢查:正確應用SQL對象?授權?歧義?

檢查Shared Pool:已被其他Session處理過

?

優化:生成一個可在oracle中用來執行語句的最佳計劃

行資源生成:為回話取得最佳計劃和建立執行計劃

執行:完成實際執行查詢的行資源生成步驟的輸出

?

存儲在常規表中行采用沒有特定的次序存儲

Oracle將獲取的名字與ROWID進行關聯。ROWID是表中行的物理地址,可以告知對象的來源,所處的文件以及文件中特定數據塊。

?

?

?

Oracle常用的有兩種索引類型:B樹索引和位圖索引

B樹索引:B樹索引是最常用的索引,它的存儲結構類似于書的目錄索引結構,有分支節點和葉子節點,分支節點相當于書的大目錄,葉子節點相當于具體到頁的索引。B樹索引是oracle數據庫的默認索引類型。

只有幾個不同的值供選擇。例如,一個"類型"列中,只有四個不同的值(A,B,C,和D)。該索引是一個低效的選擇。如果你有一個Oracle數據庫,那么為這些選擇范圍小的的列建立位圖索引是更好的選擇。

?

?

?

數據庫啟動和關閉

為了滿足數據庫管理的需要,Oracle數據庫的啟動和關閉是分步驟進行的

STARTUP

ALTER DATABASE db01 MOUNT

ALTER DATABASE db01 READ ONLY

STARTUP RESTPICT
ALTER SYSTEM ENABLE RESTRICTED SESSION

?

?

?

?

?

?

?

?

?

當數據庫被創建的時候,oracle 服務在數據文件創建額外的對象結構

數據字典表

動態性能表

?

Oracle數據字典是由表和視圖組成,存儲有關數據庫結構信息的一些數據庫對象。

數據字典按照存在的形式分為數據字典表和數據字典視圖。

數據字典

基表是存儲有關數據庫的信息的底層表。基表是在任何 Oracle 數據庫中首先創建的對象。在使用 CREATE DATABASE 創建數據庫時,只要 Oracle 服務器運行 sql.bsq 腳本,就會自動創建這些對象。

數據字典視圖

數據字典視圖是基表的匯總,可以更有效地顯示基表信息。

?

?

?

數據字典內容包括:

1,數據庫中所有模式對象的信息,如表、視圖、簇、索引、集群、同義詞、序列、過程、方法、包、觸發器等。

2,分配多少空間,當前使用了多少空間等。

3,列的缺省值。

4,約束信息的完整性。

5,Oracle用戶的名字。

6,用戶及角色被授予的權限。

7,用戶訪問或使用的審計信息。

8,其它產生的數據庫信息。

?

?

數據字典有三個主要的用途

Oracle服務器使用它來發現關于使用者,模式對象,存儲結構的信息。

Oracle 服務器修改它當DDL語句執行時。

用戶和DBAs可以把它當作只讀表來查看數據庫的信息。

?

?

?

?

?

為了便于用戶對數據字典表的查詢, Oracle對這些數據字典都分別建立了用戶視圖,這樣即容易記住,還隱藏了數據字典表表之間的關系,Oracle針對這些對象的范圍,分別為:

DBA:所有方案中的視圖(可以看到所有數據字典里的信息)

ALL:用戶可以訪問的視圖(可以看到所有這個用戶可以看到的信息)

USER:用戶方案中的視圖(僅僅是這個用戶擁有的信息)

三者直接的關系:

?

?

動態性能視圖記錄當前數據庫的活動

只要數據庫正在操作視圖就會持續的更新

信息是從內存和控制文件中獲得的

DBAs使用動態視圖來監視和調整數據庫

SYS 用戶才能使用動態視圖

不允許有DML操作

?

在oracle數據庫中,用戶權限分為下列兩個類

系統權限

允許用戶在數據庫中執行特定的操作

對象權限

允許用戶讀取和操作特定的對象

?

總共有超過100個不同的系統權限

ANY關鍵字 可以擁有所有的權限

GRANT關鍵字 可以增加權限

REVOKE關鍵字 回收權限

?

Eg:GRANT CREATE SESSION TO emi;

????GRANT CREATE SESSION TO emi WITH ADMIN OPTION;

只用授權時帶有WITH ADMIN OPTION 子句時,用戶才可以將獲得的系統權限再授予其他用戶,即系統權限的傳遞性。

?

系統權限的回收

REVOKE CREATE TABLE FROM emi;

不管師是否有 WITH ADMIN OPTION,它都不會產生連級的影響

?

?

對象權限

回收對象權限使用WITH GRANT OPTION將會有連級的影響。

?

?

?

角色

角色的好處

更簡單的權限管理

動態的權限管理

選擇可供使用的權限

可以通過操作系統授權

提高性能

?

Eg:CREATE ROLE oe_clerk;

ALTER ROLE oe_clerk IDENTIFIED BY order;

????GRANT oe_clerk TO scott;

ALTER USER scott DEFAULT ROLE hr_clerk,oe_clerk

CREATE ROLE admin role IDENTIFIED USING hr.employee

????SET ROLE hr_clerk;

????SET ROLE oe_clerk IDENTIFIED BY order;

????REVOKE oe_clerk FROM scott;

????REVOKE hr_manager FROM PUBLIC;

????DROP ROLE hr_manager;

?

?

Oracle提供的語句

條件語句

CASE 表達式

?

CASE expr WHEN comparison_expr1 THEN return_expr1

[WHEN comparison_expr2 THEN return_expr2

WHEN comparison_exprn THEN return_exprn

ELSE else_expr]

END

?

DECODE 函數

decode(條件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值)

該函數的含義如下:
IF 條件=值1 THEN
    RETURN(翻譯值1)
ELSIF 條件=值2 THEN
    RETURN(翻譯值2)
    ......
ELSIF 條件=值n THEN
    RETURN(翻譯值n)
ELSE
    RETURN(缺省值)
END IF
decode(字段或字段的運算,值1,值2,值3)

?????? 這個函數運行的結果是,當字段或字段的運算的值等于值1時,該函數返回值2,否則返回值3
當然值1,值2,值3也可以是表達式,這個函數使得某些sql語句簡單了許多

使用方法:
1、比較大小
select decode(sign(變量1-變量2),-1,變量1,變量2) from dual; --取較小值
sign()函數根據某個值是0、正數還是負數,分別返回0、1、-1
例如:
變量1=10,變量2=20
則sign(變量1-變量2)返回-1,decode解碼結果為"變量1",達到了取較小值的目的。

?

?

?

?

Merge命令

通過這個merge你能夠在一個SQL語句中對一個表同時執行inserts和updates操作. 當然是update還是insert是依據于你的指定的條件判斷的,Merge into可以實現用B表來更新A表數據,如果A表中沒有,則把B表的數據插入A表. MERGE命令從一個或多個數據源中選擇行來updating或inserting到一個或多個表

merge into products p using newproducts np on (p.product_id = np.product_id)
when matched then
update set p.product_name = np.product_name
when not matched then
insert values(np.product_id, np.product_name, np.category)

?

TRUNC(number,num_digits)

Number 需要截尾取整的數字。

Num_digits 用于指定取整精度的數字。Num_digits 的默認值為 0。

?

?

Read Consistency(讀一致性)

?

?

?

?

?

?

?

?

?

?

集合類型 ?

?

使用條件:

?? a. 單行單列的數據,使用標量變量 。
?? b. 單行多列數據,使用記錄
?? c. 單列多行數據,使用集合

?????? *集合:類似于編程語言中數組也就是。pl/sql集合類型包括關聯數組Associative array(索引表 pl/sql table)、嵌套表(Nested Table)、變長數組(VARRAY)。

?

Nested table與VARRY既可以被用于PL/SQL,也可以被直接用于數據庫中,但是Associative array不行

Associative array是不能通過CREATE TYPE語句進行單獨創建,只能在PL/SQL塊(或Package)中進行定義并使用(即適用范圍是PL/SQL Block級別)

Nested table與VARRAY則可以使用CREATE TYPE進行創建(即適用范圍是Schema級別),它們還可以直接作為數據庫表中列的類型

?

數字有三種基本類型:

NUMBER可以描述整數或實數

PLS_INTEGER和BINARY_INTENER只能描述整數

NUMBER,是以十進制格式進行存儲的,但在計算中系統會自動轉換成為二進制進行運算。例如:NUMBER(5,2)可以用來存儲表示-999.99...999.99間的數值

BINARY_INTENER用來描述不存儲在數據庫中,但是需要用來計算的帶符號的整數值。它以2的補碼二進制形式表述。循環計數器經常使用這種類型。

PLS_INTEGER和BINARY_INTENER唯一區別:

在計算當中發生溢出時,BINARY_INTENER型的變量會被自動指派給一個NUMBER型而不會出錯,PLS_INTEGER型的變量將會發生錯誤

?

DECLARE
????TYPE ib_planguage IS TABLE OF VARCHAR2(10) INDEX BY PLS_INTEGER;
????lang ib_planguage;
????idx PLS_INTEGER;
BEGIN
????lang(1):='java';
????lang(9):='c#';
????lang(3):='c++';
????idx:=lang.FIRST;
????WHILE(idx IS NOT NULL) LOOP
????????DBMS_OUTPUT.PUT_LINE(lang(idx));
????????idx:=lang.NEXT(idx);
????END LOOP;
END;

?

與Associative array不同,Nested table變量需要顯式初始化。Nested table初始化之后還需要調用EXTEND過程,擴展集合的"容量"

DECLARE

????TYPE nt_planguage IS TABLE OF VARCHAR2(10);

????lang nt_planguage;
BEGIN
????lang:=nt_planguage('java','c#','c++');
????FOR i IN 1..lang.COUNT LOOP
????????DBMS_OUTPUT.PUT_LINE(lang(i));
????END LOOP;
END;

?

?

VARRAY可以在聲明時限制集合的長度。其索引總是連續的,而Nested table的索引在初始化賦值時是連續的,不過隨著集合元素被刪除,可能變得不連續

DECLARE

????TYPE va_planguage IS VARRAY(8) OF VARCHAR2(10);

????lang va_planguage;
BEGIN
????lang:=va_planguage('java','c#','c++');
????FOR i IN 1..lang.COUNT LOOP
????????DBMS_OUTPUT.PUT_LINE(lang(i));
????END LOOP;
END;

?

首選是Associative array,因為它不需要初始化或者EXTEND操作,并且是迄今為止最高效的集合類型。唯一不足的一點是它只能用于PL/SQL而不能直接用于數據庫。

如果你需要允許使用負數索引,應該選擇Associative array;

如果你需要限制集合元素的個數,應該選擇VARRAY

?

?

?

DUAL表

dual是一個虛擬表,用來構成select的語法規則

select user from dual;

select to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss') from dual;--獲得當前系統時間

select SYS_CONTEXT('USERENV','TERMINAL') from dual;--獲得主機名

select SYS_CONTEXT('USERENV','language') from dual;--獲得當前 locale

select dbms_random.random from dual;--獲得一個隨機數

select your_sequence.nextval from dual;--獲得序列your_sequence的下一個值

select your_sequence.currval from dual;--獲得序列your_sequence的當前值

select 7*9 from dual; --用做計算器

?

?

ASCII 返回與指定的字符對應的十進制數

CHR 給出整數,返回對應的字符

CONCAT 連接兩個字符串

INITCAP 返回字符串并將字符串的第一個字母變為大寫

INSTR(C1,C2,I,J) 在一個字符串中搜索指定的字符,返回發現指定的字符的位置

LENGTH 返回字符串的長度

LOWER 返回字符串,并將所有的字符小寫

UPPER 返回字符串,并將所有的字符大寫

RPAD和LPAD 粘貼字符

ADD_MONTHS增加或減去月份

LAST_DAY 返回日期的最后一天

MONTHS_BETWEEN 給出date2-date1的月份

?

?

PL/SQL基礎

?

概述:

PL/SQL是Oracle對SQL的一種擴充,集成了程序化設計語言中的許多特性

PL/SQL的特點

過程化和模塊化

使用過程化語言的控制結構

錯誤處理

可移植性

集成

改善性能

支持所有的事物控制命令

支持所有SQL的DML命令

支持所有SQL的DDL命令

支持所有SQL的DCL命令

支持所有SQL的數據類型、函數、各種運算符

PL/SQL程序塊可以存儲在服務器中,被其他程序或SQL命令調用

對PL/SQL程序塊可以進行權限管理

?

?

PL/SQL中的Select語句

SELECT 列名,列名 . . . INTO 變量1,變量2 . . .

FROM 表 WHERE 條件 . . . ;

在使用SELECT …INTO…時,結果只能有一條,如果返回了多條數據或沒有數據,則將產生錯誤。(對于多條記錄的遍歷,可以使用游標)

?

PL/SQL程序結構

  • PL/SQL程序的單元由邏輯塊(BLOCK)組成
    • 塊可以順序出現,也可以相互嵌套
    • 每一個塊分成三部分

[DECLEAR]

????-- 說明部分(可選的)

BEGIN

????-- 語句執行部分(必需的)

[EXCEPTION]

????-- 出錯處理程序(可選的)

END ;

/

?

PL/SQL類型

無名塊:嵌入在應用內或交互式發出的無名塊

有名塊(應用的過程、函數):可以接受參數,并返回結果的有名塊,存儲在應用程序中。可以被反復調用。

存儲過程、函數:可以接受參數,并返回結果的有名塊,存儲在服務器端。可以被反復調用

包:有名的PL/SQL模塊,是相關的過程、函數、標識符的集合。存儲在服務器端。可以被反復調用。

數據庫出發器:與數據庫表相關的PL/SQL塊,存儲在服務器端。在客戶與服務器觸發事件發生時自動觸發。

應用觸發器:與一個應用事件相關的PL/SQL塊,存儲在服務器端。在應用程序的觸發事件時自動觸發。

?

?

變量定義

變量 [CONSTANT] 數據類型 [NOT NULL] [:= DEFAULT PL/SQL 表達式];

V_num????????number(2)????????:= 12 ;

沒有賦初值的變量,初值都是NULL

?

變量類型

%TYPE和%ROWTYPE 類型

%TYPE:表示已經定義的變量類型定義

%ROWTYPE:表示已經定義的表、視圖中的紀錄的類型或游標的結構類型

優點

不必了解數據庫中列的個數和數據類型

如果表結構改變,PL/SQL程序可以不變,減少程序的維護工作

V_EMPNO ????EMP.EMPNO%TYPE; /*EMP表名,EMPNO列名*/

V_REC????????EMP%ROWTYPE; /*EMP可以是表名或游標名*/

?

?

用戶定義的類型

create or replace type student_type as object(

????id????????number(5) ,

????firstname????varchar2(20) ,

????lastname????varchar2(20) ,

????major????????varchar2(30) ,

????current_credits????number(3));

????v_stu????????student_type ;

?

?

變量賦值

變量名:=常量 或 PL/SQL表達式

可在說明部分賦值,也可在執行部分賦值

DECLEAR

????num_var????number(5):=5; /*說明部分賦值*/

????v_emp????????emp%rowtype;

BEGIN

????v_emp.empno := 11011 ;???? /*執行部分賦值*/

????……

  select sal into num_var from emp where empno = 7788 ;

?

?

變量的作用范圍

變量如果不在子塊中重新定義,則在PL/SQL塊的所有子塊中有效

?

如果變量在子塊內重新定義,子塊內定義的變量優先,此變量的作用范圍僅在本子塊內有效。

?

如果主塊中的變量A和子塊變量A中同時定義時,在子塊中要用主塊的變量A時,必須在變量前加塊的標識符(如:塊的標識符.A)。

?

常用內置函數

函數 說明 轉換前的類型

TO_CHAR 轉換成VARCHAR類型 數字型、日期型

TO_DATE 轉換成DATE 字符型

TO_NUMBER 轉換成number類型 字符型

?

SELECT TO_CHAR (current_credits) INTO v_1 FROM student2 WHERE id = 1002

?

?

條件語句:

IF語句

DECLARE

????v_sal????emp.sal%type ;

BEGIN

????SELECT sal INTO v_sal FROM emp WHERE empno = 7788;

????IF v_sal < 500 THEN

????????UPDATE emp SET sal = sal * 1.5 WHERE empno = 7788;

????ELSIF v_sal < 1500 THEN

????????UPDATE emp SET sal = sal * 1.3 WHERE empno = 7788;

????ELSE

????????UPDATE emp SET sal = sal * 1.0 WHERE empno = 7788;

????END IF;

????COMMIT;

END;

/

<條件>是一個布爾型變量或表達式,取值只能是TRUE/FALSE/NULL

?

CASE語句:
CASE ????

????WHEN grade= 'A' THEN dbms_output.put_line('excellent');

????WHEN grade= 'B' THEN dbms_output.put_line('very good');

????WHEN grade= 'C' THEN dbms_output.put_line('good');

????WHEN grade= 'D' THEN dbms_output.put_line('fair');

????WHEN grade= 'F' THEN dbms_output.put_line('poor);

????ELSE dbms_output.put_line(' no such grade');

END CASE;

?

?

循環語句

Loop語句

DECLARE

????v_counter number :=1;

BEGIN

????LOOP

???? INSERT INTO temp_table VALUES(v_counter, 'loop index') ;

???? v_counter := v_counter + 1;

???? IF v_counter > 50 THEN

????????exit

???? END IF;

????END LOOP;

END;

/

?

?

WHILE語句

DECLARE

????v_counter number := 1 ;

BEGIN

????WHILE v_counter <= 50 LOOP

????????INSERT INTO temp_table VALUES(v_counter, 'loop_index');

????????v_counter := v_counter + 1 ;

????END LOOP;

END;

/

?

FOR語句

DECLARE

????????v_counter number :=1 ;

BEGIN

????FOR v_counter IN 1..50 LOOP

????????INSERT INTO temp_table VALUES(v_counter,'loop index');

????END LOOP ;

END;

/

FOR v_counter IN REVERSE 1..50 LOOP

其中:IN:表示索引變量的值小到大 IN REVERSE:表示索引變量的值從大到小

?

?

GOTO語句

DECLARE

????v_vonter number := 1;

BEGIN

????LOOP

????????INSERT INTO temp_table VALUES(v_counter, 'loop count');

????????v_counter := v_counter + 1 ;

????????IF v_counter > 50 THEN

????????????GOTO ENDOFLOOP ;

????????END IF ;

????END LOOP ;

????<<ENDOFLOOP>>

????????INSERT INTO temp_table(char_col) VALUES('done!') ;

END;

?

對于塊、循環或IF語句而言,想要從外層跳到內層是非法的

從一個IF子句調轉到IF的另一個子句中是非法的

出錯處理塊不能實行跳轉

?

?

?

異常處理

一個PL/SQL塊的出錯處理(EXCEPTION)部分包含程序處理多個錯誤的代碼。當一個錯誤發生時,程序控制離開PL/SQL塊的執行部分轉移到出錯處理部分。

. . .

BEGIN

. . .

EXCEPTION

????WHEN 錯誤1 [ OR 錯誤2 ] THEN 語句序列 1 ;

????WHEN 錯誤3 [ OR 錯誤4 ] THEN 語句序列 2 ;

????. . .

????WHEN OTHERS THEN 語句序列 3 ;

END ;

?

?

系統預定義錯誤 :在PL/SQL中經常出現的25個系統定義的錯誤,不必定義,允許服務器隱式地出發它們,只需要在出錯處理部分處理它們

用戶自定義錯誤:開發者認為是非正常的一個條件,必須在說明部分定義,在執行部分顯示觸發它們,在出錯處理部分處理它們。

?

異常代碼 異常名稱 說明

ORA-01403 NO_DATA_FOUND 查詢沒有返回數據

ORA-01422 TOO_MANY_ROWS SELECT….INTO 語句返回多行結果

DECLARE

????v_comm emp.comm%type ;

BEGIN

????SELECT????comm????INTO????v_comm

????FROM????emp????WHERE????empno = 7788 ;

EXCEPTION

????WHEN no_data_found THEN

????????????dbms_output.put_line( 'no data ! ' ) ;

????WHEN too_many_rows THEN

????????????dbms_output.put_line( 'too many row ! ' ) ;

????WHEN others THEN

????????????null ;

END ;

?

?

用戶自定義的錯誤有三個步驟:定義錯誤,觸發錯誤,處理錯誤

DECLARE

????e_toomanystudent???? exception;  /*定義錯誤*/

????v_currentstudent????????number(3);

????v_maxstudent????????number(3);

????v_errorcode????????number;

????v_errortext????????varchar2(200);

BEGIN????

SELECT current_student , max_students INTO

????v_currentstudent , v_maxstudent

FROM classe????WHERE department = 'HIS' and course = 101 ;

IF v_currentstudent > v_maxstudent THEN

????RAISE????e_toomanystudent ;     /*觸發錯誤*/

END IF ;

EXCEPTION

?

?

WHEN no_data_found or too_many_rows THEN

????dbms_output.putline('發生系統預定義錯誤') ;

WHEN e_toomanystudent THEN????????/*處理錯誤*/

????INSERT INTO log_table(info)

????VALUES('history 101 has' || v_currentstudent);

WHEN others THEN

????v_errorcode = sqlcode ;

????v_errortext = substr(sqlerrm,1,200)

????INSERT INTO log_table(code , message , info )

????VALUES(v_errorcode , v_errortext ,'Oracle error occured');

END ;

/

?

?

?

游標

游標是一個指向內存區域的指針,一個PL/SQL結構

游標有兩種類型:顯示游標和隱式游標

顯示游標:是由程序員定義和命名的,并且在塊的執行部分中通過特定語句操作的內存工作區。

隱式游標:是由PL/SQL為DML語句和SELECT語句隱式定義的工作區

?

?

顯示游標的處理步驟

?

游標是一個不含INTO子句的SELECT語句

SELECT語句允許帶WHERE,ORDER BY,GROUP BY等子句。

游標的定義

DECLARE

CURSOR emp_cursor IS

SELECT empno, ename

???? FROM emp;

CURSOR dept_cursor IS

SELECT *

FROM dept

WHERE deptno = 10;

BEGIN

...

?

打開游標

OPEN 游標名;

?

游標的處理

FETCH游標名INTO????[變量1, 變量2, ...]| 紀錄名];

FETCH emp_cursor INTO v_empno, v_ename;

?

DECLARE

???? CURSOR c_classes IS SELECT * FROM class;

v_classes c_classes%rowtype ;

BEGIN

???? . . .

OPEN c_classes;

FETCH c_classes INTO v_classes ;

. . .

END;

/

?

完成對行數據處理后,可以關閉游標,如果需要,還可以再次打開游標,關閉游標后,系統釋放與該游標關聯的資源,不能再對游標進行FETCH操作。

CLOSE????????c_classes;

?

顯示游標的一些屬性

%ISOPEN,%NOTFOUND,%FOUND,%ROWCOUNT

%ROWCOUNT Number 值是當前為止返回的記錄數,初值為0,每取一條記錄,該屬性值加1。

?

LOOP

FETCH emp_cursor INTO v_ename , v_sal;

EXIT WHEN emp_cursor%ROWCOUNT>5 or emp_cursor%NOTFOUND;

...

END LOOP;

?

?

DECLARE

v_deptno emp.deptno%type :=&p_deptno;

v_ename emp.ename%type;

v_sal emp.sal%type;

CURSOR emp_cursor IS SELECT ename ,sal FROM emp

????????????????????????????????WHERE deptno = v_deptno;

BEGIN

OPEN emp_cursor;

LOOP

FETCH emp_cursor INTO v_ename , v_sal;

EXIT WHEN emp_cursor%NOTFOUND;

INSERT INTO temp(ename, sal) VALUES(v_ename,v_sal);

END LOOP;

CLOSE emp_cursor;

COMMIT;

END;

/

?

?

?

游標的FOR循環

使用游標的FOR循環,可以簡化游標的操作步驟

游標的FOR循環隱式(自動)地完成三個步驟:打開游標;(FETCT)取數據;關閉游標

記錄名師系統隱式定義的游標名%ROWTYPE類型的記錄變量,不必事先定義

FOR 紀錄名 IN 游標名 LOOP

????????語句1;

????語句2;

????...

END LOOP;

?

DECLARE

v_deptno emp.deptno%type := &p_deptno;

CURSOR emp_cursor IS SELECT ename ,sal FROM emp

????????????????????????????????????WHERE deptno = v_deptno;

BEGIN

FOR emp_record IN emp_cursor LOOP

INSERT INTO temp(ename , sal)

VALUES(emp_record.ename , emp_record.sal);

END LOOP;

COMMIT; /*在本段程序中,沒有打開游標、取數據、關閉游標語句*/

END;

/

?

要操縱數據庫中數據,在定義游標的查詢語句時,必須加上FOR UPDATE OF從句,表示要對表加鎖。

表加鎖后,在UPDATE或DELETE語句中,加WHERE CURRENT OF子句,既可以對鎖定的數據進行修改

CURSOR 游標名IS

SELECT 列1,列2 … FORM 表 WHERE 條件

FOR UPDATE [OF column][NOWAIT];

?

帶WHERE CURRENT O 從句的UPDATE語句和DELETE語句

DELETE FROM 表 WHERE CURRENT OF 游標名;

UPDATE 表 SET 列1=值1,列2=值2... WHERE CURRENT OF 游標名;

?

Eg:查詢emp表某部門的雇員情況,如果雇員的工資小于800,則將其工資改為800

DECLARE

v_deptno emp.deptno%type :=&p_deptno;

v_empno emp.empno%type; 

v_job emp.job%type;

v_sal emp.sal%type;

CURSOR emp_cursor IS SELECT ename,job,sal FROM emp

????????????????WHERE deptno = v_deptno FOR UPDATE OF sal;

BEGIN

FOR emp_record IN emp_cursor LOOP

IF emp_record.sal < 800 THEN

UPDATE emp SET sal=800 WHERE CURRENT OF emp_cursor;

END IF;

dbms_output.put_line(emp_record.empno||emp_record.sal);

END LOOP;

COMMIT;

END;

?

?

Eg:為職工增加10%的工資,從最低工資開始長,增加后工資總額限制在50萬以內

DECLARE

emp_num number :=0; s_sal emp.sal%type; 

e_sal emp.sal%type; e_empno emp.empno%type;

CURSOR c1 IS SELECT empno,sal FROM emp ORDER BY sal

???????????????? FOR UPDATE OF sal;

BEGIN

OPEN c1;

SELECT sum(sal) INTO s_sal FROM emp;

WHILE s_sal < 500000

LOOP

FETCH c1 INTO e_empno,e_sal;

EXIT WHEN c1%NOTFOUND;

s_sal := s_sal + e_sal*0.1;

UPDATE emp SET sal=sal*1.1 WHERE CURRENT OF c1;

?

emp_num := emp_num + 1;

END LOOP;

CLOSE c1;

INSERT INTO msg VALUES(emp_num,s_sal);

COMMIT;

END;

?

?

帶參數的游標

此參數只能在游標的查詢語句中使用

只能向游標傳遞參數數值,不能通過參數帶出結果

可以有選擇地給參數提供一個默認值

CURSOR 游標名(參數1 數據類型[{:=|DEFAULT}值]

        [,參數2 數據類型[{:=|DEFAULT]值] ...]

IS SELECT 語句 ;

?

DECLARE

CURSOR emp_cursor

(p_deptno NUMBER, p_job VARCHAR2) IS

SELECT????empno, ename????FROM????emp

WHERE????deptno = p_deptno

AND ????job = p_job;

BEGIN

OPEN emp_cursor(10, 'CLERK');

...

?

Eg:首先查詢DEPT表取出所有的部門號,然后根據DEPT表中返回的每一個部門號,從emp表查詢該部門的雇員信息

DECLARE

CURSOR dept_cursor IS SELECT deptno FROM dept;

v_ename emp.ename%type;

v_sal emp.sal%type;

CURSOR emp_cursor(v_deptno number) IS

SELECT ename, sal FROM emp WHERE deptno = v_deptno;

BEGIN

FOR dept_record IN dept_cursor LOOP

EXIT WHEN dept_cursor%NOTFOUND ;

OPEN emp_cursor(dept_record.deptno);

LOOP

FETCH emp_cursor INTO v_ename,v_sal;

EXIT WHEN emp_cursor%NOTFOUND;

dbms_output.put_line(dept_record.deptno ||' '||

' '||v_sal);

END LOOP;

CLOSE emp_cursor;

END LOOP;

COMMIT;

END;

?

?

隱式游標

由系統定義,不需要用戶定義

用來處理INSERT,UPDATE,DELETE和單行的SELECT…INTO語句

游標名為SQL

游標的屬性存儲有關最近一次SQL命令的狀態信息

BEGIN

UPDATE emp SET sal=10000,deptno=30 WHERE empno=9998;

IF SQL%NOTFOUND THEN

INSERT INTO emp(empno,sal,deptno) VALUES(9998,10000,30);

END IF;

COMMIT;

END;

?

隱式游標的游標屬性%ISOPEN總是FALSE,因為當語句執行完后立即關閉隱式游標

SELEC….INTO語句只能執一行

?

存儲過程

CREATE [OR REPLACE] PROCEDURE 過程名

[(參數名 [ IN | OUT | IN OUT ] 數據類型,... )]

{IS | AS}

????????????[說明部分]

BEGIN

????????????語句序列

????[EXCEPTION 出錯處理]

END [過程名];

OR REPLACE 是一個可選的關鍵字,表示替代原有的過程

IS或AS后面是一個完整的PL/SQL塊的三部分(說明部分,執行部分,異常處理部分)

IN表示輸入變量,OUT表示輸出變量,IN OUT表示輸入輸出變量,缺省表示IN

CREATE OR REPLACE PROCEDURE modetest(

p_inpara IN????number,

p_outpare OUT number,

p_inoutpara IN OUT number)

IS

v_local number;

BEGIN

v_local????????:= p_inpara; /* IN類型參數不能出現在:=的左邊 */

p_outpara????:= 7; /* OUT類型參數不能出現在:=的右邊 */

v_local????????:= p_inoutpara;

p_inoutpara????:= 7;

END;????

?

?

CREATE PROCEDURE raise_salary(emp_id interger,v_increase integer)

IS                          /* 缺省IN */

BEGIN

UPDATE emp SET sal = sal + v_increase

WHERE empno = emp_id;

COMMIT;

END;

?

如果IN OUT參數的值在過程中沒有被更改,則它返回到調用環境時值不變

如果IN OUT 參數是字符型,不能指定長度。長度有調用環境決定

?

?

函數

參數都是IN類型,存儲函數必須返回并且只返回一個結果

函數體的可執行部分必須有RETURN語句(RETURN 表達式)

表達式的數值類型與RETURN子句定義要一致

CREATE OR REPLACE FUNCTION get_sal (p_emp_no IN empno%TYPE)

RETURN NUMBER

IS

???? v_emp_sal emp.sal%TYPE :=0;

BEGIN

???? SELECT sal INTO v_emp_sal FROM emp WHERE empno=p_emp_no;

RETURN(v_emp_sal);

EXCEPTION

WHEN no_data_found or too_many_rows THEN

dbms_output.put_line('System Error');

  WHEN others THEN

dbms_output.put_line(sqlerrm);

END get_sal;

/

?

?

CREATE OR REPLACE FUNCTION average_sal(v_n IN number(3))

RETURN NUMBER

IS

???? CURSOR c_emp IS SELECT empno ,sal FROM emp;

v_total_sal emp.sal%TYPE;

v_counter number;

v_emp_no emp.empno%TYPE;

BEGIN

FOR r_emp IN c_emp LOOP

EXIT WHEN c_emp%ROWCOUNT > v_n OR c_emp%NOTFOUND;

v_total_sal := v_total_sal + r_emp.sal;

v_counter := c_emp%ROWCOUNT;

v_emp_no := r_emp.empno;

dbms_output.putline('loop='||v_counter||

';empno='||v_emp_no);

END LOOP;

RETURN(v_total_sal/v_counter);

END average_sal;

/

?

過程和函數

參數類型不同:函數只有IN類型參數,而存儲有IN,OUT,IN OUT三個類型參數

返回值的方法不同:函數返回只有一個值,而存儲過程返回值由OUT參數帶出來

調用方法不同:

過程(實際參數1,實際參數2……);

變量名:=函數名(實際參數1,實際參數2….);

?

過程/函數中的異常處理

CREATE OR REPLACE PROCEDURE fire_emp(

p_emp_no IN emp.empno%TYPE)

IS

invalid_employee EXCEPTION;????????/*定義錯誤*/

BEGIN

DELETE FROM emp WHERE empno = p_emp_no ;

IF SQL%NOTFOUND THEN

RAISE invalid_employee; /*觸發錯誤*/

END IF;

EXCEPTION

WHEN invalid_employee THEN ROLLBACK;

????????INSERT INTO exception_table(line_nr,line)

????????VALUES(1,'employee does not exist.');

WHEN others THEN

dbms_output.putline(sqlerrm);

END fire_emp;

/

?

在SQL*Plus中使用過程/函數

在SQL*Plus中,用VARIABLE定義的變量在引用時,必須前面加冒號(:)。用ACCEPT接受的變量在引用時,前面加&符號。

?

SET SERVEROUTPUT ON

ACCEPT p_emp_no PROMPT 'please enter the employee number:'

VARIABLE v_emp_name varchar2(14);

VARIABLE v_emp_sal number;

VARIABLE v_emp_comm number;

EXECUTE query_emp(&p_emp_no,:v_emp_name,

:v_emp_sal,:v_emp_comm);

EXECUTE dbms_output.putline('Infomation for employee:'

|| to_char(&p_emp_no));

EXECUTE dbms_output.putline('The name is:'|| :v_emp_name);

EXECUTE dbms_output.putline('The salary is:'

|| to_char(:v_emp_sal));

EXECUTE dbms_output.putline(The commission is:'

|| to_char(:v_emp_comm));

?

?

?

包是一個可以將相關對象存儲在一起的PL/SQL結構

它包含了兩個分離的組成部分:包說明和包主體

包的組成

可以將相關的若干程序單元組織到一塊,用一個包名來標識這個集合

包中可以包含的程序單元

過程,函數,變量,游標,類型,常量,出錯情況

CREATE [OR REPLACE] PACKAGE 包名

{IS | AS}

公共變量的定義????????| 

公共類型的定義????????|

公共出錯處理的定義????|

公共游標的定義????????|

函數說明????????????|

過程說明      

END;

/

CREATE PACKAGE sal_package IS

PROCEDURE raise_sal(v_empno emp.empno%TYPE,

v_sal_increment emp.sal%TYPE);

PROCEDURE reduce_sal(v_empno emp.empno%TYPE,

v_sal_reduce emp.sal%TYPE);

v_raise_sal emp.sal%TYPE :=0;

v_reduce_sal emp.sal%TYPE :=0;

END;

/

?

CREATE [OR REPLACE] PACKAGE BODY 包名

{IS | AS}

私有變量的定義????????| 

私有類型的定義????????|

私有出錯處理的定義????|

私有游標的定義????????|

函數定義????????????|

過程定義      

END ;

/

CREATE PACKAGE BODY sal_package IS

PROCEDURE raise_sal(v_empno emp.empno%TYPE,

v_sal_increment emp.sal%TYPE)

IS

BEGIN

UPDATE emp SET sal = sal + v_sal_increment

WHERE empno = v_empno;

COMMIT WORK;

v_raise_sal := v_raise_sal + v_sal_increment;

END;

PROCEDURE reduce_sal(v_empno emp.empno%TYPE,

v_sal_reduce emp.sal%TYPE)

IS

BEGIN

UPDATE emp SET sal = sal – v_sal_reduce

WHERE empno = v_empno;

COMMIT WORK;

v_reduce_sal := v_reduce_sal + v_sal_reduce;

END;

END;

?

?

所有提供的Package由SYS所擁有,對于不是SYS的用戶,必須擁有EXCEUTE權限才能調用

所有Oracle提供的程序包都是以DBMS_或UTL_開頭

?

靜態SQL
靜態SQL指直接嵌入在PL/SQL塊中的SQL語句,靜態SQL用于完成特定或固定的任務。
select sal from emp where empno=4000;

?

動態SQL
動態SQL運行PL/SQL塊時動態輸入的SQL語句。如果在PL/SQL需要執行DDL語句,DCL語句,或則需要執行更加靈活的SQL語句(select中有不同where條件),需要用到用到動態SQL。
編寫動態SQL語句時,需要將SQL語句存放到字符串變量中,而且SQL語句可以包含占位符(以冒號開始)。
v_sql varchar2(100);
v_sql:='delete from emp where empno =:v_empno';

?

?

//刪除某個表
create or replace procedure pro_drop_table(v_table_name varchar2)
is
v_sql varchar2(100);
begin

v_sql := 'drop table ' || v_table_name;
execute immediate v_sql;

end;

?

BEGIN

FOR I IN 1 .. 100 LOOP

BEGIN

EXECUTE IMMEDIATE 'DROP TABLE T'||I;

EXCEPTION

WHEN OTHERS THEN NULL;

END;

EXECUTE IMMEDIATE 'CREATE TABLE T'||I||' ( DUMMY CHAR(1) )';

EXECUTE IMMEDIATE 'INSERT INTO T'||I||' VALUES ( ''X'' )';

END LOOP;

END;

/

?

將字符串每個逗號字符用方括號進行封裝

declare

t_vararray dbms_utility.lname_array;

vc_stringlist varchar2(4000);

n_idx binary_integer;

begin

--comma to table

vc_stringlist := 'dkf,dddl,fewe,klkj';

dbms_utility.comma_to_table(vc_stringlist, n_idx, t_vararray);

dbms_output.put_line('Total Num : '||to_char(n_idx));

?

for i in 1..n_idx loop

dbms_output.put_line(t_vararray(i));

t_vararray(i) := '['||t_vararray(i)||']';

end loop;

--table to comma

dbms_utility.table_to_comma(t_vararray, n_idx, vc_stringlist);

dbms_output.put_line('');

dbms_output.put_line(vc_stringlist);

?

end;

結果

Total Num : 4

dkf

dddl

fewe

klkj

[dkf],[dddl],[fewe],[klkj]

?

?

DECLARE

l_temp NUMBER;

BEGIN

l_temp := DBMS_UTILITY.get_time;

dbms_output.put_line('before=' || l_temp);

dbms_lock.sleep(5);

l_temp := DBMS_UTILITY.get_time;

dbms_output.put_line('after=' || l_temp);

END;

/

?

?

before=59955835

after=59956335

?

?

?

DECLARE

l_temp NUMBER;

BEGIN

l_temp := DBMS_UTILITY.get_cpu_time;

dbms_output.put_line('before=' || l_temp);

dbms_lock.sleep(5);

l_temp := DBMS_UTILITY.get_cpu_time;

dbms_output.put_line('after=' || l_temp);

END;

/

before=10

after=10

?

?

?

觸發器

觸發器由說明部分,語句執行部分和出錯處理部分三部分組成的PL/SQL有名塊(類似于存儲過程和函數)

觸發器不接受參數,不能再程序中調用

當觸發事件發生時隱式地(自動地)執行

觸發事件包括:在數據庫中執行如下操作

INSERT

UPDATE

DELETE

?

將超過某工種工資范圍的員工信息紀錄到aduit_message表中。sal_guide表紀錄了每一工種的工資范圍

CREATE OR REPLACE TRIGGER check_sal

BEFORE INSERT OR UPDATE OF sal,job ON emp FOR EACH ROW

WHEN (new.job <> 'PRESIDENT')

DECLAER

v_minsal sal_guide.minsal%TYPE;

v_maxsal sal_guide.maxsal%TYPE;

e_sal_out_of_range EXCEPTION;

BEGIN

SELECT minsal , maxsal INTO v_minsal , v_maxsal

FROM sal_guide WHERE job = :new.job;

IF (:new.sal < v_minsal) OR (:new.sal > v_maxsal) THEN

RAISE e_sal_out_of_range;

END IF;

EXCEPTION

WHEN e_sal_out_range THEN

INSERT INTO audit_message(line_nr,line)

VALUES(1,'salary'||to_char(:new.sal)||

'is out of range for employee'||to_char(:new.empno));

END ;

?

?

觸發器類型:語句級和行級

觸發事件:表的插入,更新,刪除

觸發時間:BEFORE和AFTER

?

觸發器分語句級和行級觸發器兩個級別

行級觸發器與語句級觸發器的區別主要在于觸發次數不同

如果DML語句只影響一行,則語句級和行級觸發器效果一樣

如果該DML語句影響多行,則行級觸發器觸發的次數比語句級觸發器觸發的次數多

?

語句之前觸發->行之前觸發->插入、更新、刪除一條記錄->行之后出發->語句之后觸發

?

在觸發器體內禁止使用COMMIT,ROLLBACK語句

?

事件指明觸發事件的數據操縱語句,有三種可能的值:INSERT,UPDATE,UPDATE OF 列名1,DELETE

該觸發器在一個數據操作語句發生時只觸發一次

CREATE [OR REPLACE] TRIGGER 觸發器名

{BEFORE | AFTER} 事件1 [OR 事件2 ...] ON 表名

PL/SQL 塊;

Eg:創建一個BEFORE型語句級觸發器。限制一周內向emp表插入數據的時間,如果是周六、周日,或晚上6點到第二天早上8點之間插入,則中斷操作,并提示用戶不允許在此時間向emp表插入

CREATE OR REPLACE TRIGGER secure_emp

BEFORE INSERT ON emp

BEGIN

IF (TO_CHAR(sysdate,'DY') IN( 'SAT','SUN')

OR (TO_CHAR(sysdate,'HH24') NOT BETWEEN '8' AND '18')

THEN RAISE_APPLICATION_ERROR(-20500,'you may only

insert emp during normal hours.');

END IF;

END; ????????

?

使用觸發謂詞(INSERTING,UPDATING,DELETING)

觸發器可以包含多個觸發事件,在觸發器中使用謂詞判斷是哪個觸發了觸發器

謂詞 行為和值

INSERTING????????????如果觸發事件是INSERTING,則謂詞的值為TRUE,否則為FALSE

?

?

CREATE OR REPLACE TRIGGER secure_emp

BEFORE DELETE OR INSERT OR UPDATE ON emp

BEGIN

IF (TO_CHAR(sysdate,'DY') IN( 'SAT','SUN') OR

(TO_CHAR(sysdate,'HH24') NOT BETWEEN '8' AND '18') THEN

IF DELETING THEN

????RAISE_APPLICATION_ERROR(-20502,'you may only

delete emp during normal hours.');

ELSIF INSERTING THEN

RAISE_APPLICATION_ERROR(-20500,'you may only

insert emp during normal hours.');

ELSE THEN

RAISE_APPLICATION_ERROR(-20504,'you may only

update emp during normal hours.');

END IF;

END IF;

END;????

?

?

通過在CREATE TRIGGER 語句中指定FOR EACH ROW 子句創建一個行觸發器

CREATE [OR REPLACE] TRIGGER 觸發器名

{BEFORE | AFTER} 事件1 [OR 事件2 ...] ON 表名

FOR EACH ROW [WHEN 限制條件]

PL/SQL 塊;

?

Eg:將每個用戶對數據庫emp表進行數據操縱(插入、更新、刪除)的次數紀錄到audit_table表中

CREATE OR REPLACE TRIGGER audit_emp

AFTER DELETE OR INSERT OR UPDATE ON emp FOR EACH ROW

BEGIN

IF DELETING THEN

UPDATE audit_table SET del = del + 1

WHERE user_name = user AND table_name = 'emp'

AND colun_name IS NULL;

ELSIF INSERTING THEN

UPDATE audit_table SET ins = ins + 1

WHERE user_name = user AND table_name = 'emp'

AND colun_name IS NULL;

ELSE THEN

UPDATE audit_table SET upd = upd + 1

WHERE user_name = user AND table_name = 'emp'

AND colun_name IS NULL;

END IF;

END; ????

?

?

使用行級觸發器的標識符(:OLD和:NEW)

在行級觸發器中,列名前加上:OLD標識符表示該列變化前的值,加上:NEW標識符表示變化后的值

在BEFORE型行級觸發器和AFTER型行級觸發器中使用這些標識符

在語句級觸發器中不要使用這些標識符

在觸發器體的SQL語句或PL/SQL語句中使用這些標識符時,前加冒號(:)

在行級觸發器的WHEN限制條件中使用這些標識符時,前面不要加冒號(:)

?

Eg:在行級觸發器中獲取某列的新值和舊值,為emp表中的所有數據保留一個歷史檔案

CREATE OR REPLACE TRIGGER audit_emp_values

AFTER DELETE OR INSERT OR UPDATE ON emp FOR EACH ROW

BEGIN

INSERT INTO audit_emp(user_name,timestamp,empno,

old_ename,new_ename,old_job,new_job,

old_sal,new_sal)

VALUES(USER,SYSDATE,:old.empno,:old.ename,

:new.ename,:old.job,:new.job,:old.sal,:newsal);

END;

?

?

Eg:在行級觸發器加WHEN限制條件。根據銷售員工資的改變自動計算銷售員的獎金

CREATE OR REPLACE TRIGGER derive_comm

BEFORE UPDATE OF sal ON emp FOR EACH ROW

WHEN (new.job = 'SALESMAN')

BEGIN

:new.comm := :old.comm * (:new.sal/:old.sal);

END;????????

?

?

CREATE TIGGER

CREATE OR REPLACE TRIGGER

DROP TRIGGER

?

SYSTEM觸發器

DDL觸發器

?

INSTEAD OF 觸發器

instead of trigger 是基于視圖建立的,不能建在表上,為什么要建在視圖上,一般的視圖如果其數據來源一個表并且包含該表的主鍵,就可以對視圖進行DML操作.另外一種情況是 從多個表查詢出來的.這樣我們就不能對視圖進行操作了,也就是只能查詢.instead of trigger可以解決建在多表上視圖的更新操作.

?

?

?

?

BULK DML

Oracle引入了兩個DML語句: BUKL COLLECT 和 FORALL

這兩個語句在PL/SQL內部進行以一種數據處理

BUKL COLLECT 提供對數據的高速檢索

FORALL 可大大改進INSERT,UPDATE和DELETE操作的性能

Oracle數據庫使用這些語句大大減少了PL/SQL與SQL語句執行引擎的環境切換次數,從而使其性能有了顯著提高

?

DECLARE
????TYPE books_aat IS TABLE OF book%ROWTYPE
????????INDEX BY PLS_INTEGER;
????my_books books_aat;
BEGIN
????SELECT * BULK COLLECT INTO my_books
????FROM book WHERE title LIKE '%PL/SQL%';
????...
END;

?

?

CREATE TYPE books_nt
IS TABLE OF book%ROWTYPE;

CREATE OR REPLACE PROCEDURE add_books ( books_in IN books_nt)
IS
BEGIN
????FORALL book_index
????????IN books_in.FIRST .. books_in.LAST
????INSERT INTO book VALUES books_in(book_index);
????...
END;

?

?

?

?

DECLARE

Type region_id_tbl IS TABLE of NUMBER INDEX BY BINARY_INTEGER;

Type region_name_tbl IS TABLE of VARCHAR2(20) INDEX BY BINARY_INTEGER;

region_ids region_id_tbl; region_names region_name_tbl; ret_code NUMBER;

ret_errmsg VARCHAR2(1000);

Procedure load_regions_bulk_bind (region_ids IN region_id_tbl, region_names IN region_name_tbl,

retcd OUT NUMBER, errmsg OUT VARCHAR2)

IS

BEGIN

-- clean up the region_tab table initially.

DELETE FROM region_tab;

FORALL i IN region_ids.FIRST..region_ids.LAST

INSERT INTO region_tab values (region_ids(i), region_names(i));

Retcd := 0;

EXCEPTION

WHEN OTHERS THEN

COMMIT;

Retcd := SQLCODE;

Errmsg := SQLERRM;

END;

BEGIN

FOR i IN 1..5 LOOP

Region_ids(i) := i; Region_names(i) := 'REGION'||i;

END LOOP;

Load_regions_bulk_bind(region_ids, region_names, ret_code, ret_errmsg);

EXCEPTION WHEN OTHERS THEN

RAISE_APPLICATION_ERROR(-20112, SQLERRM);

END;

?

?

?

什么時候使用FORALL

FORALL可以大量的提高從源表或者視圖到目標表的插入,更新,刪除,合并操作

?

如果FORALL的調用集合中缺失一個元素那么錯誤將會發生

如果一個行級別的發生那么整個進程將會停止

?

?

DECLARE

t_outtab_type IS TABLE OF input_table%ROWTYPE;

v_outtab t_outtab_type;

BEGIN

SELECT * BULK COLLECT INTO v_outtab

FROM input_table

WHERE key_col = '<val1>';

?

FOR i IN 1..v_outtab.COUNT LOOP

-- Process the rows one by one according to required logic.

END LOOP;

END;

/

?

DECLARE

t_outtab_type IS TABLE OF input_table%ROWTYPE;

v_outtab t_outtab_type;

CURSOR c_in IS SELECT * FROM input_table

WHERE key_col = '<val1>';

BEGIN

OPEN c_in;

FETCH c_in BULK COLLECT INTO v_outtab;

FOR i IN 1..v_outtab.COUNT LOOP

-- Process the rows one by one according to required logic.

END LOOP;

?

CLOSE c_in;

END;

/

?

DECLARE

t_outtab_type IS TABLE OF input_table%ROWTYPE;

v_outtab t_outtab_type;

CURSOR c_in IS SELECT * FROM input_table

WHERE key_col = '<val1>';

BEGIN

OPEN c_in;

FETCH c_in BULK COLLECT INTO v_outtab;

FOR i IN 1..v_outtab.COUNT LOOP

-- Process the rows one by one according to required logic.

END LOOP;

?

CLOSE c_in;

END;

/

?

?

用bulk query的主要有點,

減少運行的時間,更少的延時

如果取得的數據很大的話,那么回增加內存的消耗

?

可以通過特定的limite數量來控制取得的數量

DECLARE

t_outtab_type IS TABLE OF input_table%ROWTYPE;

v_outtab t_outtab_type;

CURSOR c_in IS SELECT * FROM input_table WHERE key_col = '<val1>';

BEGIN

OPEN c_in;

LOOP

FETCH c_in BULK COLLECT INTO v_outtab LIMIT 100;

FOR i IN 1..v_outtab.COUNT LOOP

-- Process the rows one by one according to required logic.

NULL;

END LOOP;

EXIT WHEN c_in%NOTFOUND;

END LOOP;

CLOSE c_in;

END;

/

?

自治事物

自治事物允許你在一個事務中創建一個事務,這個事務將會獨立于父事務進行提交,回滾等改變

允許你掛起現在正在執行的事務,開始一個新的事務,做一些工作,提交回滾,所有的這些事情不會影響當前正在執行事務的狀態

通過pragma autonomous_transaction將一個pl/sql程序結構設定為自治事務,pragma是編譯器指令,可以將procedure function package等頂級匿名塊定義成自治的程序結構。

?

create or replace trigger EMP_AUDIT

????before update on emp for each row

declare

????pragma autonomous_transaction;

????l_cnt number;

begin

????select count(*) into l_cnt from dual

????where EXISTS ( select null from emp where empno = :new.empno

????????start with mgr = ( select empno from emp where ename = USER )

????????connect by prior empno = mgr );

????if ( l_cnt = 0 ) then

????????insert into audit_tab ( msg )

????????values ( 'Attempt to update ' || :new.empno );

????????commit;

????????raise_application_error( -20001, 'Access Denied' );

????end if;

end;

/

?

?

?

?

?

綁定變量

下面的代碼每次都要硬編碼

create or replace procedure dsal(p_empno in number)
as
begin
????execute immediate
????????'update emp set sal = sal*2

????????where empno = '||p_empno;
????commit;
end;

?

通過如下改變就可以了

create or replace procedure dsal(p_empno in number)
as
begin
????execute immediate
????????'update emp set sal = sal*2

????????where empno = :x' using p_empno;
????commit;
end;

?

游標變量 : 聲明游標實際上是創建一個指針 , 指針具有數據類型 REF X.REF 是 REFERENCE ,X 是表示類對象 . 因此 , 游標變量具有數據類型 REF? CURSOR.

注 : 游標總是指向相同的查詢工作區 , 游標變量能夠指向不同的工作區 , 因此游標和游標變量不能互操作 .

DECLARE

TYPE empcurtyp IS REF CURSOR RETURN employees%ROWTYPE;

emp empcurtyp;

-- after result set is built, process all the rows inside a single procedure

-- rather than calling a procedure for each row

PROCEDURE process_emp_cv (emp_cv IN empcurtyp)

IS

person employees%ROWTYPE;

BEGIN

DBMS_OUTPUT.PUT_LINE('-----');

DBMS_OUTPUT.PUT_LINE('Here are the names from the result set:');

LOOP

FETCH emp_cv INTO person;

EXIT WHEN emp_cv%NOTFOUND;

DBMS_OUTPUT.PUT_LINE('Name = ' || person.first_name || ' ' || person.last_name);

END LOOP;

END;

BEGIN

-- First find 10 arbitrary employees.

OPEN emp FOR SELECT * FROM employees WHERE ROWNUM < 11;

process_emp_cv(emp);

CLOSE emp;

?

-- find employees matching a condition.

OPEN emp FOR SELECT * FROM employees WHERE last_name LIKE 'R%';

process_emp_cv(emp);

CLOSE emp;

END;

轉載于:https://www.cnblogs.com/kexinxin/p/10011934.html

總結

以上是生活随笔為你收集整理的大型数据库的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。