oracle存儲過程超詳細使用手冊

Oracle 存儲過程總結
一、建立存儲過程
create or replace procedure test(var_name_1 in type,var_name_2 out ty
pe) as
--聲明變量(變量名 變量類型)
begin
--存儲過程的執行體
end test;
打印出輸入的時間信息
E.g:
create or replace procedure test(workDate in Date) is
begin
dbms_output.putline(The input date is:||to_date(workDate, yyyy-mm-d
d));
end test;
二、變量賦值
變量名 := 值;
E.g:
create or replace procedure test(workDate in Date) is
x number(4,2);
begin
x := 1;
end test;
三、判斷語句:
if 比較式 then begin end; end if;
E.g
create or replace procedure test(x in number) is
begin
if x >0 then
begin
x := 0 - x;
end;
end if;
if x = 0 then
begin
x: = 1;
end;
end if;
end test;
四、 For 循環
For ... in ... LOOP
--執行語句
end LOOP;
(1)循環遍歷遊標
create or replace procedure test() as
Cursor cursor is select name from student;
name varchar(20);
begin
for name in cursor LOOP
begin
dbms_output.putline(name);
end;
end LOOP;
end test;
(2)循環遍歷數組
create or replace procedure test(varArray in myPackage.TestArray) a
s
--(輸入參數varArray 是自定義的數組類型,定義方式見標題6)
i number;
begin
i := 1; --存儲過程數組是起始位置是從1開始的,與java、 C、 C++等語言
不一樣。由於在Oracle 中本是沒有數組的概念的,數組其實就是一張
--表(Table),每一個數組元素就是表中的一個記錄,因此遍歷數組時就至關於從表
中的第一條記錄開始遍歷
for i in 1..varArray.count LOOP
dbms_output.putline(The No. || i ||record in varArray is: ||varArray
(i));
end LOOP;
end test;
五、 While 循環
while 條件語句 LOOP
begin
end;
end LOOP;
E.g
create or replace procedure test(i in number) as
begin
while i < 10 LOOP
begin
i:= i + 1;
end;
end LOOP;
end test;
六、數組
首先明確一個概念: Oracle中本是沒有數組的概念的, 數組其實就是一張表(Ta
ble),每一個數組元素就是表中的一個記錄。
使用數組時,用戶可使用Oracle已經定義好的數組類型,或可根據本身的需
要定義數組類型。
(1)使用Oracle自帶的數組類型
x array; --使用時須要須要進行初始化
e.g:
create or replace procedure test(y out array) is
x array;
begin
x := new array();
y := x;
end test;
(2)自定義的數組類型 (自定義數據類型時,建議經過建立Package的方式實現,
以便於管理)
E.g (自定義使用參見標題4.2) create or replace package myPackage is
-- Public type declarations type info is record( name va
rchar(20), y number);
type TestArray is table of info index by binary_integer; --此處
聲明瞭一個TestArray 的類型數據,其實其爲一張存儲Info 數據類型的Table
而已,及TestArray 就是一張表,有兩個字段,一個是
name, 一個是y。 須要注意的是此處使用了Index by binary_integer 編制該T
able 的索引項,也能夠不寫,直接寫成: type TestArray is
table of info,若是不寫的話使用數組時就須要進行初始化: varArray myPac
kage.TestArray; varArray := new myPackage.TestArray();
end TestArray;
7.遊標的使用 Oracle 中Cursor是很是有用的, 用於遍歷臨時表中的查詢結果。
其相關方法和屬性也不少,現僅就經常使用的用法作一二介紹:
(1)Cursor型遊標(不能用於參數傳遞)
create or replace procedure test() is
cusor_1 Cursor is select std_name from student where ...; --Curso
r 的使用方式1 cursor_2 Cursor;
begin
select class_name into cursor_2 from class where ...; --Cursor的使
用方式2
可以使用For x in cursor LOOP .... end LOOP; 來實現對 Cursor的遍歷
end test;
(2)SYS_REFCURSOR型遊標, 該遊標是Oracle以預先定義的遊標, 可做出參數進
行傳遞
create or replace procedure test(rsCursor out SYS_REFCURSOR) is
cursor SYS_REFCURSOR; name varhcar(20);
begin
OPEN cursor FOR select name from student where ... --SYS_REFCURSOR只
能經過OPEN方法來打開和賦值
LOOP
fetch cursor into name --SYS_REFCURSOR只能經過 fetch into來打
開和遍歷 exit when cursor%NOTFOUND; --SYS_R
EFCURSOR中可以使用三個狀態屬性:
---%NOTFOUND(未找到記錄信息) %FOUND(找到記錄信息)
---%ROWCOUNT(而後當前遊標所指向的行位置)
dbms_output.putline(name);
end LOOP;
rsCursor := cursor;
end test;
下面寫一個簡單的例子來對以上所說的存儲過程的用法作一個應用:
現假設存在兩張表,一張是學生成績表(studnet),字段爲: stdId,math,artic
le,language,music,sport,total,average,step
一張是學生課外成績表(out_school),
字段爲:stdId,parctice,comment
經過存儲過程自動計算出每位學生的總成績和平均成績, 同時, 若是學生在課外
課程中得到的評價爲 A,就在總成績上加20分。
create or replace procedure autocomputer(step in number) is
rsCursor SYS_REFCURSOR;
commentArray myPackage.myArray;
math number;
article number;
language number;
music number;
sport number;
total number;
average number;
stdId varchar(30);
record myPackage.stdInfo;
i number;
begin
i := 1;
get_comment(commentArray); --調用名爲get_comment()的存儲過程獲取學生
課外評分信息
OPEN rsCursor for select stdId,math,article,language,music,sport from
student t where t.step = step;
LOOP
fetch rsCursor into stdId,math,article,language,music,sport; exit whe
n rsCursor%NOTFOUND;
total := math + article + language + music + sport;
for i in 1..commentArray.count LOOP
record := commentArray(i);
if stdId = record.stdId then
begin
if record.comment = 'A' then
begin
total := total + 20;
go to next; --使用go to跳出for循環
end;
end if;
end;
end if;
end LOOP;
<<continue>> average := total / 5;
update student t set t.total=total and t.average = average where t.
stdId = stdId;
end LOOP;
end;
end autocomputer;
--取得學生評論信息的存儲過程
create or replace procedure get_comment(commentArray out myPackage.my
Array) is
rs SYS_REFCURSOR;
record myPackage.stdInfo;
stdId varchar(30);
comment varchar(1);
i number;
begin
open rs for select stdId,comment from out_school
i := 1;
LOOP
fetch rs into stdId,comment; exit when rs%NOTFOUND;
record.stdId := stdId;
record.comment := comment;
recommentArray(i) := record;
i:=i + 1;
end LOOP;
end get_comment;
--定義數組類型myArray
create or replace package myPackage is begin
type stdInfo is record(stdId varchar(30),comment varchar(1));
type myArray is table of stdInfo index by binary_integer;
end myPackage;
項目中有涉及存儲過程對字符串的處理, 因此就將在網上查找到的資料彙總, 作一個信
息拼接式的總結。
如下信息均來自互聯網,貼出來一則本身保存以待之後使用,一則供你們分享。
字符函數——返回字符值
這些函數全都接收的是字符族類型的參數(CHR除外)而且返回字符值.
除了特別說明的以外,這些函數大部分返回 VARCHAR2 類型的數值.
字符函數的返回類型所受的限制和基本數據庫類型所受的限制是相同的。
字符型變量存儲的最大值:
VARCHAR2數值被限制爲 2000字符(ORACLE 8 中爲4000 字符)
CHAR數值被限制爲 255字符(在 ORACLE8中是 2000)
long類型爲 2GB
Clob類型爲 4GB
一、 CHR
語法: chr(x)
功能: 返回在數據庫字符集中與X擁有等價數值的字符。 CHR和ASCII是一對反函數。 通過
CHR轉換後的字符再通過ASCII轉換又獲得了原來的字
符。
使用位置:過程性語句和SQL語句。
二、 CONCAT
語法: CONCAT( string1,string2)
功能:返回string1,而且在後面鏈接string2。
使用位置:過程性語句和SQL語句。
三、 INITCAP
語法: INITCAP( string)
功能:返回字符串的每一個單詞的第一個字母大寫而單詞中的其餘字母小寫的string。單詞
是用.空格或給字母數字字符進行分隔。不是字母的
字符不變更。
使用位置:過程性語句和SQL語句。
四、 LTRIM
語法: LTRIM( string1,string2)
功能:返回刪除從左邊算起出如今string2中的字符的string1。 String2被缺省設置爲單
個的空格。數據庫將掃描string1,從最左邊開始。當
遇到不在string2中的第一個字符,結果就被返回了。 LTRIM的行爲方式與RTRIM很類似。
使用位置:過程性語句和SQL語句。
五、 NLS_INITCAP
語法: NLS_INITCAP( string[,nlsparams])
功能: 返回字符串每一個單詞第一個字母大寫而單詞中的其餘字母小寫的string, nlsparams
指定了不一樣於該會話缺省值的不一樣排序序列。若是不指定參數,則功能和INITCAP相同。 N
lsparams可使用的形式是:
‘ NLS_SORT=sort’
這裏sort制訂了一個語言排序序列。
使用位置:過程性語句和SQL語句。
六、 NLS_LOWER
語法: NLS_LOWER( string[,nlsparams])
功能:返回字符串中的全部字母都是小寫形式的string。不是字母的字符不變。
Nlsparams參數的形式與用途和NLS_INITCAP中的nlsparams參數是相同的。
若是nlsparams沒有被包含,那麼NLS_LOWER所做的處理和
LOWER相同。
使用位置;過程性語句和SQL語句。
七、 NLS_UPPER
語法: nls_upper( string[,nlsparams])
功能: 返回字符串中的全部字母都是大寫的形式的string。 不是字母的字符不變。 nlspara
ms參數的形式與用途和NLS_INITCAP中的相同。若是
沒有設定參數,則NLS_UPPER功能和UPPER相同。
使用位置:過程性語句和SQL語句。
八、 REPLACE
語法: REPLACE( string, search_str[,replace_str])
功能: 把string中的全部的子字符串search_str用可選的replace_str替換, 若是沒有指
定replace_str,全部的string中的子字符串
search_str都將被刪除。 REPLACE是TRANSLATE所提供的功能的一個子集。
使用位置:過程性語句和SQL語句。
九、 RPAD
語法: RPAD( string1,x[,string2])
功能: 返回在X字符長度的位置上插入一個string2中的字符的string1。 若是string2的
長度要比X字符少,就按照須要進行復制。若是string2
多於X字符, 則僅string1前面的X各字符被使用。 若是沒有指定string2, 那麼使用空格
進行填充。 X是使用顯示長度能夠比字符串的實際長度
要長。 RPAD的行爲方式與LPAD很類似,除了它是在右邊而不是在左邊進行填充。
使用位置:過程性語句和SQL語句。
十、 RTRIM
語法: RTRIM( string1,[,string2])
功能: 返回刪除從右邊算起出如今string1中出現的字符string2. string2被缺省設置
爲單個的空格.數據庫將掃描string1,從右邊開始.當遇
到不在string2中的第一個字符,結果就被返回了RTRIM的行爲方式與LTRIM很類似.
使用位置:過程性語句和SQL語句。
十一、 SOUNDEX
語法: SOUNDEX( string)
功能: 返回string的聲音表示形式.這對於比較兩個拼寫不一樣可是發音相似的單詞而言
頗有幫助.
使用位置:過程性語句和SQL語句。
十二、 SUBSTR
語法: SUBSTR( string,a[,b])
功能: 返回從字母爲值a開始b個字符長的string的一個子字符串.若是a是0,那麼它
就被認爲從第一個字符開始.若是是正數,返回字符是從左
邊向右邊進行計算的.若是b是負數,那麼返回的字符是從string的末尾開始從右向左進行
計算的.若是b不存在,那麼它將缺省的設置爲整個字符
串.若是b小於1,那麼將返回NULL.若是a或b使用了浮點數,那麼該數值將在處理進行之前
首先被卻爲一個整數.
使用位置:過程性語句和SQL語句。
1三、 TRANSLATE
語法: TRANSLATE(string,from_str,to_str)
功能: 返回將所出現的from_str中的每一個字符替換爲to_str中的相應字符之後的
string. TRANSLATE是REPLACE所提供的功能的一個超集.
若是from_str比to_str長,那麼在from_str中而不在to_str中而外的字符將從string
中被刪除,由於它們沒有相應的替換字符. to_str不能爲空
.Oracle把空字符串認爲是NULL,而且若是TRANSLATE中的任何參數爲NULL,那麼結果也是N
ULL.
使用位置:過程性語句和SQL語句。
1四、 UPPER
語法: UPPER( string)
功能: 返回大寫的string.不是字母的字符不變.若是string是CHAR數據類型的,那麼結果
也是CHAR類型的.若是string是VARCHAR2類型的,那麼
結果也是VARCHAR2類型的.
使用位置: 過程性語句和SQL語句。
字符函數——返回數字
這些函數接受字符參數回數字結果.參數能夠是CHAR或者是VARCHAR2類型的.儘管實際下許
多結果都是整數值,可是返回結果都是簡單的NUMBER
類型的,沒有定義任何的精度或刻度範圍.
1六、 ASCII
語法: ASCII( string)
功能: 數據庫字符集返回string的第一個字節的十進制表示.請注意該函數仍然稱做爲ASC
II.儘管許多字符集不是7位ASCII.CHR和ASCII是互爲
相反的函數.CHR獲得給定字符編碼的響應字符. ASCII獲得給定字符的字符編碼.
使用位置: 過程性語句和SQL語句。
1七、 INSTR
語法: INSTR( string1, string2[a,b])
功能: 獲得在string1中包含string2的位置. string1時從左邊開始檢查的,開始的位
置爲a,若是a是一個負數,那麼string1是從右邊開始進行
掃描的.第b次出現的位置將被返回. a和b都缺省設置爲1,這將會返回在string1中第一
次出現string2的位置.若是string2在a和b的規定下沒有
找到,那麼返回0.位置的計算是相對於string1的開始位置的,無論a和b的取值是多少.
使用位置: 過程性語句和SQL語句。
1八、 INSTRB
語法: INSTRB( string1, string2[a,[b]])
功能: 和INSTR相同,只是操做的對參數字符使用的位置的是字節.
使用位置: 過程性語句和SQL語句。
1九、 LENGTH
語法: LENGTH( string)
功能: 返回string的字節單位的長度.CHAR數值是填充空格類型的,若是string由數據
類型CHAR,它的結尾的空格都被計算到字符串長度中間.
若是string是NULL,返回結果是NULL,而不是0.
使用位置: 過程性語句和SQL語句。
20、 LENGTHB
語法: LENGTHB( string)
功能: 返回以字節爲單位的string的長度.對於單字節字符集LENGTHB和LENGTH是同樣
的.
使用位置: 過程性語句和SQL語句。
2一、 NLSSORT
語法: NLSSORT( string[,nlsparams])
功能: 獲得用於排序string的字符串字節.全部的數值都被轉換爲字節字符串,這樣在不一樣
數據庫之間就保持了一致性. Nlsparams的做用和
NLS_INITCAP中的相同.若是忽略參數,會話使用缺省排序.
使用位置: 過程性語句和SQL語句。 oracle 存儲過程的基本語法
1.基本結構
CREATE OR REPLACE PROCEDURE 存儲過程名字
(
參數1 IN NUMBER,
參數2 IN NUMBER
) IS
變量1 INTEGER :=0;
變量2 DATE;
BEGIN
END 存儲過程名字
2.SELECT INTO STATEMENT

