最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Oracle PL/SQL 從入門(mén)到精通

 更新時(shí)間:2026年04月20日 09:36:58   作者:Chenxi Hu  
文章介紹了PL/SQL語(yǔ)言的基本概念、特點(diǎn)、與SQL的區(qū)別、應(yīng)用場(chǎng)景和語(yǔ)法結(jié)構(gòu),PL/SQL是Oracle數(shù)據(jù)庫(kù)中用于編寫(xiě)復(fù)雜業(yè)務(wù)邏輯的程序化擴(kuò)展語(yǔ)言,而Oracle APEX則是一個(gè)基于PL/SQL的低代碼Web應(yīng)用開(kāi)發(fā)平臺(tái)

PL/SQL 簡(jiǎn)介

什么是PL/SQL?

PL/SQL(Procedural Language/Structured Query Language)是Oracle數(shù)據(jù)庫(kù)的過(guò)程化擴(kuò)展語(yǔ)言,它將SQL的數(shù)據(jù)操作能力與過(guò)程化語(yǔ)言的流程控制能力相結(jié)合。PL/SQL允許開(kāi)發(fā)者在數(shù)據(jù)庫(kù)服務(wù)器端編寫(xiě)復(fù)雜的業(yè)務(wù)邏輯,減少網(wǎng)絡(luò)傳輸,提高應(yīng)用程序性能。

PL/SQL 的主要特點(diǎn)

塊結(jié)構(gòu)

-- PL/SQL程序由塊組成
[DECLARE]
  -- 聲明部分
BEGIN
  -- 執(zhí)行部分
[EXCEPTION]
  -- 異常處理部分
END;

過(guò)程化結(jié)構(gòu)

PL/SQL支持完整的過(guò)程化編程結(jié)構(gòu):

  • 條件判斷(IF-THEN-ELSE,CASE)
  • 循環(huán)(LOOP,WHILE,F(xiàn)OR)
  • 順序控制(GOTO,NULL)

錯(cuò)誤處理機(jī)制

EXCEPTION
  WHEN exception1 THEN
    -- 處理特定異常
  WHEN OTHERS THEN
    -- 處理其他所有異常

高性能特性

  • 減少網(wǎng)絡(luò)流量:在數(shù)據(jù)庫(kù)服務(wù)器端執(zhí)行復(fù)雜邏輯
  • 預(yù)編譯:代碼在首次執(zhí)行時(shí)編譯,后續(xù)執(zhí)行使用編譯后的版本
  • 批量處理:支持BULK COLLECT和FORALL進(jìn)行批量操作

可移植性

PL/SQL代碼可以在所有支持Oracle數(shù)據(jù)庫(kù)的平臺(tái)上運(yùn)行,無(wú)需修改。

PL/SQL與SQL的區(qū)別

特性SQLPL/SQL
語(yǔ)言類(lèi)型聲明式語(yǔ)言過(guò)程化語(yǔ)言
執(zhí)行方式單條語(yǔ)句執(zhí)行塊執(zhí)行
流程控制無(wú)完整的流程控制
錯(cuò)誤處理有限強(qiáng)大的異常處理
變量支持無(wú)支持變量和常量

PL/SQL的應(yīng)用場(chǎng)景

  • 數(shù)據(jù)庫(kù)觸發(fā)器
  • 存儲(chǔ)過(guò)程和函數(shù)
  • 包(Package)
  • 數(shù)據(jù)庫(kù)作業(yè)(DBMS_JOB)
  • 復(fù)雜的業(yè)務(wù)邏輯實(shí)現(xiàn)

Oracle APEX

Oracle APEX簡(jiǎn)介

Oracle APEX(Oracle Application Express)是Oracle推出的低代碼Web應(yīng)用開(kāi)發(fā)平臺(tái)。

核心優(yōu)勢(shì)

  • 低代碼開(kāi)發(fā):通過(guò)可視化界面(如App Builder)和SQL/PL/SQL語(yǔ)言,大幅減少代碼量,非專(zhuān)業(yè)開(kāi)發(fā)人員也能快速上手,顯著縮短應(yīng)用開(kāi)發(fā)周期。
  • 深度集成Oracle數(shù)據(jù)庫(kù):作為Oracle生態(tài)的核心組件,與Oracle數(shù)據(jù)庫(kù)(包括自治數(shù)據(jù)庫(kù))無(wú)縫集成,充分利用數(shù)據(jù)庫(kù)的性能、安全性、事務(wù)管理能力,適合構(gòu)建數(shù)據(jù)密集型應(yīng)用(如ERP、CRM、報(bào)表系統(tǒng)等)。

**核心功能模塊 **

  • App Builder:可視化拖拽式界面,支持頁(yè)面設(shè)計(jì)、表單創(chuàng)建、報(bào)表生成、流程定義等,快速構(gòu)建Web應(yīng)用的前端與業(yè)務(wù)邏輯。
  • SQL Workshop:Object Browser、SQL Commands等工具,用于數(shù)據(jù)庫(kù)對(duì)象管理、SQL/PL/SQL語(yǔ)句執(zhí)行、腳本管理等,是“數(shù)據(jù)庫(kù)到應(yīng)用”的橋梁。

Oracle APEX - SQL Workshop - SQL Commands第一個(gè)PL/SQL程序

-- 簡(jiǎn)單的PL/SQL塊
BEGIN
  DBMS_OUTPUT.PUT_LINE('Hello, PL/SQL World!');
  DBMS_OUTPUT.PUT_LINE('當(dāng)前時(shí)間: ' || TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));
END;
/
-- “/” 是 PL/SQL 塊特有的執(zhí)行指令,用來(lái)明確告訴 Oracle 執(zhí)行環(huán)境:“當(dāng)前編輯的 PL/SQL 塊已完整,請(qǐng)執(zhí)行它”。
-- 帶變量的PL/SQL塊
DECLARE
  v_message VARCHAR2(100) := '歡迎學(xué)習(xí)PL/SQL';
  v_counter NUMBER := 1;
