Oracle (06)常見的連線資料庫技術.迴圈
常見的連線資料庫技術
JDBC :Java訪問資料庫的技術
PL/SQL :過程化SQL語言 , 時直接在資料庫內部操作資料的一種語言!
proc/c++ : c和c++訪問資料庫的技術
ODBC :微軟提供的訪問資料庫的技術
OCI :ORACLE底層的連線介面!
這些技術, 需要使用到1521埠號
簡介 *
是一種程式語言 ,過程化SQL語言 !
是對SQL語句的擴充套件, 目前支援的資料庫較少!
擴充套件的時SQL的過程
PL/SQL語法格式 *
回憶使用Java 列印輸出一句話的格式:
class Demo{ //成員位置 宣告一些成員 public static void main(String[] args){ try{ //程式的執行部分 System.out.println("hello Java"); }catch(Exception e){ //異常處理位置 } } }
PL/SQL格式:
declare
--宣告區
begin
--執行區域
exception
--異常處理區
end;
-
申明區: 用來定義變數和型別, 如果沒有申明的元素, 可以不寫declare
-
執行區: 用來執行PL/SQL語句 和 SQL語句
-
異常處理區: 用來處理執行區發生的異常, 就像Java中的catch塊!
向控制檯輸出文字
Java中語法格式: System.out.println(“Hello Java”);
PL/SQL語法格式: dbms_output.put_line(‘Hello PLSQL’);
Java語言, 預設就是打開了對於控制檯輸出的許可權.
PL/SQL中, 如果想要向控制檯輸出文字, 必須在程式的第一行將資料庫服務端的輸出狀態設定為開啟狀態 !
案例:
–開啟輸出狀態
set serveroutput on;
begin
dbms_output.put_line(‘Hello PLSQL’);
end;
註釋
– : 單行註釋
/**/: 多行註釋
識別符號
規則與Java基本相同
不能是PLSQL /SQL 的關鍵字
長度最大限制為31個字元
變數 *
Java定義變數的格式:
資料型別 變數名 = 初始化值 ;
在SQL中 ‘=‘符號已經被比較運算佔用了, 用來比較是否相等 ! 那麼’=’ 就無法用來進行賦值操作 !
在PL/SQL中使用 ':='進行 賦值運算 !
PL/SQL定義變數:
變數名 資料型別(長度) := 初始化值;
PL/SQL中常見的資料型別:
1. number : 數字 (整型和浮點型)
2. char : 定長字串
3. varchar2: 變長字串
4. date : 日期型別
5. boolean : 布林型別
6. binary_integer : 整型數字
參考型別: ref
複合型別: record型別 table型別 cursor型別
大容量大資料型別:BLOB CLOB 用來儲存音訊 , 視訊, 電子書, 圖片等!
我們一般儲存音視訊檔案不用這種 大容量型別 , 而是採用如下方式:
1. 將檔案按照指定的目錄結構進行本地檔案儲存
2. 將檔案所在的路徑字串, 儲存到資料庫中
練習:
按照上述的語法格式, 宣告數字型別的變數 a 並將其輸出到控制檯 !
set serveroutput on;
declare
haha number := 100;
begin
dbms_output.put_line(haha);
end;
常量
常量在宣告時必須賦值, 且無法更改值的內容 !
格式: 變數名 constant 資料型別(長度) := 初始值;
練習:
按照上述的語法格式, 定義一個常量a , 不進行初始化賦值, 嘗試輸出並列印, 觀察報錯 ! 然後初始化賦值, 並列印!
set serveroutput on;
declare
a constant number ;
begin
dbms_output.put_line(a);
end;
上述程式碼丟擲錯誤: PLS-00322: 常數 ‘A’ 的宣告必須包含初始賦值
set serveroutput on;
declare
a constant number := 1000;
begin
dbms_output.put_line(a);
end;
非空變數
在PL/SQL中 尚未初始化的變數 預設值為null
非空變數 表示: 變數不可為null , 在宣告時必須賦值!
通過not null修飾的變數, 就是非空變數
格式: 變數名 資料型別(長度) not null := 初始化值 ;
案例:
set serveroutput on;
declare
abcd number not null;
begin
dbms_output.put_line(abcd);
end;
上述案例, 因為沒有給not null變數 初始化值,導致出現瞭如下錯誤:
PLS-00218: 宣告為 NOT NULL 的變數必須有初始化賦值
案例:
set serveroutput on;
declare
abcd number not null := 20;
begin
dbms_output.put_line(abcd);
end;
模仿表格欄位宣告變數
我們PL/SQL在開發中, 更多的操作 , 在於操作資料庫的表格 , 對其進行增刪改差! 那麼在變數定義時, 我們大多數時候 , 會參考表格欄位進行變數的宣告!
練習:
定義兩個變數, 名稱為 salary , last_name ,並給其初始化賦值, 將其輸出列印 !
salary的型別與長度 與 s_emp表格中 salary欄位一致
last_name的型別與長度 與 s_emp表格中 last_name欄位一致
set serveroutput on;
declare
salary number(11,2) :=88888;
last_name varchar2(25) := ‘董菲菲’;
begin
dbms_output.put_line(‘員工的姓:’||last_name||’,月薪:’||salary);
end;
引用 表格欄位型別 來宣告變數 ***
格式: 變數名 表名.欄位名%type := 初始值;
練習:
定義變數, 名稱為id ,salary , last_name ,dept_id並給其初始化賦值, 將其輸出列印 !
- salary的型別與長度 與 s_emp表格中 salary欄位一致
- last_name的型別與長度 與 s_emp表格中 last_name欄位一致
- id的型別與長度 與 s_emp表格中 id欄位一致
- dept_id的型別與長度 與 s_emp表格中 dept_id欄位一致
set serveroutput on;
declare
id s_emp.id%type := 10001;
last_name s_emp.last_name%type := ‘董飛飛飛非’;
salary s_emp.salary%type := 8888.88;
dept_id s_emp.dept_id%type := 10;
begin
dbms_output.put_line(‘員工id:’||id||’,員工姓:’||last_name||’,員工所在部門:’||dept_id||’,員工月薪:’||salary);
end;
record 型別 ***
類似 Java中的類 , 把多個不同的資料型別 封裝為一個自定義的型別
建立自定義型別的語法格式:
便攜在宣告區:
type 名稱 is record(
內部變數名1 資料型別(長度),
內部變數名2 資料型別(長度),
...
內部變數名n 資料型別(長度),
);
宣告自定義型別變數的語法格式:
變數名 自定義型別名稱;
操作record型別變數的屬性, 對其進行賦值與取值操作
賦值(set): record變數名.內部變數名 := 值;
取值(get): record變數名.內部變數名;
案例:
定義一個record型別 並宣告變數 給屬性賦值,取出並列印 :
欄位(id,salary,last_name)與s_emp表格中的 (id,salary,last_name) 一致!
set serveroutput on;
declare
type myemp is record(
id s_emp.id%type;
salary s_emp.salary%type;
last_name s_emp.last_name%type;
);
myemp1 myemp;
begin
myemp1.id := 10002;
myemp1.salary := 888888;
myemp1.last_name := 'dongfei';
dbms_output.put_line('員工編號:'||myemp1.id||',員工姓名:'||myemp1.last_name||',員工月薪:'||myemp1.salary);
end;
練習:
定義一個record型別變數, 包含s_dept表格中的所有欄位(id,name ,region_id) , 並宣告變數, 給屬性賦值, 取出列印 !
set serveroutput on;
declare
type mydept is record(
id s_dept.id%type,
name s_dept.name%type,
region_id s_dept.region_id%type
);
myd1 mydept;
begin
myd1.id := 10001;
myd1.name := ‘jiaoji’;
myd1.region_id := 10;
dbms_output.put_line(‘部門編號:’||myd1.id||’,部門名稱:’||myd1.name||’,部門地區所在編號:’||myd1.region_id);
end;
引用表格的型別 ***
表名%rowtype 是一個record型別, 型別中的變數列表, 與表中的欄位列表完全一致 !
宣告一個 s_dept表格型別的 變數, 並賦值, 取出列印
set serveroutput on;
declare
myd1 s_dept%rowtype;
begin
myd1.id := 10001;
myd1.name := 'jiaoji';
myd1.region_id := 10;
dbms_output.put_line('部門編號:'||myd1.id||',部門名稱:'||myd1.name||',部門地區所在編號:'||myd1.region_id);
end;
從資料庫查詢一行資料, 並賦值給一個record型別的變數 ***
格式:
select 欄位列表 into record型別變數名 from 表名 where 條件…;
格式要求:
select語句查詢的欄位列表 必須與 record封裝的屬性列表完全一致 !
練習:
使用s_emp表格的record型別, 並查詢s_emp表格 中的 id為20的員工的資訊, 賦值給這個型別的變數, 取出值, 並列印
--設定伺服器輸出狀態 為開啟
set serveroutput on;
declare
--宣告一個表格行型別的 record變數
myemp s_emp%rowtype;
begin
--查詢s_emp表格中id為20的員工資訊, 並賦值給上面建立的變數
select * into myemp from s_emp where id=20;
--取出其中的資料 並輸出列印
dbms_output.put_line('員工編號:'||myemp.id||',員工月薪:'||myemp.salary);
end;
練習:
建立s_dept表格的行型別變數, 查詢s_dept表格中 部門編號為35的部門資訊, 並將其賦值給變數, 取出變數中資料並列印 !
set serveroutput on;
declare
mydept s_dept%rowtype;
begin
select * into mydept from s_dept where id=35;
dbms_output.put_line('部門編號:'||mydept.id||',部門名稱:'||mydept.name);
end;
table型別 *
類似Java中學習過的 Map集合, 是一個鍵值對的容器, 儲存的是雙值
語法:
-
定義一個型別
type 型別名稱 is table of 值型別 index by 鍵型別; -
根據型別定義變數
變數名 型別名稱; -
向容器中設定值, 取值:
- 設定
變數名(key) := 值; - 獲取
變數名(key);
- 設定
練習:
定義一個table型別 , 要求key為binary_integer , 值型別為number
要求向其中儲存5個數據, 然後取出列印 :
set serveroutput on;
declare
type mytab is table of number index by binary_integer;
mt mytab;
begin
mt(0):=10001;
mt(1):=10002;
mt(2):=10003;
mt(3):=10004;
mt(4):=10005;
dbms_output.put_line(mt(0));
dbms_output.put_line(mt(1));
dbms_output.put_line(mt(2));
dbms_output.put_line(mt(3));
dbms_output.put_line(mt(4));
end;
迭代table型別的資料 **
table型別 可以通過迭代方法 獲取第一個, 下一個 和 最後一個值的key:
table變數.first(): 獲取table變數儲存的第一個元素的 key
table變數.next(當前key): 獲取當前元素的下一個元素的key
table變數.last(): 獲取最後一個元素的key
案例:
定義一個table型別 , 要求key為binary_integer , 值型別為number
要求向其中儲存5個數據, 然後取出列印 :
set serveroutput on;
declare
type mytab is table of number index by binary_integer;
mt mytab;
mt_index binary_integer;
begin
mt(-100):=10001;
mt(100):=10002;
mt(22):=10003;
mt(37):=10004;
mt(45):=10005;
–讓索引值, 在迭代之前, 等於我們table型別變數的第一個key
mt_index := mt.first();
dbms_output.put_line(mt(mt_index));
mt_index := mt.next(mt_index);
dbms_output.put_line(mt(mt_index));
mt_index := mt.next(mt_index);
dbms_output.put_line(mt(mt_index));
mt_index := mt.next(mt_index);
dbms_output.put_line(mt(mt_index));
mt_index := mt.next(mt_index);
dbms_output.put_line(mt(mt_index));
end;
變數作用域
編寫程式碼的格式, 是可以互相巢狀的, 例如:
declare
begin
--全域性位置
declare
begin
--區域性位置
end;
end;
set serveroutput on;
declare
i number:=100;
begin
declare
i number:=1000;
begin
dbms_output.put_line(i);
end;
end;
上述的案例, 結果輸出為1000 , 我們訪問的規則為 就近原則 .
如果在擁有相同名稱的區域性變數和全域性變數時, 我們想要訪問全域性變數, 怎麼做? 可以給程式碼塊新增標籤 來區分:
set serveroutput on;
<<haha>>
declare
i number:=100;
begin
declare
i number:=1000;
begin
dbms_output.put_line(haha.i);
end;
end;
上述案例 輸出結果 為 100;
if *****
語法一:
Java:
if(條件){
//如果條件為true , 則執行這裡
}
PL/SQL:
if 條件 then
–如果條件為true , 則執行這裡
end if;
語法二:
Java:
if(條件){
//如果條件為true , 則執行這裡
}else{
//如果條件為false , 則執行這裡
}
PL/SQL:
if 條件 then
–如果條件為true , 則執行這裡
else
–如果條件為false , 則執行這裡
end if;
語法三:
Java:
if(條件1){
//如果條件1為true , 則執行這裡
}else if(條件2){
//如果條件1為false ,且條件2為true, 則執行這裡
}
PL/SQL:
if 條件1 then
–如果條件1為true , 則執行這裡
elsif 條件2 then
–如果條件1為false ,且條件2為true, 則執行這裡
end if;
語法四:
Java:
if(條件1){
//如果條件1為true , 則執行這裡
}else if(條件2){
//如果條件1為false ,且條件2為true, 則執行這裡
…
}else{
//以上n個條件 都為false 則這裡執行
}
PL/SQL:
if 條件1 then
–如果條件1為true , 則執行這裡
elsif 條件2 then
–如果條件1為false ,且條件2為true, 則執行這裡
…
elsif 條件n then
–如果以上條件都為false ,且條件n為true, 則執行這裡
else
–如果以上條件都為false,則執行這裡
end if;
接收使用者鍵盤輸入, 結合if演示案例
在執行區域, 給變數賦值時使用:
格式: 變數名 := &提示文字;
: 提示文字 不需要通過引號引住
案例:
-
接收使用者輸入的兩個數字, 並輸出較大的那一個!
set serveroutput on;
declare
x number;
y number;
begin
–接收使用者的輸入
x := &請輸入第一個數字;
y := &請輸入第二個數字;if x>y then dbms_output.put_line('較大的數字為:'||x); else dbms_output.put_line('較大的數字為:'||y); end if; end;
迴圈
任何迴圈都可以通過如下語法結束:
if 條件 then
exit;
end if;
loop迴圈(簡單迴圈) ***
語法格式:
loop
迴圈體
exit when 退出條件; --如果這句話不存在, 則迴圈為死迴圈
end loop;
練習: 迴圈輸出 1-10的數字
set serveroutput on;
declare
i number :=1;
begin
loop
dbms_output.put_line(i);
exit when i=10;
i := i+1;
end loop;
end;
練習: 迴圈輸出 10-1的數字
set serveroutput on;
declare
i number := 10;
begin
loop
dbms_output.put_line(i);
exit when i=1;
i:=i-1;
end loop;
end;
while迴圈 *****
語法:
while 迴圈條件 loop
迴圈體
end loop;
與Java中while迴圈定義 完全相同
練習: while迴圈輸出 1-10的數字
set serveroutput on;
declare
i number :=1;
begin
while i!=11 loop
dbms_output.put_line(i);
i:=i+1;
end loop;
end;
練習: while迴圈輸出 10-1的數字
set serveroutput on;
declare
i number :=10;
begin
while i!=0 loop
dbms_output.put_line(i);
i:=i-1;
end loop;
end;
for迴圈 (智慧迴圈) *****
智慧: 指的是, 迴圈變數自動變化 , 迴圈變數只能讀取, 不可修改!
迴圈變數只能是整型; 迴圈變數會自動隨著迴圈從初始值到最終值每次加一!
語法格式:
for 迴圈變數名 in 初始值..最終值 loop
迴圈體
end loop;
練習: for迴圈輸出 1-10的數字
set serveroutput on;
begin
for i in 1..10 loop
dbms_output.put_line(i);
end loop;
end;
練習: for迴圈輸出 10-1的數字
set serveroutput on;
begin
for i in 1..10 loop
dbms_output.put_line(11-i);
end loop;
end;
反轉for迴圈
與正常的for迴圈相反, 迴圈變數的初始值 ,大於 迴圈變數的最終值, (倒序迴圈)
語法格式:
for 迴圈變數名 in reverse 最終值..初始值 loop
迴圈體
end loop;
練習: 反轉for迴圈輸出 10-1的數字
set serveroutput on;
begin
for i in reverse 1..10 loop
dbms_output.put_line(i);
end loop;
end;
多重迴圈的退出問題 ***
練習:
編寫一個兩層迴圈 , 外層迴圈迴圈10次, 內層迴圈迴圈10次!
當外層迴圈變數為7時, 內層迴圈為8時, 退出外層迴圈
set serveroutput on;
declare
x number :=0;
y number :=0;
begin
while x<10 loop
y :=0;
while y<10 loop
dbms_output.put_line('x:'||x||',y:'||y);
if x=7 and y=8 then
exit;
end if;
y:=y+1;
end loop;
x:=x+1;
end loop;
end;
上述程式碼出現了問題, 退出迴圈時, 只是退出了內層迴圈, 外層迴圈還在繼續 .
解決問題的方案 與 java基本一致, 給迴圈新增標籤名
格式: 在迴圈程式碼前一行:<<標籤名>>
在退出迴圈時, exit 標籤名;
set serveroutput on;
declare
x number :=0;
y number :=0;
begin
<<dongfei>>
while x<10 loop
y :=0;
while y<10 loop
dbms_output.put_line('x:'||x||',y:'||y);
if x=7 and y=8 then
exit dongfei;
end if;
y:=y+1;
end loop;
x:=x+1;
end loop;
end;
GOTO 語句 *
我們可以在程式碼中 通過<<>>新增標籤
GOTO語句的作用: 當代碼執行到GOTO語句時, 可以選擇跳轉到某一個標籤位置 繼續執行 !
新增標籤的格式: <<標籤名>>
GOTO語句格式: goto 標籤名;
set serveroutput on;
declare
begin
dbms_output.put_line('1');
dbms_output.put_line('2');
dbms_output.put_line('3');
goto a;
dbms_output.put_line('4');
dbms_output.put_line('5');
dbms_output.put_line('6');
dbms_output.put_line('7');
dbms_output.put_line('8');
dbms_output.put_line('9');
<<a>>
dbms_output.put_line('10');
end;
嘗試將goto跳轉的位置, 挪動到end前一行
set serveroutput on;
declare
begin
dbms_output.put_line('1');
dbms_output.put_line('2');
dbms_output.put_line('3');
goto a;
dbms_output.put_line('4');
dbms_output.put_line('5');
dbms_output.put_line('6');
dbms_output.put_line('7');
dbms_output.put_line('8');
dbms_output.put_line('9');
dbms_output.put_line('10');
<<a>>
end;
上述的程式碼 出錯了. 我們不可以通過goto語句 直接跳轉到一個程式的末尾 !
這是格式上的限制 , 我們可以通過在程式末尾新增空行, 來實現這個操作!
set serveroutput on;
declare
begin
dbms_output.put_line('1');
dbms_output.put_line('2');
dbms_output.put_line('3');
goto a;
dbms_output.put_line('4');
dbms_output.put_line('5');
dbms_output.put_line('6');
dbms_output.put_line('7');
dbms_output.put_line('8');
dbms_output.put_line('9');
dbms_output.put_line('10');
<<a>>
NULL;
end;
使用goto模擬迴圈
通過goto模擬迴圈 輸出1-10的數字
set serveroutput on;
declare
i number :=0;
begin
<<a>>
i := i+1;
dbms_output.put_line(i);
if i<10 then
goto a;
end if;
end;