1. 程式人生 > >Oracle (06)常見的連線資料庫技術.迴圈

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;
  1. 申明區: 用來定義變數和型別, 如果沒有申明的元素, 可以不寫declare

  2. 執行區: 用來執行PL/SQL語句 和 SQL語句

  3. 異常處理區: 用來處理執行區發生的異常, 就像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集合, 是一個鍵值對的容器, 儲存的是雙值

語法:

  1. 定義一個型別
    type 型別名稱 is table of 值型別 index by 鍵型別;

  2. 根據型別定義變數
    變數名 型別名稱;

  3. 向容器中設定值, 取值:

    • 設定
      變數名(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;