BEGIN
  WHILE v_counter <= 5 LOOP
    DBMS_OUTPUT.PUT_LINE(v_counter || ': ' || v_message);
    v_counter := v_counter + 1;
  END LOOP;
END;
/

PL/SQL 塊結(jié)構(gòu)

PL/SQL 塊的基本組成

完整塊結(jié)構(gòu)

[DECLARE]
  -- 聲明部分:變量、常量、游標(biāo)、異常等
BEGIN
  -- 執(zhí)行部分:PL/SQL和SQL語(yǔ)句
[EXCEPTION]
  -- 異常處理部分:錯(cuò)誤處理邏輯
END;

各部分的詳細(xì)說(shuō)明

聲明部分(DECLARE)

DECLARE
  -- 變量聲明
  v_employee_id    NUMBER(6) := 100;
  v_employee_name  VARCHAR2(50);
  v_salary         NUMBER(8,2);
  v_hire_date      DATE;
  v_is_active      BOOLEAN := TRUE;
  
  -- 常量聲明
  c_company_name   CONSTANT VARCHAR2(30) := '甲骨文公司';
  c_tax_rate       CONSTANT NUMBER := 0.1;
  
  -- 異常聲明
  e_salary_too_high EXCEPTION;   -- 聲明一個(gè)自定義異常
  -- 將自定義異常與特定錯(cuò)誤編號(hào)綁定
  -- -20001是 Oracle 預(yù)留的用戶(hù)自定義錯(cuò)誤編號(hào)(范圍:-20000 到 -20999),用于區(qū)分系統(tǒng)錯(cuò)誤(如 ORA-00001 是主鍵沖突)和用戶(hù)業(yè)務(wù)錯(cuò)誤
  PRAGMA EXCEPTION_INIT(e_salary_too_high, -20001);

執(zhí)行部分(BEGIN)

BEGIN
  -- 數(shù)據(jù)查詢(xún)
  SELECT first_name || ' ' || last_name, salary, hire_date
  INTO v_employee_name, v_salary, v_hire_date
  FROM employees
  WHERE employee_id = v_employee_id;
  -- 數(shù)據(jù)處理
  IF v_salary > 10000 THEN
    RAISE e_salary_too_high;
  END IF;
  -- 數(shù)據(jù)輸出
  DBMS_OUTPUT.PUT_LINE('員工: ' || v_employee_name);
  DBMS_OUTPUT.PUT_LINE('薪資: ' || v_salary);
  DBMS_OUTPUT.PUT_LINE('入職日期: ' || TO_CHAR(v_hire_date, 'YYYY-MM-DD'));

異常處理部分(EXCEPTION)

EXCEPTION
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('錯(cuò)誤: 未找到指定的員工記錄');
  WHEN TOO_MANY_ROWS THEN
    DBMS_OUTPUT.PUT_LINE('錯(cuò)誤: 查詢(xún)返回了多條記錄');
  WHEN e_salary_too_high THEN
    DBMS_OUTPUT.PUT_LINE('錯(cuò)誤: 員工薪資超過(guò)限制');
  WHEN OTHERS THEN
    -- SQLCODE:返回當(dāng)前錯(cuò)誤的錯(cuò)誤編號(hào)(如系統(tǒng)錯(cuò)誤NO_DATA_FOUND對(duì)應(yīng)100,用戶(hù)自定義錯(cuò)誤-20001等)。
    -- SQLERRM:返回與SQLCODE對(duì)應(yīng)的錯(cuò)誤描述信息(如ORA-01403: 未找到數(shù)據(jù)、ORA-20001: 工資過(guò)高等)。
    DBMS_OUTPUT.PUT_LINE('系統(tǒng)錯(cuò)誤: ' || SQLCODE || ' - ' || SQLERRM);
    -- 事務(wù)回滾
    ROLLBACK;
END;

匿名塊詳解