select查詢的結果存入到變量中,能夠同時將多個列存儲多個變量中,必須有一條
記錄,不然拋出異常(若是沒有記錄拋出NO_DATA_FOUND)
例子:
BEGIN
SELECT col1,col2 into 變量1,變量2 FROM typestruct where xxx;
EXCEPTION
WHEN NO_DATA_FOUND THEN
xxxx;
END;
...
3.IF 判斷
IF V_TEST=1 THEN
BEGIN
do something
END;
END IF;
4.while 循環
WHILE V_TEST=1 LOOP
BEGIN
XXXX
END;
END LOOP;
5.變量賦值
V_TEST := 123;
6.用for in 使用cursor
...
IS
CURSOR cur IS SELECT * FROM xxx;
BEGIN
FOR cur_result in cur LOOP
BEGIN
V_SUM :=cur_result.列名1+cur_result.列名2
END;
END LOOP;
END;
7.帶參數的cursor
CURSOR C_USER(C_ID NUMBER) IS SELECT NAME FROM USER WHERE
TYPEID=C_ID;
OPEN C_USER(變量值);
LOOP
FETCH C_USER INTO V_NAME;
EXIT FETCH C_USER%NOTFOUND;
do something
END LOOP;
CLOSE C_USER;
8.用pl/sql developer debug
鏈接數據庫後創建一個 Test WINDOW
在窗口輸入調用 SP的代碼,F9開始debug,CTRL+N單步調試 關於oracle存儲過程的若干問題備忘
1.在oracle中,數據表別名不能加 as,如:
select a.appname from appinfo a;-- 正確
select a.appname from appinfo as a;-- 錯誤
也許,是怕和 oracle中的存儲過程當中的關鍵字 as衝突的問題吧
2.在存儲過程當中, select某一字段時, 後面必須緊跟 into, 若是select整個記錄, 利用遊標的
話就另當別論了。
select af.keynode into kn from APPFOUNDATION af where af.appid=aid and af.
foundationid=fid;-- 有into,正確編譯
select af.keynode from APPFOUNDATION af where af.appid=aid and af.foundat
ionid=fid;-- 沒有into,編譯報錯,提示: Compilation
Error: PLS-00428: an INTO clause is expected in this SELECT statement
3.在利用select...into...語法時,必須先確保數據庫中有該條記錄,不然會報出"no data
found"異常。
能夠在該語法以前,先利用select count(*) from 查看數據庫中是否存在該記錄,若是存
在,再利用select...into...
4.在存儲過程當中,別名不能和字段名稱相同,不然雖然編譯能夠經過,但在運行階段會報錯
select keynode into kn from APPFOUNDATION where appid=aid and foundationi
d=fid;-- 正確運行
select af.keynode into kn from APPFOUNDATION af where af.appid=appid and af.
foundationid=foundationid;-- 運行階段報錯,提示
ORA-01422:exact fetch returns more than requested number of rows
5.在存儲過程當中,關於出現null的問題
假設有一個表A,定義以下:
create table A(
id varchar2(50) primary key not null,
vcount number(8) not null,
bid varchar2(50) not null -- 外鍵
);
若是在存儲過程當中,使用以下語句:
select sum(vcount) into fcount from A where bid='xxxxxx';
若是A表中不存在bid="xxxxxx"的記錄,則fcount=null(即便fcount定義時設置了默認值,
如: fcountnumber(8):=0依然無效, fcount仍是會變成null),這樣之後使用fcount時就
可能有問題,因此在這裏最好先判斷一下:
if fcount is null then
fcount:=0;
end if;
這樣就一切ok了。
6.Hibernate調用oracle存儲過程
this.pnumberManager.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
CallableStatement cs = session
.connection()
.prepareCall("{call modifyapppnumber_remain(?)}");
cs.setString(1, foundationid);
cs.execute();
return null;
}
}); oracle 存儲過程語法總結及練習
---------------------------------------------
--1.存儲過程之if
clear;
create or replace procedure mydel(
in_a in integer)
as
begin
if in_a<100 then
dbms_output.put_line('小於 100.');
elsif in_a<200 then
dbms_output.put_line('大於 100 小於200.');
else
dbms_output.put_line('大於 200.');
end if;
end;
/
set serveroutput on;
begin
mydel(1102);
end;
/
---------------------------------------------
--2.存儲過程之 case1
clear;
create or replace procedure mydel(
in_a in integer)
as
begin
case in_a
when 1 then
dbms_output.put_line('小於 100.');
when 2 then
dbms_output.put_line('大於 100 小於200.');
else
dbms_output.put_line('大於 200.');
end case;
end;
/
set serveroutput on;
begin
mydel(2);
end;
/
------------------------------------------------
--1.存儲過程之 loop1
clear;
create or replace procedure mydel(
in_a in integer)
as
a integer;
begin
a:=0;
loop
dbms_output.put_line(a);
a:=a+1;
exit when
a>301;
end loop;
end;
/
set serveroutput on;
begin
mydel(2);
end;
/
--------------------------------------------------
--1.存儲過程之 loop2
clear;
create or replace procedure mydel(
in_a in integer)
as
a integer;
begin
a:=0;
while a<300 loop
dbms_output.put_line(a);
a:=a+1;
end loop;
end;
/
set serveroutput on;
begin
mydel(2);
end;
--------------------------------------------------
--1.存儲過程之 loop3
clear;
create or replace procedure mydel(
in_a in integer)
as
a integer;
begin
for a in 0..300
loop
dbms_output.put_line(a);
end loop;
end;
/
set serveroutput on;
begin
mydel(2);
end;
/
clear;
select ename,cc:=(case
when comm=null then sal*12;
else (sal+comm)*12;
end case from emp order by salpersal;
----------------------------------------------------
clear;
create or replace procedure getstudentcomments(
i_studentid in int,o_comments out varchar)
as
exams_sat int;
avg_mark int;
tmp_comments varchar(100);
begin
select count(examid) into exams_sat from studentexam
where studentid=i_studentid;
if exams_sat=0 then
tmp_comments:='n/a-this student did not attend the exam!';
else
select avg(mark) into avg_mark from studentexam
where studentid=i_studentid;
case
when avg_mark<50 then tmp_comments:='very bad';
when avg_mark<60 then tmp_comments:='bad';
when avg_mark<70 then tmp_comments:='good';
end case;
end if;
o_comments:=tmp_comments;
end;
/
set serveroutput on;
declare
pp studentexam.comments%type;
begin
getstudentcomments(8,pp);
dbms_output.put_line(pp);
end;
/
--------------------------------------------------------
delete from emp where empno<6000;
clear;
create or replace procedure insertdata(
in_num in integer)
as
myNum int default 0;
emp_no emp.empno%type:=1000;
begin
while myNum<in_num loop
insert into emp
values(emp_no,'hui'||myNum,'coder',7555,current_date,8000,6258,30);
emp_no:=emp_no+1;
myNum:=myNum+1;
end loop;
end;
/
set serveroutput on;
begin
insertdata(10);
end;
/
select * from emp;
------------------------------------------------------------------
clear;
select studentname,averageMark,case
when averageMark<60 then '不及格'
when averageMark<70 then '考得好'
when averageMark<80 then '考得很好'
end case
from (select (
select b.name from student b where b.studentid=a.studentid) as studentname,
round(avg(mark),2) as averageMark from studentexam a group by a.studentid); ORACLE 查詢練習
emp員工表(empno員工號/ename員工姓名/job工做/mgr上級編號/hiredate受僱日期/sal薪金
/comm 佣金/deptno部門編號)
dept部門表(deptno部門編號/dname 部門名稱/loc 地點)
工資 = 薪金 + 佣金
1.列出至少有一個員工的全部部門。
2.列出薪金比「 SMITH」 多的全部員工。
3.列出全部員工的姓名及其直接上級的姓名。
4.列出受僱日期早於其直接上級的全部員工。
5.列出部門名稱和這些部門的員工信息,同時列出那些沒有員工的部門
6.列出全部「 CLERK」 (辦事員)的姓名及其部門名稱。
7.列出最低薪金大於 1500的各類工做。
8.列出在部門「 SALES」 (銷售部)工做的員工的姓名,假定不知道銷售部的部門編號。
9.列出薪金高於公司平均薪金的全部員工。
10.列出與「 SCOTT」 從事相同工做的全部員工。
11.列出薪金等於部門 30 中員工的薪金的全部員工的姓名和薪金。
12.列出薪金高於在部門 30 工做的全部員工的薪金的員工姓名和薪金。
13.列出在每一個部門工做的員工數量、平均工資和平均服務期限。
14.列出全部員工的姓名、部門名稱和工資。
15.列出全部部門的詳細信息和部門人數。
16.列出各類工做的最低工資。
17.列出各個部門的 MANAGER(經理)的最低薪金。
18.列出全部員工的年工資,按年薪從低到高排序。
--------1----------
select dname from deptwhere deptnoin(
select deptnofrom emp);
--------2----------
select * fromemp where sal>(
select sal from emp whereename='SMITH');
--------3----------
select a.ename,(
select ename from emp b where b.empno=a.mgr) as bossname from emp a;
--------4----------
select a.ename from emp a wherea.hiredate<(
select hiredate fromemp b whereb.empno=a.mgr);
--------5----------
select a.dname,b.empno,b.ename,b.job,b.mgr,b.hiredate,b.sal,b.comm,b.deptno
from depta left join emp b ona.deptno=b.deptno;
--------6----------
selecta.ename,b.dnamefromempajoindeptb
ona.deptno=b.deptnoanda.job='CLERK';
--------7----------
selectdistinctjobasHighSalJobfromempgroupbyjobhavingmin(sal)>1500;
--------8----------
selectenamefromempwheredeptno=(
selectdeptnofromdeptwheredname='SALES');
--------9----------
selectenamefromempwheresal>(
selectavg(sal)fromemp);
--------10---------
selectenamefromempwherejob=(
selectjobfromempwhereename='SCOTT');
--------11---------
selecta.ename,a.salfromempawherea.salin(
selectb.salfromempbwhereb.deptno=30)anda.deptno<>30;
--------12---------
selectename,salfromempwheresal>(
selectmax(sal)fromempwheredeptno=30);
--------13---------
select
(selectb.dnamefromdeptbwherea.deptno=b.deptno)asdeptname,
count(deptno)asdeptcount,
avg(sal)asdeptavgsal
fromempagroupbydeptno;
--------14---------
select
a.ename,
(selectb.dnamefromdeptbwhereb.deptno=a.deptno)asdeptname,
sal
fromempa;
--------15---------
select
a.deptno,
a.dname,
a.loc,
(selectcount(deptno)fromempbwhereb.deptno=a.deptnogroupbyb.deptno)asdeptcount
fromdepta;
--------16---------
selectjob,avg(sal)fromempgroupbyjob;
--------17---------
selectdeptno,min(sal)fromempwherejob='MANAGER'groupbydeptno;
--------18---------
selectename,(sal+nvl(comm,0))*12assalpersalfromemporderbysalpersal; ORACLE 子句查詢,分組等
A.同表子查詢做爲條件
a. 給出人口多於 Russia(俄國)的國家名稱 SELECT name FROM bbc
WHERE population>
(SELECT population FROM bbc
WHERE name='Russia')
b.給出'India'(印度), 'Iran'(伊朗)所在地區的全部國家的全部信息 SELECT * FROM bbc
WHERE region IN
(SELECT region FROM bbc
WHERE name IN ('India','Iran'))
c.給出人均 GDP 超過'United Kingdom'(英國)的歐洲國家. SELECT name FROM bbc
WHERE region='Europe' AND gdp/population >
(SELECT gdp/population FROM bbc
WHERE name='United Kingdom')
d.這個查詢實際上等同於如下這個:
select e1.ename from emp e1,(select empno from emp where ename = 'KING') e2 whe
re e1.mgr = e2.empno;
你能夠用 EXISTS寫一樣的查詢,你只要把外部查詢一欄移到一個像下面這樣的子查詢環境
中就能夠了:
select ename from emp e
where exists (select 0 from emp where e.mgr = empno and ename = 'KING');
當你在一個 WHERE 子句中寫 EXISTS時,又等於向最優化傳達了這樣一條信息,即你想讓外
部查詢先運行,使用每個值來從內部查詢(假定: EXISTS=由外而內)中獲得一個值。
B.異表子查詢做爲條件
a.select * from studentExam where studentid=( select studentid from student whe
re name='吳麗麗');
b.select * from studentexam where studentid in (
select studentid from student) order by studentid;
c.select * from student where studentid in (select studentid from studentexam w
here mark>80);
3.select studentexam.mark,studentexam.studentid as seid, student.studentid,stud
ent.name from studentexam,student where student.studentid=studentexam.studentid;
過濾分組:
順序爲先分組,再過濾,最後進行統計(實際值).
select studentid,count(*) as highpasses from studentexamwhere mark>70group by s
tudentid;
假使咱們不想經過數據表中的實際值,而是經過聚合函數的結果來過過濾查詢的結果.
select studentid,avg(mark) as averagemarkfrom studentexamwhere avg(mark)<50 or
avg(mark)>70group by studentid;(此句錯誤,where 句子是不能用聚合函數做條件的)此
時要用 having.
select studentid,avg(mark) from studentexam group by studentid having avg(mark)
>70 or avg(mark)<50;
select studentid,avg(mark) from studentexam where studentid in(1,7,9,5)group by
studentid having avg(mark)>70;(先分組,再過濾,再 having聚合,最後再統計).
select studentid ,avg(mark) as averagemarkfrom studentexamwhere examid in(5,8,1
1)group by studentidhaving avg(mark)<50 or avg(mark)>70;
返回限定行數查詢:
select name from student where rownum<=10;
oracle 中使用 rownum 關鍵字指定,但該關鍵字必須在 where 子句中與一個比較運算符一塊兒
指定,而不能與order by 一塊兒配合便用,由於rownum 維護的是原始行號.若是須要用group
by\order by 就用子句查詢做表使用的方法:
select studentid,averagemark from(select studentid,avg(mark) as averagemarkfrom
studentexamgroup by studentid order by averagemark desc)where rownum<=10; oracle 存儲過程語法:Oracle存儲過程入門學習基本語法
1.基本結構
createOR REPLACEPROCEDURE 存儲過程名字
( 參數1IN NUMBER, 參數2IN NUMBER
)IS 變量1INTEGER:=0; 變量2DATE;
BEGIN
END 存儲過程名字
2.selectINTOSTATEMENT 將select查詢的結果存入到變量中, 能夠同時將多個列存儲多個變量中, 必須有一條記錄, 不然拋出 異常(若是沒有記錄拋出NO_DATA_FOUND) 例子:
BEGIN
selectcol1,col2into 變量1,變量2 FROMtypestructwherexxx;
EXCEPTION
WHENNO_DATA_FOUNDTHEN
xxxx;
END;
...
3.IF 判斷
IFV_TEST=1THEN
BEGIN
dosomething
END;
ENDIF;
4.while 循環
WHILEV_TEST=1 LOOP
BEGIN
XXXX
END;
END LOOP;
5.變量賦值
V_TEST:=123;
6.用for in 使用cursor
...
IS
CURSOR curIS select*FROM xxx;
BEGIN
FOR cur_resultincurLOOP
BEGIN
V_SUM :=cur_result.列名1+cur_result.列名2
END;
ENDLOOP;
END;
7.帶參數的cursor
CURSOR C_USER(C_IDNUMBER) IS selectNAME FROM USERwhereTYPEID=C_ID;
OPEN C_USER(變量值);
LOOP
FETCHC_USER INTOV_NAME;
EXITFETCH C_USER%NOTFOUND;
dosomething
END LOOP;
CLOSE C_USER;
8.用pl/sqldeveloperdebug 鏈接數據庫後創建一個Test WINDOW 在窗口輸入調用SP的代碼,F9開始debug,CTRL+N單步調試 oracle語法:Oracle 觸發器語法及實例基礎知識(一) 一Oracle觸發器語法 觸發器是特定事件出現的時候, 自動執行的代碼塊 相似於存儲過程, 觸發器和存儲過程的區別 在於:存儲過程是由用戶或應用程序顯式調用的,而觸發器是不能被直接調用的 功能:
一、 容許/限制對錶的修改
二、 自動生成派生列, 好比自增字段
三、 強制數據一致性
四、 提供審計和日誌記錄
五、 防止無效的事務處理
六、 啓用複雜的業務邏輯 觸發器觸發時間有兩種:after 和before
一、觸發器的語法:
CREATE[OR REPLACE]TIGGER 觸發器名 觸發時間 觸發事件
ON 表名
[FOR EACHROW]
BEGIN
pl/sql 語句
END 其中: 觸發器名:觸發器對象的名稱 因爲觸發器是數據庫自動執行的, 所以該名稱只是一個名稱, 沒有實質的用途 觸發時間:指明觸發器什麼時候執行, 該值可取:
before---表示在數據庫動做的前觸發器執行;
after---表示在數據庫動做的後出發器執行 觸發事件:指明哪些數據庫動做會觸發此觸發器:
insert:數據庫插入會觸發此觸發器;
update:數據庫修改會觸發此觸發器;
delete:數據庫刪除會觸發此觸發器 表 名:數據庫觸發器所在的表
foreach row:對錶的每一行觸發器執行一次 若是沒有這一選項, 則只對整個表執行一次
二、舉例: 下面的觸發器在更新表auths的前觸發, 目的是不容許在週末修改表:
createtriggerauth_securebefore insertorupdate ordelete//對整表更新前觸發
onauths
begin
if(to_char(sysdate,'DY')='SUN'
RAISE_APPLICATION_ERROR(-20600,'不能在週末修改表auths');
endif;
end 例子:
CREATE OR REPLACE TRIGGER CRM.T_SUB_USERINFO_AUR_NAME AFTER UPDATE OF
STAFF_NAME
ON CRM.T_SUB_USERINFO
REFERENCING OLDAS OLD NEWAS NEW
FOR EACHROW
declare
begin
if:NEW.STAFF_NAME!=:OLD.STAFF_NAME then
begin 客戶投訴
update T_COMPLAINT_MANAGE set SERVE_NAME=:NEW.STAFF_NAME where
SERVE_SEED=:OLD.SEED; 客戶關懷
updateT_CUSTOMER_CARE setEXECUTOR_NAME=:NEW.STAFF_NAME
whereEXECUTOR_SEED=:OLD.SEED; 客戶服務
updateT_CUSTOMER_SERVICE setEXECUTOR_NAME=:NEW.STAFF_NAME
whereEXECUTOR_SEED=:OLD.SEED;
end;
endif;
endT_sub_userinfo_aur_name;
/
2 Oracle觸發器詳解 開始:
createtriggerbiufer_employees_department_id
beforeinsertorupdateofdepartment_idonemployees
referencingoldasold_valuenewasnew_value
foreach row
when(new_value.department_id<>80)
begin
:new_value.commission_pct :=0;
end;
/
一、觸發器的組成部分:
一、 觸發器名稱
二、 觸發語句
三、 觸發器限制
四、 觸發操做
1.一、觸發器名稱
createtrigger biufer_employees_department_id 命名習慣:
biufer(beforeinsertupdatefor eachrow)
employees表名
department_id列名
1.二、觸發語句 好比: 表或視圖上的DML語句
DDL語句 數據庫關閉或啓動,startupshutdown等等
beforeinsert orupdate
ofdepartment_id
onemployees
referencingoldasold_value
newasnew_value
foreach row 介紹說明:
一、 不管是否規定了department_id, 對employees表進行insert的時候
二、 對employees表的department_id列進行update的時候
1.三、觸發器限制
when(new_value.department_id<>80) 限制不是必須的 此例表示若是列department_id不等於80的時候, 觸發器就會執行 其中的new_value是表明更新的後的值
1.四、觸發操做 是觸發器的主體
begin
:new_value.commission_pct :=0;
end; 主體很簡單, 就是將更新後的commission_pct列置爲0 觸發:
insertinto employees(employee_id,last_name,first_name,hire_date,job_id,email,
department_id,salary,commission_pct)
values( 12345,’Chen’,’Donny’, sysdate,12, ‘donny@hotmail.com’,60,10000,.25);
selectcommission_pctfromemployeeswhere employee_id=12345;
二、觸發器的類型有: 觸發器類型:
一、 語句觸發器
二、 行觸發器
三、 INSTEAD OF觸發
四、 系統條件觸發器
五、 用戶事件觸發器
2.一、語句級觸發器.(語句級觸發器對每一個DML語句執行一次) 是在表上或者某些狀況下的視圖上執行的特定語句或者語句組上的觸發器 可以和 INSERT、
UPDATE、 DELETE或者組合上進行關聯 可是不管使用什麼樣的組合, 各個語句觸發器都只會針對 指定語句激活一次 好比, 不管update多少行, 也只會調用一次update語句觸發器 例子:
createor replacetrigger tri_test
afterinsertor updateor delete_disibledevent=> 測試,插入幾條記錄
insertinto test values(0,'ff');
insertinto test values(0,'ff');
insertinto test values(0,'tt'); 例子 2: 建立一個觸發器,不管用戶插入新記錄,仍是修改emp表的job列,都將用戶指定的job列的值轉換成大 寫.
create orreplacetriggertrig_job
beforeinsert orupdateof job
onemp
foreach row
begin
ifinserting then
:new.job:=upper(:new.job);
else
: new.job:=upper(:new.job);
endif;
end;
2.三、 insteadof觸發器.
(此觸發器是在視圖上而不是在表上定義的觸發器,它是用來替換所使用實際語句的觸發器.) 語法以下:
createor replacetriggertrig_test
insteadofinsertor update_disibledevent=>
2.五、數據庫級觸發器. 能夠建立在數據庫事件上的觸發器,包括關閉,啓動,服務器錯誤,登陸等.這些事件都是例子範圍的,不和 特定的表或視圖關聯. 例子:
createor replacetrigger trig_name
afterstartup_disibledevent=>
四、 測試
updateemployees_copyset salary=salary*1.1;
select*fromemployess_log;
五、 肯定是哪一個語句起做用? 便是INSERT/UPDATE/DELETE中的哪個觸發了觸發器? 能夠在觸發器中使用INSERTING/ UPDATING/ DELETING條件謂詞, 做判斷:
begin
ifinserting then
-----
elsifupdatingthen
-----
elsifdeletingthen
------
endif;
end;
ifupdating(‘COL1’) orupdating(‘COL2’) then
------
endif;
2.八、 [試驗]
一、 修改日誌表
alter tableemployees_log
add(actionvarchar2(20));
二、 修改觸發器, 以便記錄語句類型
then
l_action:=’Delete’;
else
raise_application_error(-20001,’Youshouldneverever getthiserror.’);
Insertintoemployees_log(Who,action,when)
Values(user,l_action,sysdate);
End;Createor replacetrigger biud_employee_copy
Beforeinsertorupdate ordelete
On employees_copy
Declare
L_actionemployees_log.action%type;
Begin
ifinserting then
l_action:=’Insert’;
elsifupdatingthen
l_action:=’Update’;
elsifdeleting
/
三、 測試
insert intoemployees_copy( employee_id,last_name, email, hire_date,job_id)
values(12345,’Chen’,’Donny@hotmail’,sysdate,12);
select*fromemployees_log oracle 基本語法備忘
2008 年 11 月 13 日 星期四 09:58
1.基本結構
CREATE OR REPLACE PROCEDURE 存儲過程名字
( 參數 1IN NUMBER, 參數 2IN NUMBER
) IS 變量1 INTEGER :=0; 變量2 DATE;
BEGIN END 存儲過程名字 2.SELECT INTO STATEMENT 將 select 查詢的結果存入到變量中,能夠同時將多個列存儲多個變量中,必須有一條 記錄,不然拋出異常(若是沒有記錄拋出 NO_DATA_FOUND) 例子: BEGIN SELECT col1,col2 into 變量 1,變量2 FROM typestruct where xxx; EXCEPTION WHEN NO_DATA_FOUND THEN xxxx; END; ... 3.IF 判斷 IF V_TEST=1 THEN BEGIN do something END; END IF; 4.while 循環 WHILE V_TEST=1 LOOP BEGIN XXXX END; END LOOP; 5.變量賦值 V_TEST := 123; 6.用 for in 使用 cursor ... IS CURSOR cur IS SELECT * FROM xxx; BEGIN FOR cur_result in cur LOOP BEGIN V_SUM :=cur_result.列名1+cur_result.列名2 END; END LOOP; END; 7.帶參數的 cursor CURSOR C_USER(C_ID NUMBER) IS SELECT NAME FROM USER WHERE TYPEID=C_ID; OPEN C_USER(變量值); LOOP FETCH C_USER INTO V_NAME; EXIT FETCH C_USER%NOTFOUND; do something END LOOP; CLOSE C_USER; 8.用 pl/sql developer debug 鏈接數據庫後創建一個Test WINDOW 在窗口輸入調用SP的代碼,F9開始debug,CTRL+N單步調試 關於 oracle 存儲過程的若干問題備忘
1.在 oracle中,數據表別名不能加 as,如:
selecta.appname from appinfoa;-- 正確
selecta.appname from appinfoas a;-- 錯誤 也許,是怕和oracle 中的存儲過程當中的關鍵字 as 衝突的問題吧
2.在存儲過程當中, select 某一字段時,後面必須緊跟 into,若是 select 整個記錄,利用遊標的話就另當別論了。
select af.keynode into kn fromAPPFOUNDATION af where af.appid=aid andaf.foundationid=fid;-- 有 into,正確編譯
select af.keynode fromAPPFOUNDATION af where af.appid=aid and af.foundationid=fid;-- 沒有 into,編譯報錯,提示:
Compilation
Error: PLS-00428: an INTOclause is expected in this SELECTstatement
3.在利用 select...into...語法時,必須先確保數據庫中有該條記錄,不然會報出"no data found"異常。 能夠在該語法以前,先利用 select count(*) from 查看數據庫中是否存在該記錄,若是存在,再利用 select...into...
4.在存儲過程當中,別名不能和字段名稱相同,不然雖然編譯能夠經過,但在運行階段會報錯
selectkeynode into kn fromAPPFOUNDATION whereappid=aidand foundationid=fid;-- 正確運行
select af.keynode into kn fromAPPFOUNDATION af where af.appid=appid and af.foundationid=foundationid;-- 運行階段報
錯,提示
ORA-01422:exact fetch returnsmore thanrequested number of rows
5.在存儲過程當中,關於出現 null 的問題 假設有一個表A,定義以下:
createtableA(
id varchar2(50) primary key not null,
vcount number(8) notnull,
bidvarchar2(50) not null -- 外鍵
); 若是在存儲過程當中,使用以下語句:
selectsum(vcount) into fcount fromAwhere bid='xxxxxx'; 若是 A 表中不存在 bid="xxxxxx"的記錄, 則 fcount=null(即便 fcount 定義時設置了默認值, 如: fcount number(8):=0 依然 無效, fcount仍是會變成 null),這樣之後使用 fcount 時就可能有問題,因此在這裏最好先判斷一下:
iffcount is null then
fcount:=0;
endif; 這樣就一切ok了。
一、建立存儲過程 create or replace procedure test(var_name_1 in type,var_name_2 out type) as --聲明變量(變量名 變量類型) begin --存儲過程的執行體 end test; 打印出輸入的時間信息 E.g: create or replace procedure test(workDate in Date) is begin dbms_output.putline('The input date is:'||to_date(workDate,'yyyy-mm-dd')); end test;
二、變量賦值 變量名 := 值; E.g: create or replace procedure test(workDate in Date) is x number(4,2); begin x := 1; end test;
三、判斷語句: if 比較式 then begin end; end if; E.g create or replace procedure test(x in number) is begin if x >0 then begin x := 0 - x; end; end if; if x = 0 then begin x: = 1; end; end if; end test;
四、 For 循環 For ... in ... LOOP --執行語句 end LOOP;
(1)循環遍歷遊標 create or replace procedure test() as Cursor cursor is select name from student; name varchar(20); begin for name in cursor LOOP begin dbms_output.putline(name); end; end LOOP; end test;
(2)循環遍歷數組 create or replace procedure test(varArray in myPackage.TestArray) as --(輸入參數varArray 是自定義的數組類型,定義方式見標題 6) i number; begin i := 1; --存儲過程數組是起始位置是從1開始的,與java、 C、 C++等語言不一樣。由於在Oracle中本是 沒有數組的概念的,數組其實就是一張 --表(Table),每一個數組元素就是表中的一個記錄,因此遍歷數組時就至關於從表中的第一條記錄開始遍 歷 for i in 1..varArray.count LOOP dbms_output.putline('The No.'|| i || 'record in varArray is:'||varArray(i)); end LOOP; end test;
五、 While 循環 while 條件語句 LOOP begin end; end LOOP; E.g create or replace procedure test(i in number) as begin while i < 10 LOOP begin i:= i + 1; end; end LOOP; end test;
六、數組 首先明確一個概念: Oracle中本是沒有數組的概念的,數組其實就是一張表(Table),每一個數組元素就是 表中的一個記錄。 使用數組時,用戶可使用Oracle已經定義好的數組類型,或可根據本身的須要定義數組類型。
(1)使用 Oracle自帶的數組類型 x array; --使用時須要須要進行初始化 e.g: create or replace procedure test(y out array) is x array; begin x := new array(); y := x; end test;
(2)自定義的數組類型 (自定義數據類型時,建議經過建立Package 的方式實現,以便於管理) E.g (自定義使用參見標題 4.2) create or replace package myPackage is -- Public type declarations type info is record( name varchar(20), y number); type TestArray is table of info index by binary_integer; --此處聲明瞭一個TestArray的類型數 據,其實其爲一張存儲Info數據類型的Table而已,及TestArray 就是一張表,有兩個字段,一個是 name,一個是y。須要注意的是此處使用了Index by binary_integer 編制該Table的索引項,也能夠 不寫,直接寫成: type TestArray is table of info,若是不寫的話使用數組時就須要進行初始化: varArray myPackage.TestArray; varArray := new myPackage.TestArray(); end TestArray;
7.遊標的使用 Oracle中Cursor 是很是有用的,用於遍歷臨時表中的查詢結果。其相關方法和屬性也很 多,現僅就經常使用的用法作一二介紹:
(1)Cursor 型遊標(不能用於參數傳遞) create or replace procedure test() is cusor_1 Cursor is select std_name from student where ...; --Cursor的使用方式1 cursor_2 Cursor; begin select class_name into cursor_2 from class where ...; --Cursor的使用方式2 可以使用 For x in cursor LOOP .... end LOOP; 來實現對Cursor 的遍歷 end test;
(2)SYS_REFCURSOR型遊標,該遊標是Oracle以預先定義的遊標,可做出參數進行傳遞 create or replace procedure test(rsCursor out SYS_REFCURSOR) is cursor SYS_REFCURSOR; name varhcar(20); begin OPEN cursor FOR select name from student where ... --SYS_REFCURSOR 只能經過OPEN方法來打開和 賦值 LOOP fetch cursor into name --SYS_REFCURSOR只能經過fetch into來打開和遍歷 exit when cursor%NOTFOUND; --SYS_REFCURSOR 中可以使用三個狀態屬 性: ---%NOT FOUND(未找到記錄信息) %FOUND(找到記錄信 息) ---%ROW COUNT(而後當前遊標所指向的行位置) dbms_output.putline(name); end LOOP; rsCursor := cursor; end test;
下面寫一個簡單的例子來對以上所說的存儲過程的用法作一個應用: 現假設存在兩張表,一張是學生成績表(studnet),字段爲: stdId,math,article,language,music,sport,total,average,step 一張是學生課外成績表(out_school),字段爲:stdId,parctice,comment 經過存儲過程自動計算出每位學生的總成績和平均成績,同時,若是學生在課外課程中得到的評價爲A, 就在總成績上加20分。 create or replace procedure autocomputer(step in number) is rsCursor SYS_REFCURSOR; commentArray myPackage.myArray; math number; article number; language number; music number; sport number; total number; average number; stdId varchar(30); record myPackage.stdInfo; i number; begin i := 1; get_comment(commentArray); --調用名爲get_comment()的存儲過程獲取學生課外評分信息 OPEN rsCursor for select stdId,math,article,language,music,sport from student t where t.step = step; LOOP fetch rsCursor into stdId,math,article,language,music,sport; exit when rsCursor%NOTFOUND; total := math + article + language + music + sport; for i in 1..commentArray.count LOOP record := commentArray(i); if stdId = record.stdId then begin if record.comment = 'A' then begin total := total + 20; go to next; --使用 go to跳出for循環 end; end if; end; end if; end LOOP; <<continue>> average := total / 5; update student t set t.total=total and t.average = average where t.stdId = stdId; end LOOP; end; end autocomputer;
--取得學生評論信息的存儲過程 create or replace procedure get_comment(commentArray out myPackage.myArray) is rs SYS_REFCURSOR; record myPackage.stdInfo; stdId varchar(30); comment varchar(1); i number; begin open rs for select stdId,comment from out_school i := 1; LOOP fetch rs into stdId,comment; exit when rs%NOTFOUND; record.stdId := stdId; record.comment := comment; recommentArray(i) := record; i:=i + 1; end LOOP; end get_comment;
--定義數組類型myArray create or replace package myPackage is begin type stdInfo is record(stdId varchar(30),comment varchar(1)); type myArray is table of stdInfo index by binary_integer; end myPackage;java

相關文章
相關標籤/搜索