plsql實例精講部分筆記
轉換sql:
create or replace view v_sale(year,month1,month2,month3,month4,month5,month6,month7,month8,month9,month10,month11,month12)
as
select
substrb(month,1,4),
sum(decode(substrb(month,5,2),‘01‘,sell,0)),
sum(decode(substrb(month,5,2),‘02‘,sell,0)),
sum(decode(substrb(month,5,2),‘03‘,sell,0)),
sum(decode(substrb(month,5,2),‘04‘,sell,0)),
DECLARE
STATEMENTS
BEGIN
STATEMENTS
EXCEPTION
STATEMENTS
END;
可執行部分必須存在
DECLARE
v_first_name VARCHAR2(35);
v_last_name VARCHAR2(35);
c_count CONSTANT NUMBER := 0;
BEGIN
SELECT first_name, last_name
INTO v_first_name, v_last_name
FROM student
WHERE student_id=123;
DBMS_OUTPUT.PUT_LINE(‘student_name: ‘ || v_first_name || ‘ ‘ || v_last_name);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE(‘There is no student with‘ || ‘ student id 123‘);
END;
PLSQL減少訪問數據庫的網絡傳輸
命名語句塊存儲在數據庫中,以後可以應用
DECLARE
v_name VARCHAR2(50);
v_total NUMBER;
BEGIN
SELECT i.first_name || ‘ ‘ || i.last_name, COUNT(*)
INTO v_name, v_toal
FROM instructor i, section s
WHERE i.instructor_id = s.instructor_id
AND i.instructor_id = 123
GROUP BY i.first_name || ‘ ‘ || i.last_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.put_line(‘There is no such instructor‘);
END;
編譯過程: 語法檢查, 綁定(變量分配存儲地址), 生成偽代碼
. plsql結尾(可選) /執行plsql
set serveroutput on;顯示輸出結果
& 或者 && 替代變量前綴
使用替代變量獲取輸入值
替代變量沒有分配內存,不能用作輸出
& 每次出現替代變量都要重新輸入參數
set verify off; 不顯示具體替換工程
出現多次 && 只需輸入一次參數值 加上 ‘’
set define character 修改&為其他字符
set define on 重新修改為&
set serveroutput on size 5000; 修改默認緩存大小為5000字節
7一些函數類型
聲明變量如果沒有賦值 則為null,dbms_output輸出時內容為空
|| 不要用空格
coalesce(sum(data) , null,0) 返回第一個不是null的值
nvl(sum(data),0) oracle ifnull(sum(data),0) mysql
decode(sign(salary-8000),1,salary*1.15,-1,salary*1.2,salary) sign(data) 返回-1 1 0
to_char(34.56,’fm999.00’) 34.56
to_char(0.123,’fm999.00’) .12
9沒有數字顯示空格,0沒有數字顯示0 。fm去掉如果是9顯示的空格。
to_char(0.123,’fm990.00’)
TO_NUMBER(REGEXP_REPLACE(status,‘[^0-9]‘,‘‘)) > 30
status中非數字轉換為空字符 在用to_number函數
select to_number(’RMB234234.4350′,’L999999.0000′) from dual;
select username,decode(lock_date,null,‘unlocked‘,‘locked‘) status from t;
anchroed數據類型
declare
v_name sys_user.usr_name%type;
字節 字符
varchar2(n) 與字節數有關,a 1b 我2b varchar2(n char) 與字符數有關 a 1一個字符 哦 1個字符 每個字符占2個字節
nvarchar(n) 與字符數有關 可以容納n個字符 每個字符2個字節
varchar2(n) number(m,n) 四舍五入
date timestamp binary_integer 用於索引plsql表 boolean一般用char(1)
oracle 沒有Boolean plsql有Boolean 輸出不能直接用Boolean類型值
函數:trunc(sysdate, ‘hh24’) 2013-01-06 17:00:00 trunc(124.235,2) 124.23
to_char(sysdate, ‘hh24’) 17 sysdate+numtodsinterval(30,’minute’)
substr instr trunk to_date to_timestamp
date相減是天數(帶小數) timestamp相減是時間格式
timestamp精確到毫秒
trunc不支持timestamp
聲明exception變量 e_show_exception_scope exception; raise exception拋出異常
when e_show_exception_show then ….
《inner_block》《outer_block》
v_bool Boolean; null true false
if v_bool is null then… end;
v_bool := nvl(v_bool , false);
if(v_bool) then dbms_output.put_line(‘false’);
sequence.currval nextval
dml
select into
commit rollback savepoint xx rollback to savepoint xxx
trim ltrim rtrim
8條件語句
if then else end if
if then elseif then else end if
case 搜索case 表達式case 3種形式
case xxx類型 與when xx返回類型一樣
case xxx when xx then xx; when xxx then xx ; else xx; end case;
搜索case when返回Boolean類型值
case when xxx then xx ; else xx; end case;
表達式case
賦值:=case end
select case。。。end into
表達式case 直接end,不是end case 表達式case中沒有 符號 ;
嵌套case
v_date date:=to_date(&sv_date,‘yyyy-mon-dd‘);
to_char(v_date,‘d‘) 數字形式星期 1234567 日一二三四五六七
nullif(exp1,exp2) exp1=exp2返回null,否則返回exp1
exp1不能賦值字面值null
coalesce(exp1,exp2,exp3,…) 返回第一個不是null的值
9循環
loop … end loop
if xx then exit end if
exit when condition
while condition loop
statements
end loop
null不能與任何變量進行比較 false
循環計數器經常使用 binary_integer
for v_counter in 1..5 loop statements end loop
for中v_counter被隱含定義和 遞增,for外面不能引用v_counter
for v_counter in reverse 1..5 loop exit when .. end loop
reverse逆序
if then continue end if;
continue when
10異常
exception when then
no_data_found to_many_rows zero_divide login_denied program_error
value_error invalid_number dup_value_on_index
others
when others then …..
聲明部分的異常無法處理,除非外面還有語句塊包圍處理,
重新拋出 when exception then raise
raise_application_error(-20001,’zip code is not valid’);
11遊標
創建遊標 打開遊標 檢索遊標 關閉遊標
記錄類型
遊標屬性: %notfound %found %isopen %rowcount
sql%rowcount 隱藏遊標可以用 沒有數據拋異常 不用sql%rowcount=0判斷
12.高級遊標
或者open 時帶參數
會加鎖
13.觸發器
for each row 之能增刪改操作
刪除一個表,表上的觸發器也會刪除
使用:
一些復雜業務規則;統計值;自動生成衍生列的值;防止無效事務
事務回滾或者提交,觸發器執行的操作也會提交或者回滾。 自治事務例外
自治事務都會提交 autononous transaction commit
:new :old
如果某行沒有update,:new是null,所以用nvl(new.zip,’’)
操作view,底層數據庫表也會修改
刪除時如果存在約束,需要先刪除外鍵表中記錄
instead of 觸發器比較復雜,要考慮不同表之間的關系,以及特定關系可能引起的負面影響
視圖中插入數據時,外鍵zip在zipcode表中不存在對應記錄,則先在zipcode表中插入對應記錄
14.復合觸發器
變異表問題:
select into 操作的表section正在被修改,是變異的,改用如下方式:
復合觸發器:
drop trigger sss
drop package xxx
GRANT EXECUTE ON verify_function_11G TO PUBLIC;
before each row 才能用 :new
作業1:
create or replace trigger instructor_compound
for insert or update on instructor
compound trigger
v_day varchar2(10);
v_hour varchar2(5);
before statement is
begin
v_day := rtrim(to_char(sysdate,‘day‘));
v_hour := to_char(sysdate,‘hh24‘);
if v_day like (‘s%‘) then
raise_application_error(-20001,‘this table can not be
modified on off day‘);
elseif v_hour <9 or v_hour >17 then
raise_application_error(-20001,‘this table can not be
modified on off day‘);
end if;
end before statement;
before each row is
begin
:new.instructor_id := seq_instructor_id.nextval;
if inserting then
:new.created_by := user;
:new.created_date := sysdate;
elseif updating then
:new.created_by := :old.created_by;
:new.created_date := :old.created_date;
end if;
:new.modified_by := user;
:new.modified_date := sysdate;
end before each row;
end instructor_compound;
作業2:
create or replace trigger zipcode_compound
for insert or update on zipcode
v_type varchar2(10);
v_count number;
v_table varchar2(20);
before each row is
begin
:new.modified_by := user;
:new.modified_date := sysdate;
end before each row;
after statement is
if inserting then
v_type := ‘insert‘;
else updating then
v_type := ‘update‘;
end if;
v_count := sql%rowcount;
v_table := ‘zipcode‘;
update zipcode
set transaction_user=user,
transaction_date=sysdate,
transaction_rowcount=v_count
where table_name = v_table
and trancaction_name=v_type;
if sql%notfound then
insert into transaction
values(v_table,v_type,user,sysdate,v_count);
end if;
end after statement;
end zipcodecompound;
15章:集合
1.pl/sql表
聯合數組和嵌套表類似數據庫單列表,通過下標訪問,具有相同結構。
差別:嵌套表可以存儲在數據庫列中,聯合數組不可以。
聯合數組:
嵌套表:
要初始化,否則報異常 構造方法()
長度要擴展 extend
delete(10) delete(1,3) prior(3) next(3) trim(2)
count last first extend trim
declare
type index_by_type is table of number
index by binary_integer;
index_by_table index_by_type;
type nested_type is table of number;
nested_table nested_type :=
nested_type(1,2,3,4,5,6,7,8,9,10);
begin
for i in 1..10 loop
index_by_table(i) := i;
end loop;
if index_by_table.exists(3) then
dbms_output.put_line(‘index_by_table(3)=‘||
index_by_table(3));
end if;
--delete 10th element from a collection
nested_table.delete(10);
--delete elements 1 through 3 from a colleciton
nested_table.delete(1,3);
index_by_table.delete(10);
dbms_output.put_line(‘nested_table.count=‘||nested_table.count);
dbms_output.put_line(‘nested_table.first=‘||nested_table.first);
dbms_output.put_line(‘nested_table.last=‘||nested_table.last);
dbms_output.put_line(‘nested_table.prior(2)=‘||nested_table.prior(2));
dbms_output.put_line(‘nested_table.next(2)=‘||nested_table.next(2));
dbms_output.put_line(‘index_by_table.count=‘||index_by_table.count);
dbms_output.put_line(‘index_by_table.first=‘||index_by_table.first);
dbms_output.put_line(‘index_by_table.last=‘||index_by_table.last);
dbms_output.put_line(‘index_by_table.prior(2)=‘||index_by_table.prior(2));
dbms_output.put_line(‘index_by_table.next(2)=‘||index_by_table.next(2));
nested_table.trim(2);
dbms_output.put_line(‘nested_table.count=‘||nested_table.count);
nested_table.trim();
dbms_output.put_line(‘nested_table.count=‘||nested_table.count);
end;
當從中間刪除元素時,delete保留刪除元素的索引,則 count和last值就會不同。
last會比count值大
trim長度會改變,重新賦值需要 exntend
變長數組:
變長數組擴展不能超過最大尺寸,否則報錯。
extend(2,4) 末尾追加第四個元素的2個副本
limit限制長度
varray 變長數組不能delete
chr(10)換行
多層數組:
16記錄類型
type xxx is record (name type,…)
%rowtype
not null需要初始化,否則報錯
如果都是用戶自定義類型record ,如果類型名不同不可以相互賦值, 表記錄或者遊標自定義類型之間可以相互賦值。
如果輸入內容較多,修改大小
17章 本地動態sql
例子:
18章 批量sql
2.indices of 可以處理稀疏的集合,嵌套表或者聯合數組。
3 values of 集合中元素做索引
創建一個有字段的空表
cursor要一行行檢索
select buck collect into 會批量檢索 直接講結果存保存在了集合中
1.select bulk collect into填充嵌套表時,會自動初始化和擴展。
2.bulk collect into select不返回任何數據時,不拋出no_data_found異常,所以要自己檢查返回的集合是否有數據。
3.bulk collect 不會限制集合的尺寸,並自動擴展,所以當select返回大量數據時,最好限制結合寄過集。 通過使用帶有遊標select的bulk collect,以及添加limit.
帶有limit的bulk collect子句,一次性從student檢索50行數據。每個集合最多50條記錄。
合並forall select bulk collect into
plsql實例精講部分筆記