匿名塊的特點(diǎn)

  • 沒(méi)有名稱(chēng),不被數(shù)據(jù)庫(kù)存儲(chǔ)
  • 每次執(zhí)行都需要重新編譯
  • 適合一次性任務(wù)和測(cè)試
  • PL/SQL 匿名塊的固定語(yǔ)法是 DECLARE...BEGIN...END;/,沒(méi)有任何 “命名定義”(如存儲(chǔ)過(guò)程的CREATE PROCEDURE 名稱(chēng)

匿名塊的使用場(chǎng)景

-- 場(chǎng)景1:數(shù)據(jù)驗(yàn)證和清理
DECLARE
  v_invalid_count NUMBER;
BEGIN
  -- 統(tǒng)計(jì)無(wú)效數(shù)據(jù)
  SELECT COUNT(*) INTO v_invalid_count
  FROM employees
  WHERE department_id NOT IN (SELECT department_id FROM departments);
  DBMS_OUTPUT.PUT_LINE('發(fā)現(xiàn) ' || v_invalid_count || ' 條無(wú)效記錄');
  -- 清理無(wú)效數(shù)據(jù)
  IF v_invalid_count > 0 THEN
    DELETE FROM employees
    WHERE department_id NOT IN (SELECT department_id FROM departments);
    DBMS_OUTPUT.PUT_LINE('已清理 ' || SQL%ROWCOUNT || ' 條記錄');
    COMMIT;
  END IF;
END;
/
-- 場(chǎng)景2:數(shù)據(jù)轉(zhuǎn)換
DECLARE
  CURSOR c_employees IS
    SELECT employee_id, salary
    FROM employees
    WHERE salary < 3000;
  v_raise_percentage NUMBER := 0.1;
BEGIN
  FOR emp_rec IN c_employees LOOP
    UPDATE employees
    SET salary = salary * (1 + v_raise_percentage)
    WHERE employee_id = emp_rec.employee_id;
    DBMS_OUTPUT.PUT_LINE('員工 ' || emp_rec.employee_id || 
                        ' 薪資從 ' || emp_rec.salary || 
                        ' 調(diào)整為 ' || emp_rec.salary * (1 + v_raise_percentage));
  END LOOP;
  COMMIT;
END;
/

命名塊詳解

命名塊的類(lèi)型

  • 存儲(chǔ)過(guò)程(Procedure):執(zhí)行特定任務(wù),不返回值
  • 函數(shù)(Function):執(zhí)行計(jì)算并返回一個(gè)值
  • 觸發(fā)器(Trigger):響應(yīng)數(shù)據(jù)庫(kù)事件自動(dòng)執(zhí)行
  • 包(Package):相關(guān)程序單元的集合

命名塊的優(yōu)勢(shì)

  1. 代碼重用:一次編寫(xiě),多次調(diào)用
  2. 模塊化:將復(fù)雜系統(tǒng)分解為小模塊
  3. 安全性:通過(guò)權(quán)限控制訪問(wèn)
  4. 性能:預(yù)編譯,執(zhí)行效率高
  5. 維護(hù)性:集中管理,易于維護(hù)

塊的嵌套和標(biāo)簽

嵌套塊

DECLARE
  v_outer_variable VARCHAR2(50) := '外部變量';
BEGIN
  DBMS_OUTPUT.PUT_LINE('外層塊: ' || v_outer_variable);
  -- 內(nèi)層塊開(kāi)始
  DECLARE
    v_inner_variable VARCHAR2(50) := '內(nèi)部變量';
  BEGIN
    DBMS_OUTPUT.PUT_LINE('內(nèi)層塊: ' || v_outer_variable); -- 可以訪問(wèn)外部變量
    DBMS_OUTPUT.PUT_LINE('內(nèi)層塊: ' || v_inner_variable);
    -- 可以重新定義外部變量(不推薦)
    v_outer_variable := '在內(nèi)層塊修改的外部變量';
  END;
  DBMS_OUTPUT.PUT_LINE('外層塊: ' || v_outer_variable); -- 顯示修改后的值
END;
/

塊標(biāo)簽

<<outer_block>>
DECLARE
  v_counter NUMBER := 1;
BEGIN
  DBMS_OUTPUT.PUT_LINE('外部塊計(jì)數(shù)器: ' || v_counter);
  <<inner_block>>
  DECLARE
    v_counter NUMBER := 100; -- 與外部塊變量同名
  BEGIN
    DBMS_OUTPUT.PUT_LINE('內(nèi)部塊計(jì)數(shù)器: ' || v_counter); -- 顯示100
    DBMS_OUTPUT.PUT_LINE('外部塊計(jì)數(shù)器: ' || outer_block.v_counter); -- 顯示1
    outer_block.v_counter := outer_block.v_counter + 1; -- 修改外部塊變量
  END inner_block;
  DBMS_OUTPUT.PUT_LINE('外部塊計(jì)數(shù)器: ' || v_counter); -- 顯示2
END outer_block;
/

變量和數(shù)據(jù)類(lèi)型

變量聲明

變量聲明語(yǔ)法

variable_name [CONSTANT] datatype [NOT NULL] [:= | DEFAULT initial_value];

變量聲明示例

DECLARE
  -- 基本變量聲明
  v_employee_id    NUMBER(6);
  v_first_name     VARCHAR2(20);
  v_last_name      VARCHAR2(25);
  v_salary         NUMBER(8,2);
  v_commission_pct NUMBER(2,2);
  v_hire_date      DATE;
  v_is_manager     BOOLEAN;
  -- 帶初始化的變量聲明
  v_department_id  NUMBER(4) := 50;
  v_job_id         VARCHAR2(10) DEFAULT 'IT_PROG';
  v_active_status  BOOLEAN := TRUE;
  -- 常量聲明
  c_company_name   CONSTANT VARCHAR2(30) := 'Oracle Corporation';
  c_max_salary     CONSTANT NUMBER := 100000;
  c_pi             CONSTANT NUMBER := 3.14159;
  -- NOT NULL約束
  v_required_field VARCHAR2(50) NOT NULL := '默認(rèn)值';
BEGIN
  -- 變量使用示例
  v_employee_id := 100;
  v_first_name := 'Steven';
  v_last_name := 'King';
  v_salary := 24000;
  v_hire_date := SYSDATE;
  v_is_manager := TRUE;
  DBMS_OUTPUT.PUT_LINE('員工: ' || v_first_name || ' ' || v_last_name);
  DBMS_OUTPUT.PUT_LINE('薪資: ' || v_salary);
  DBMS_OUTPUT.PUT_LINE('公司: ' || c_company_name);
END;
/

標(biāo)量數(shù)據(jù)類(lèi)型

數(shù)值類(lèi)型

DECLARE
  -- NUMBER類(lèi)型
  v_integer      NUMBER(5);        -- 整數(shù),最多5位
  v_decimal      NUMBER(8,2);      -- 小數(shù),總位數(shù)8,小數(shù)位2
  v_float        NUMBER;           -- 浮點(diǎn)數(shù)
  v_scientific   NUMBER;           -- 科學(xué)計(jì)數(shù)法
  -- 整數(shù)子類(lèi)型
  v_pls_integer  PLS_INTEGER;      -- PL/SQL整數(shù),性能更好
  v_binary_int   BINARY_INTEGER;   -- 二進(jìn)制整數(shù)
  v_simple_int   SIMPLE_INTEGER;   -- 簡(jiǎn)單整數(shù)(NOT NULL)
  -- 其他數(shù)值類(lèi)型
  v_double       BINARY_DOUBLE;    -- 二進(jìn)制雙精度
  v_float_num    BINARY_FLOAT;     -- 二進(jìn)制單精度
BEGIN
  v_integer := 12345;
  v_decimal := 123456.78;
  v_float := 3.1415926535;
  v_scientific := 1.23E+5;         -- 123000
  v_pls_integer := 100;
  v_binary_int := -50;
  v_simple_int := 200;
  v_double := 3.141592653589793;
  v_float_num := 2.71828;
  DBMS_OUTPUT.PUT_LINE('整數(shù): ' || v_integer);
  DBMS_OUTPUT.PUT_LINE('小數(shù): ' || v_decimal);
  DBMS_OUTPUT.PUT_LINE('科學(xué)計(jì)數(shù): ' || v_scientific);
END;
/

字符類(lèi)型

DECLARE
  -- VARCHAR2類(lèi)型
  v_varchar2      VARCHAR2(50);    -- 可變長(zhǎng)度字符串
  v_varchar2_def  VARCHAR2(100) := '默認(rèn)值';
  -- CHAR類(lèi)型
  v_char          CHAR(10);        -- 定長(zhǎng)字符串,自動(dòng)填充空格
  v_char_def      CHAR(5) := 'ABC';
  -- 長(zhǎng)文本類(lèi)型
  v_long          LONG;            -- 長(zhǎng)文本(已過(guò)時(shí))
  v_clob          CLOB;            -- 字符大對(duì)象
  -- 其他字符類(lèi)型
  v_nchar         NCHAR(10);       -- 國(guó)家字符集定長(zhǎng)
  v_nvarchar2     NVARCHAR2(50);   -- 國(guó)家字符集變長(zhǎng)
  v_raw           RAW(100);        -- 原始二進(jìn)制數(shù)據(jù)
  v_long_raw      LONG RAW;        -- 長(zhǎng)原始二進(jìn)制(已過(guò)時(shí))
  v_blob          BLOB;            -- 二進(jìn)制大對(duì)象
BEGIN
  v_varchar2 := '這是一個(gè)變長(zhǎng)字符串';
  v_char := '定長(zhǎng)';                -- 實(shí)際存儲(chǔ)為'定長(zhǎng)      '
  v_clob := '這是一個(gè)非常大的文本內(nèi)容...';
  DBMS_OUTPUT.PUT_LINE('VARCHAR2: ' || v_varchar2);
  DBMS_OUTPUT.PUT_LINE('CHAR: [' || v_char || ']'); -- 顯示填充的空格
  DBMS_OUTPUT.PUT_LINE('CLOB長(zhǎng)度: ' || DBMS_LOB.GETLENGTH(v_clob));
END;
/

日期和時(shí)間類(lèi)型

DECLARE
  -- 日期時(shí)間類(lèi)型
  v_date          DATE;                    -- 日期和時(shí)間
  v_timestamp     TIMESTAMP;               -- 時(shí)間戳
  v_timestamp_tz  TIMESTAMP WITH TIME ZONE;-- 帶時(shí)區(qū)的時(shí)間戳
  v_timestamp_ltz TIMESTAMP WITH LOCAL TIME ZONE; -- 本地時(shí)區(qū)時(shí)間戳
  -- 時(shí)間間隔類(lèi)型
  v_interval_ym   INTERVAL YEAR TO MONTH;  -- 年月間隔
  v_interval_ds   INTERVAL DAY TO SECOND;  -- 日秒間隔
BEGIN
  v_date := SYSDATE;
  v_timestamp := SYSTIMESTAMP;
  v_timestamp_tz := CURRENT_TIMESTAMP;
  v_timestamp_ltz := LOCALTIMESTAMP;
  v_interval_ym := INTERVAL '1-6' YEAR TO MONTH;  -- 1年6個(gè)月
  v_interval_ds := INTERVAL '5 12:30:15' DAY TO SECOND; -- 5天12小時(shí)30分15秒
  DBMS_OUTPUT.PUT_LINE('當(dāng)前日期: ' || TO_CHAR(v_date, 'YYYY-MM-DD HH24:MI:SS'));
  DBMS_OUTPUT.PUT_LINE('當(dāng)前時(shí)間戳: ' || v_timestamp);
  DBMS_OUTPUT.PUT_LINE('時(shí)間間隔: ' || v_interval_ym);
  DBMS_OUTPUT.PUT_LINE('日秒間隔: ' || v_interval_ds);
END;
/

布爾類(lèi)型

DECLARE
  v_flag1 BOOLEAN;
  v_flag2 BOOLEAN := TRUE;
  v_flag3 BOOLEAN := FALSE;
  v_flag4 BOOLEAN := NULL;
BEGIN
  v_flag1 := (10 > 5);  -- 賦值為T(mén)RUE
  -- 布爾值的使用
  IF v_flag1 THEN
    DBMS_OUTPUT.PUT_LINE('條件1為真');
  END IF;
  IF NOT v_flag3 THEN
    DBMS_OUTPUT.PUT_LINE('條件3為假');
  END IF;
  -- 注意:布爾值不能直接輸出
  -- DBMS_OUTPUT.PUT_LINE(v_flag1); -- 這會(huì)報(bào)錯(cuò)
  -- 可以通過(guò)條件判斷輸出
  DBMS_OUTPUT.PUT_LINE('flag1: ' || CASE WHEN v_flag1 THEN 'TRUE'
                                        WHEN NOT v_flag1 THEN 'FALSE'
                                        ELSE 'NULL' END);
END;
/

復(fù)合數(shù)據(jù)類(lèi)型

記錄類(lèi)型(RECORD)

在 Oracle 的 PL/SQL 中,RECORD(記錄)類(lèi)型是一種復(fù)合數(shù)據(jù)類(lèi)型,用于將多個(gè)相關(guān)但數(shù)據(jù)類(lèi)型可能不同的 “字段(Field)” 組合成一個(gè)整體,類(lèi)似其他編程語(yǔ)言中的 “結(jié)構(gòu)體(Struct)”。

DECLARE
  -- 定義記錄類(lèi)型
  TYPE employee_rec IS RECORD (
    employee_id    employees.employee_id%TYPE,
    first_name     employees.first_name%TYPE,
    last_name      employees.last_name%TYPE,
    salary         employees.salary%TYPE,
    hire_date      employees.hire_date%TYPE
  );
  -- 聲明記錄變量
  v_employee employee_rec;
  -- 使用%ROWTYPE定義記錄
  v_emp_row employees%ROWTYPE;
BEGIN
  -- 為記錄字段賦值
  v_employee.employee_id := 100;
  v_employee.first_name := 'Steven';
  v_employee.last_name := 'King';
  v_employee.salary := 24000;
  v_employee.hire_date := SYSDATE;
  -- 使用SELECT INTO為記錄賦值
  SELECT employee_id, first_name, last_name, salary, hire_date
  INTO v_employee
  FROM employees
  WHERE employee_id = 101;
  -- 使用%ROWTYPE
  SELECT * INTO v_emp_row
  FROM employees
  WHERE employee_id = 102;
  -- 輸出記錄內(nèi)容
  DBMS_OUTPUT.PUT_LINE('員工: ' || v_employee.first_name || ' ' || v_employee.last_name);
  DBMS_OUTPUT.PUT_LINE('薪資: ' || v_employee.salary);
  DBMS_OUTPUT.PUT_LINE('ROW員工: ' || v_emp_row.first_name || ' ' || v_emp_row.last_name);
END;
/

集合類(lèi)型

關(guān)聯(lián)數(shù)組(INDEX-BY TABLE)

? 在 Oracle 的 PL/SQL 中,關(guān)聯(lián)數(shù)組(Associative Array) 也稱(chēng)為INDEX-BY TABLE(索引表),是一種集合類(lèi)型,用于存儲(chǔ)多個(gè)同類(lèi)型元素的 “鍵值對(duì)” 集合,類(lèi)似其他編程語(yǔ)言中的 “哈希表(Hash Table)” 或 “字典(Dictionary)”。

DECLARE  -- 聲明區(qū):定義類(lèi)型、變量等(僅聲明不執(zhí)行)
  -- 定義第一個(gè)關(guān)聯(lián)數(shù)組類(lèi)型:salary_table
  -- 元素類(lèi)型為NUMBER(存儲(chǔ)薪資),索引類(lèi)型為PLS_INTEGER(整數(shù)索引)
  TYPE salary_table IS TABLE OF NUMBER
    INDEX BY PLS_INTEGER;
  -- 定義第二個(gè)關(guān)聯(lián)數(shù)組類(lèi)型:name_table
  -- 元素類(lèi)型為VARCHAR2(50)(存儲(chǔ)姓名),索引類(lèi)型為VARCHAR2(10)(字符串索引,長(zhǎng)度不超過(guò)10)
  TYPE name_table IS TABLE OF VARCHAR2(50)
    INDEX BY VARCHAR2(10);
  -- 聲明關(guān)聯(lián)數(shù)組變量:基于上面定義的類(lèi)型創(chuàng)建實(shí)例
  v_salaries salary_table;  -- 用于存儲(chǔ)“整數(shù)索引->薪資”的關(guān)聯(lián)數(shù)組
  v_names name_table;       -- 用于存儲(chǔ)“字符串索引->姓名”的關(guān)聯(lián)數(shù)組
  -- 聲明遍歷用的變量:存儲(chǔ)當(dāng)前索引/鍵
  v_index PLS_INTEGER;      -- 用于遍歷整數(shù)索引的v_salaries
  v_key VARCHAR2(10);       -- 用于遍歷字符串索引的v_names
BEGIN  -- 執(zhí)行區(qū):編寫(xiě)具體邏輯(實(shí)際執(zhí)行的代碼)
  -- 為v_salaries賦值(整數(shù)索引)
  v_salaries(1) := 5000;    -- 索引1對(duì)應(yīng)的值為5000
  v_salaries(2) := 7500;    -- 索引2對(duì)應(yīng)的值為7500
  v_salaries(5) := 10000;   -- 索引5對(duì)應(yīng)的值為10000(演示:關(guān)聯(lián)數(shù)組索引可以不連續(xù))
  -- 為v_names賦值(字符串索引)
  v_names('emp001') := '張三';   -- 索引'emp001'對(duì)應(yīng)的值為'張三'
  v_names('emp002') := '李四';   -- 索引'emp002'對(duì)應(yīng)的值為'李四'
  v_names('manager') := '王經(jīng)理';-- 索引'manager'對(duì)應(yīng)的值為'王經(jīng)理'
  -- 遍歷v_salaries(整數(shù)索引的關(guān)聯(lián)數(shù)組)
  v_index := v_salaries.FIRST;  -- 獲取v_salaries的第一個(gè)索引(此處為1)
  -- 循環(huán)條件:當(dāng)前索引不為空(即還有元素未遍歷)
  WHILE v_index IS NOT NULL LOOP
    -- 輸出當(dāng)前索引和對(duì)應(yīng)的值
    DBMS_OUTPUT.PUT_LINE('索引 ' || v_index || ': ' || v_salaries(v_index));
    v_index := v_salaries.NEXT(v_index);  -- 獲取當(dāng)前索引的下一個(gè)索引(1的下一個(gè)是2,2的下一個(gè)是5,5的下一個(gè)為空)
  END LOOP;  -- 結(jié)束循環(huán)
  -- 遍歷v_names(字符串索引的關(guān)聯(lián)數(shù)組)
  v_key := v_names.FIRST;  -- 獲取v_names的第一個(gè)鍵(字符串索引按字典序排序,此處為'emp001')
  -- 循環(huán)條件:當(dāng)前鍵不為空(即還有元素未遍歷)
  WHILE v_key IS NOT NULL LOOP
    -- 輸出當(dāng)前鍵和對(duì)應(yīng)的值
    DBMS_OUTPUT.PUT_LINE('鍵 ' || v_key || ': ' || v_names(v_key));
    v_key := v_names.NEXT(v_key);  -- 獲取當(dāng)前鍵的下一個(gè)鍵('emp001'的下一個(gè)是'emp002',再下一個(gè)是'manager',最后為空)
  END LOOP;  -- 結(jié)束循環(huán)
  -- 檢查v_salaries中是否存在索引3的元素
  IF v_salaries.EXISTS(3) THEN  -- EXISTS(索引):判斷指定索引是否存在
    DBMS_OUTPUT.PUT_LINE('索引3存在');
  ELSE
    DBMS_OUTPUT.PUT_LINE('索引3不存在');  -- 此處因未給索引3賦值,會(huì)執(zhí)行該分支
  END IF;
  -- 獲取并輸出關(guān)聯(lián)數(shù)組的元素?cái)?shù)量(COUNT方法)
  DBMS_OUTPUT.PUT_LINE('v_salaries元素?cái)?shù)量: ' || v_salaries.COUNT);  -- 共3個(gè)元素(索引1、2、5)
  DBMS_OUTPUT.PUT_LINE('v_names元素?cái)?shù)量: ' || v_names.COUNT);        -- 共3個(gè)元素(鍵'emp001'、'emp002'、'manager')
END;  -- 結(jié)束PL/SQL塊
/  -- 執(zhí)行該P(yáng)L/SQL塊

嵌套表(NESTED TABLE)

? 在Oracle數(shù)據(jù)庫(kù)中,嵌套表(Nested Table) 是一種用戶(hù)定義的集合數(shù)據(jù)類(lèi)型,它允許將整個(gè)表作為另一張表的列進(jìn)行存儲(chǔ)。

嵌套表是一種:

  • 無(wú)序的數(shù)據(jù)集合(元素沒(méi)有固定順序)
  • 可以動(dòng)態(tài)擴(kuò)展(元素?cái)?shù)量不固定)
  • 存儲(chǔ)在數(shù)據(jù)庫(kù)表中的特殊列類(lèi)型
  • 實(shí)際數(shù)據(jù)存儲(chǔ)在單獨(dú)的存儲(chǔ)表中
DECLARE  -- 聲明區(qū):定義類(lèi)型、變量(僅聲明不執(zhí)行)
  -- 定義第一個(gè)嵌套表類(lèi)型:number_table,元素類(lèi)型為NUMBER(存儲(chǔ)數(shù)字)
  TYPE number_table IS TABLE OF NUMBER;
  -- 定義第二個(gè)嵌套表類(lèi)型:string_table,元素類(lèi)型為VARCHAR2(50)(存儲(chǔ)字符串,長(zhǎng)度不超過(guò)50)
  TYPE string_table IS TABLE OF VARCHAR2(50);
  -- 聲明嵌套表變量(基于上面定義的類(lèi)型)
  -- v_numbers:number_table類(lèi)型的變量,通過(guò)構(gòu)造函數(shù)number_table()初始化(創(chuàng)建空嵌套表,非NULL)
  v_numbers number_table := number_table(); -- 嵌套表必須初始化,否則操作會(huì)報(bào)錯(cuò)
  -- v_names:string_table類(lèi)型的變量,聲明時(shí)直接通過(guò)構(gòu)造函數(shù)賦值(初始包含3個(gè)元素:'張三'、'李四'、'王五')
  v_names string_table := string_table('張三', '李四', '王五');
  -- 聲明遍歷用的變量:存儲(chǔ)嵌套表的索引(整數(shù)類(lèi)型)
  v_index NUMBER;
BEGIN  -- 執(zhí)行區(qū):編寫(xiě)具體邏輯(實(shí)際執(zhí)行的代碼)
  -- 為v_numbers添加元素(第一種方式:先擴(kuò)展容量再賦值)
  v_numbers.EXTEND(3); -- 擴(kuò)展3個(gè)空元素(此時(shí)v_numbers有3個(gè)可用索引:1、2、3)
  v_numbers(1) := 100; -- 給索引1的元素賦值100
  v_numbers(2) := 200; -- 給索引2的元素賦值200
  v_numbers(3) := 300; -- 給索引3的元素賦值300
  -- 為v_numbers重新賦值(第二種方式:直接通過(guò)構(gòu)造函數(shù)覆蓋原有值)
  -- 此時(shí)v_numbers的元素變?yōu)?0、20、30、40、50(索引1-5,覆蓋了之前的100、200、300)
  v_numbers := number_table(10, 20, 30, 40, 50);
  -- 遍歷v_numbers(使用FOR循環(huán),基于元素?cái)?shù)量COUNT)
  -- 循環(huán)范圍:從1到v_numbers的元素總數(shù)(COUNT=5,即i=1→2→3→4→5)
  FOR i IN 1..v_numbers.COUNT LOOP
    -- 輸出當(dāng)前索引i和對(duì)應(yīng)的值
    DBMS_OUTPUT.PUT_LINE('數(shù)字[' || i || ']: ' || v_numbers(i));
  END LOOP;  -- 結(jié)束循環(huán)
  -- 遍歷v_names(使用WHILE循環(huán),基于FIRST和NEXT方法)
  v_index := v_names.FIRST; -- 獲取v_names的第一個(gè)索引(初始為1,因初始元素是按順序添加的)
  -- 循環(huán)條件:當(dāng)前索引不為空(即還有元素未遍歷)
  WHILE v_index IS NOT NULL LOOP
    -- 輸出當(dāng)前索引v_index和對(duì)應(yīng)的值
    DBMS_OUTPUT.PUT_LINE('姓名[' || v_index || ']: ' || v_names(v_index));
    v_index := v_names.NEXT(v_index); -- 獲取當(dāng)前索引的下一個(gè)索引(1→2→3→NULL)
  END LOOP;  -- 結(jié)束循環(huán)
  -- 刪除v_names中的元素(刪除索引為2的元素,即'李四')
  v_names.DELETE(2); 
  -- 輸出刪除后v_names的元素?cái)?shù)量(原3個(gè),刪除1個(gè),剩余2個(gè))
  DBMS_OUTPUT.PUT_LINE('刪除后元素?cái)?shù)量: ' || v_names.COUNT);
END;  -- 結(jié)束PL/SQL塊
/  -- 執(zhí)行該P(yáng)L/SQL塊

變長(zhǎng)數(shù)組(VARRAY)

DECLARE  -- 聲明區(qū):定義類(lèi)型、變量(僅聲明不執(zhí)行)
  -- 定義第一個(gè)VARRAY類(lèi)型:number_varray
  -- VARRAY(5)表示這是一個(gè)可變數(shù)組,最大容量為5個(gè)元素;OF NUMBER表示元素類(lèi)型為數(shù)字
  TYPE number_varray IS VARRAY(5) OF NUMBER; -- 最大可存儲(chǔ)5個(gè)元素
  -- 定義第二個(gè)VARRAY類(lèi)型:name_varray
  -- VARRAY(10)表示最大容量為10個(gè)元素;OF VARCHAR2(50)表示元素為字符串(最大長(zhǎng)度50)
  TYPE name_varray IS VARRAY(10) OF VARCHAR2(50);
  -- 聲明VARRAY變量(基于上面定義的類(lèi)型)
  -- v_numbers:number_varray類(lèi)型的變量,通過(guò)構(gòu)造函數(shù)number_varray()初始化(創(chuàng)建空數(shù)組,非NULL)
  -- VARRAY必須初始化,否則操作會(huì)報(bào)錯(cuò)
  v_numbers number_varray := number_varray(); 
  -- v_names:name_varray類(lèi)型的變量,聲明時(shí)通過(guò)構(gòu)造函數(shù)直接賦值(初始包含2個(gè)元素:'張三'、'李四')
  v_names name_varray := name_varray('張三', '李四');
  -- 聲明遍歷用的變量:存儲(chǔ)VARRAY的索引(整數(shù)類(lèi)型)
  v_index NUMBER;
BEGIN  -- 執(zhí)行區(qū):編寫(xiě)具體邏輯(實(shí)際執(zhí)行的代碼)
  -- 為v_numbers添加元素(先擴(kuò)展容量,再賦值)
  v_numbers.EXTEND(3); -- 擴(kuò)展3個(gè)空元素(此時(shí)v_numbers的容量變?yōu)?,未超過(guò)最大限制5)
  v_numbers(1) := 100; -- 給第1個(gè)元素賦值100(VARRAY索引從1開(kāi)始)
  v_numbers(2) := 200; -- 給第2個(gè)元素賦值200
  v_numbers(3) := 300; -- 給第3個(gè)元素賦值300
  -- 遍歷v_numbers(使用FOR循環(huán),范圍從1到當(dāng)前元素總數(shù)COUNT)
  -- 此時(shí)v_numbers.COUNT=3,即i=1→2→3
  FOR i IN 1..v_numbers.COUNT LOOP
    -- 輸出當(dāng)前索引i和對(duì)應(yīng)的值
    DBMS_OUTPUT.PUT_LINE('數(shù)字[' || i || ']: ' || v_numbers(i));
  END LOOP;  -- 結(jié)束循環(huán)
  -- 獲取并輸出v_numbers的最大容量(LIMIT是VARRAY特有的方法,返回定義時(shí)指定的最大元素?cái)?shù))
  DBMS_OUTPUT.PUT_LINE('v_numbers最大容量: ' || v_numbers.LIMIT); -- 輸出5(定義時(shí)VARRAY(5))
  -- 輸出v_numbers當(dāng)前的元素?cái)?shù)量(COUNT返回實(shí)際存儲(chǔ)的元素?cái)?shù))
  DBMS_OUTPUT.PUT_LINE('v_numbers當(dāng)前大小: ' || v_numbers.COUNT); -- 輸出3(已添加3個(gè)元素)
  -- 操作v_names數(shù)組
  v_names.EXTEND; -- 擴(kuò)展1個(gè)空元素(不指定參數(shù)時(shí)默認(rèn)擴(kuò)展1個(gè),此時(shí)v_names容量從2變?yōu)?,未超過(guò)最大限制10)
  v_names(3) := '王五'; -- 給第3個(gè)元素賦值'王五'
  -- 輸出v_names當(dāng)前的元素?cái)?shù)量(擴(kuò)展并賦值后,COUNT=3)
  DBMS_OUTPUT.PUT_LINE('v_names當(dāng)前大小: ' || v_names.COUNT);
END;  -- 結(jié)束PL/SQL塊
/  -- 執(zhí)行該P(yáng)L/SQL塊

三種集合類(lèi)型對(duì)比

特性嵌套表(Nested Table)變長(zhǎng)數(shù)組(VARRAY)關(guān)聯(lián)數(shù)組(Index-by Table)
定義用戶(hù)定義的無(wú)序集合用戶(hù)定義的有序集合PL/SQL中的鍵值對(duì)集合
存儲(chǔ)位置數(shù)據(jù)庫(kù)表中數(shù)據(jù)庫(kù)表中僅內(nèi)存中
大小動(dòng)態(tài),無(wú)限制固定上限動(dòng)態(tài),無(wú)限制

選擇建議

  • 需要持久化存儲(chǔ)且數(shù)據(jù)量變化大 → 嵌套表
  • 數(shù)據(jù)量固定且需要保持順序 → 變長(zhǎng)數(shù)組
  • 臨時(shí)數(shù)據(jù)處理和快速查找 → 關(guān)聯(lián)數(shù)組
  • 需要在SQL中查詢(xún)集合內(nèi)容 → 嵌套表或變長(zhǎng)數(shù)組
  • 僅PL/SQL內(nèi)部使用 → 關(guān)聯(lián)數(shù)組

數(shù)據(jù)類(lèi)型屬性

%TYPE屬性

DECLARE
  -- 使用%TYPE引用表列的類(lèi)型
  v_employee_id   employees.employee_id%TYPE;
  v_first_name    employees.first_name%TYPE;
  v_salary        employees.salary%TYPE;
  v_hire_date     employees.hire_date%TYPE;
  -- 引用其他變量的類(lèi)型
  v_bonus v_salary%TYPE;
BEGIN
  v_employee_id := 100;
  v_first_name := 'Steven';
  v_salary := 24000;
  v_hire_date := SYSDATE;
  v_bonus := v_salary * 0.1;
  DBMS_OUTPUT.PUT_LINE('員工ID: ' || v_employee_id);
  DBMS_OUTPUT.PUT_LINE('姓名: ' || v_first_name);
  DBMS_OUTPUT.PUT_LINE('薪資: ' || v_salary);
  DBMS_OUTPUT.PUT_LINE('獎(jiǎng)金: ' || v_bonus);
END;
/

%ROWTYPE屬性

DECLARE
  -- 使用%ROWTYPE引用整行類(lèi)型
  v_employee employees%ROWTYPE;
  v_department departments%ROWTYPE;
BEGIN
  -- 為記錄賦值
  SELECT * INTO v_employee
  FROM employees
  WHERE employee_id = 100;
  SELECT * INTO v_department
  FROM departments
  WHERE department_id = v_employee.department_id;
  -- 訪問(wèn)記錄字段
  DBMS_OUTPUT.PUT_LINE('員工: ' || v_employee.first_name || ' ' || v_employee.last_name);
  DBMS_OUTPUT.PUT_LINE('部門(mén): ' || v_department.department_name);
  DBMS_OUTPUT.PUT_LINE('薪資: ' || v_employee.salary);
  DBMS_OUTPUT.PUT_LINE('入職日期: ' || TO_CHAR(v_employee.hire_date, 'YYYY-MM-DD'));
END;
/

數(shù)據(jù)類(lèi)型轉(zhuǎn)換

隱式轉(zhuǎn)換

DECLARE
  v_number NUMBER;
  v_varchar VARCHAR2(50);
  v_date DATE;
BEGIN
  -- 數(shù)字到字符串的隱式轉(zhuǎn)換
  v_varchar := 123.45;
  DBMS_OUTPUT.PUT_LINE('數(shù)字轉(zhuǎn)字符串: ' || v_varchar);
  -- 字符串到數(shù)字的隱式轉(zhuǎn)換
  v_number := '456.78';
  DBMS_OUTPUT.PUT_LINE('字符串轉(zhuǎn)數(shù)字: ' || v_number);
  -- 日期到字符串的隱式轉(zhuǎn)換
  v_varchar := SYSDATE;
  DBMS_OUTPUT.PUT_LINE('日期轉(zhuǎn)字符串: ' || v_varchar);
END;
/

顯式轉(zhuǎn)換

DECLARE
  v_number NUMBER := 123.456;
  v_varchar VARCHAR2(50);
  v_date DATE;
  v_timestamp TIMESTAMP;
BEGIN
  -- 使用TO_CHAR轉(zhuǎn)換數(shù)字和日期
  v_varchar := TO_CHAR(v_number, '999,999.99');
  DBMS_OUTPUT.PUT_LINE('格式化數(shù)字: ' || v_varchar);
  v_varchar := TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS');
  DBMS_OUTPUT.PUT_LINE('格式化日期: ' || v_varchar);
  -- 使用TO_NUMBER轉(zhuǎn)換字符串為數(shù)字
  v_number := TO_NUMBER('$1,234.56', '$9,999.99');
  DBMS_OUTPUT.PUT_LINE('字符串轉(zhuǎn)數(shù)字: ' || v_number);
  -- 使用TO_DATE轉(zhuǎn)換字符串為日期
  v_date := TO_DATE('2023-12-25 14:30:00', 'YYYY-MM-DD HH24:MI:SS');
  DBMS_OUTPUT.PUT_LINE('字符串轉(zhuǎn)日期: ' || TO_CHAR(v_date, 'YYYY-MM-DD'));
  -- 使用CAST進(jìn)行類(lèi)型轉(zhuǎn)換
  v_timestamp := CAST(SYSDATE AS TIMESTAMP);
  DBMS_OUTPUT.PUT_LINE('CAST轉(zhuǎn)換: ' || v_timestamp);
END;
/

到此這篇關(guān)于Oracle PL/SQL 從入門(mén)到精通的文章就介紹到這了,更多相關(guān)Oracle PL/SQL全解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

清远市| 太仆寺旗| 威信县| 韶关市| 马公市| 宁南县| 西城区| 双峰县| 龙岩市| 新乐市| 楚雄市| 财经| 休宁县| 咸丰县| 庆城县| 宝清县| 天镇县| 东台市| 孝义市| 安龙县| 永泰县| 青浦区| 土默特左旗| 蒲江县| 二连浩特市| 连南| 河津市| 南江县| 珲春市| 云阳县| 孟州市| 长春市| 祁东县| 德惠市| 东源县| 宁德市| 新郑市| 保德县| 阜阳市| 喀喇| 浏阳市|