PLSQL（Procedural LanguageSQL）是甲骨文公司專有的 SQL 擴充套件語言，應用在甲骨文公司的 Oracle 資料庫系統。一些的 SQL 資料庫管理系統也提供了類似的擴充套件 SQL 語言。PLSQL 的語法非常類似於 Ada，而且像 1980 年代的 Ada 編譯器一樣，PLSQL 的運作系統使用 Diana 作為中介語言。 重要的是 PLSQL 緊密的結合在 Oracle 資料庫裡面。 PLSQL 是 Oracle 資料庫使用的三種語言的其中之一，另外兩個是 SQL 和 Java。 歷史 特性 SQL 連線操作 Oracle 連線操作 left join right joinfull join 的語法確與 SQL 標準完全不同，沒有左連線與右連線的概念，也不支援全外連線。Oracle 語法如下所示： select from t1t2 where t1idt2id 採用 來表示外連線，在 Oracle 中它相當於左連線。Oracle9i 中增加了標準外連線的語法支援，但使用不廣。 物化檢視 物化檢視（materialized view）或譯為實體化檢視。與普通檢視關係不同，物化檢視更像是一個表，儲存了實實在在的資料，並且可以與表一樣定義儲存引數，可以與表一樣使用 selectinsertupdatedelete。在其它資料庫中也有和物化檢視相似的解決方案，DB2 叫物化查詢表 materialized query table，sqlserver 有索引檢視，但是索引檢視僅是起最佳化作用，與 oracle 的物化檢視還不太一樣。 資料型別 數值型別 採用本地的 number 型別做指數或對數運算，與標準的浮點數效能可能會相差 50 倍。好在 Oracle10g 中增加了高效的浮點型別 binary_floatbinary_double，從而彌補了浮點數效能的問題。 variable_name number P S 0 NUMBER 可選指定 precision P 與 scale S。精度表示十進位制有效數字的個數，最多不能超過 38 個有效數字（實際支援 3940 位十進位制數字）。Scale 的範圍為 84，127。Scale 為正數時，表示從小數點到最不重要的十進位制有效數字的個數；為負數時，其絕對值表示從最不重要的十進位制有效數字到小數點的位數。如果沒有指定精度，precision 與 scale 預設為最大的取值區間。如果指定了精度，沒有指定 scale，scale 預設為 0。內部儲存格式是變長阿拉伯數字的位元組陣列 首位元組為長度值，最大 22；如果為 NULL，則該位元組值為 255 0xFF 第二位元組是符號和指數字節 sign bitexponent，其最高位元為符號位，1 表示正數，0 表示負數；其餘 7 位元構成基為 100 的指數值，取值範圍 65，62，NUMBER 資料型別的取值範圍為 1013010126； 第二位元組值大於 128，則：指數值 位元組值 128 64 位元組值 192，即去除符號位元後偏移了 64。位元組值最大為 254 第二位元組值等於 128，則 NUMBER 資料型別表示值 0 第二位元組值小於 128，則：指數值 255 位元組值1286463ZV，即取反後去除符號位元再偏移 64 其餘位元組儲存了基數為 100 的數值 0099 對於正數：實際值＝儲存值－1 對於負數：實際值＝儲存值 101；位元組值 102 0x66 標誌位元組陣列的結束。 兩個位元組 255 與 101 表示正無窮 單位元組 0 表示負無窮 INTEGER 是 NUMBER 的子型別，它等同於 NUMBER（380），用來儲存整數。若插入、更新的數值有小數，則會被四捨五入。 FLOAT 型別也是 NUMBER 的子型別。Float n 數 n 指示位的精度，可以儲存的值的數目。n 值的範圍可以從 1 到 126。若要從二進位制轉換為十進位制的精度，請將 n 乘以 030103。要從十進位制轉換為二進位制的精度，請用 332193 乘小數精度。126 位二進位制精度的最大值是大約相當於 38 位小數精度。 BINARY_FLOAT 是 32 位、 單精度浮點數字資料型別。可以支援至少 6 位精度，每個 BINARY_FLOAT 的值需要 5 個位元組，包括長度位元組。 BINARY_DOUBLE 是為 64 位，雙精度浮點數字資料型別。每個 BINARY_DOUBLE 的值需要 9 個位元組，包括長度位元組。 其它數值型別： dec decimal double precision int numeric real smallint binary_integer 字元型別 字串資料型別依據儲存空間分為兩種： 固定長度型別：CHARNCHAR，自動補足空格，最多可以儲存 2000 位元組 可變長度型別：VARCHAR2NVARCHAR2，最大位元組數都是 4000，自動刪除首尾的空格 串的開頭儲存了串的長度。如果串的長度小於或等於 250（0x010xFA）， Oracle 會使用 1 個位元組來表示長度。對於所有長度超過 250 的串，都會在一個標誌位元組 0xFE 後跟有兩個位元組來表示長度。 chr 0 表示的不可見字元，即我們通常所說的 0 CHAR 型別： CHAR size BYTE CHAR 固定長度字串； NCHAR 型別： 根據字元集而定的 UNICODE 格式固定長度字串 最大長度 2000 bytes。 VARCHAR 型別：不建議使用。雖然 VARCHAR 資料型別目前是 VARCHAR2 的同義詞，VARCHAR 資料型別將被重新定義為一個單獨的資料型別用於可變長度的字串相比，與 VARCHAR2 具有不同的比較語義 varchar2 型別：變長字串 nvarchar2 型別：包含 UNICODE 格式資料的變長字串 欄位 translated_name 是 NCHAR 型別，則需要如下書寫： SELECT translated_description FROM product_descriptions WHERE translated_name NLCD Monitor 11PM variable_name varchar2 20 Text eg address varchar2 20 lake view road 日期型別 variable_name date to_date 01012005 142023 DDMMYYYY hh24miss Date 型別可以表示日期與時間。精度到秒。日期範圍可以是公元前 4712 年 1 月 1 日至公元 9999 年 12 月 31 日。佔用 7 個位元組的儲存空間。第 1 位元組：世紀 100；第 2 位元組：年； 第 3 位元組：月； 第 4 位元組：天； 第 5 位元組：小時 1； 第 6 位元組：分 1；第 7 位元組：秒 1。其中時間可以忽略。但無法只表示時間而忽略日期。Oracle Datatypes TIMESTAMP 型別：7 位元組或 11 位元組的定寬日期 時間資料型別。可以包含小數秒，小數位數可以指定為 09，預設為 6 位，所以最高精度可以到 ns 納秒 如果精度為 0，則用 7 位元組儲存，與 date 型別功能相同，如果精度大於 0 則用 11 位元組儲存。 TIMESTAMP WITH TIME ZONE 型別：TIMESTAMP 型別的變種，它包含了時區偏移量的值 TIMESTAMP WITH LOCAL TIME ZONE 型別： INTERVAL YEAR TO MOTH： INTERVAL DAY TO SECOND： 函式 TO_DATE 把字串轉換為日期值。 to_date 31122004 ddmmyyyy to_date 31Dec2004 ddmonyyyy NLS_DATE_LANGUAGE American 函式 TO_CHAR date_string format_string 把日期值轉換為字串。 PLSQL 支援使用 ANSI 日期與時間間隔值 The following clause gives an 18month range 示例： WHERE dateField BETWEEN DATE 20041230 INTERVAL 16 YEAR TO MONTH AND DATE 20041230 create table T C1 DATE C2 TIMESTAMP 9 insert into t c1c2 values date2010212timestamp2010212 132452234123211 insert into t c1c2 values to_date 2010212 102030YYYYMMDD HH24MISS to_timestamp 2010212 132452123456YYYYMMDD HH24MISSFF6 SQL select c1dump c1 c1_dc2dump c2 c2_d from t sysdate 返回當前系統日期和時間，精確到秒 systimestamp 返回當前系統日期和時間，精確到毫秒 日期型資料可以與數值加減得到新的日期，加減數值單位為天 sysdate1 取明天的當前時間 sysdate124 取當前時間的前一個小時 LOB 型別 內建的 LOB 資料型別包括 BLOB、CLOB、NCLOB、BFILE（外部儲存）的大型化和非結構化資料，如文字、影像、視屏、空間資料儲存。 BLOB 資料型別：儲存非結構化的二進位制資料大物件，它可以被認為是沒有字元集語義的位元流，一般是影像、聲音、影片等檔案。BLOB 物件最多儲存 4 gigabytes1 database block size 的二進位制資料。 CLOB 資料型別：儲存單位元組和多位元組字元資料。支援固定寬度和可變寬度的字元集。CLOB 物件可以儲存最多 4 gigabytes1 database block size 大小的字元 NCLOB 資料型別：儲存 UNICODE 型別的字元資料，支援固定寬度和可變寬度的字元集，NCLOB 物件可以儲存最多 4 gigabytes1 database block size 大小的文字資料。 BFILE 資料型別：儲存在資料庫外的二進位制檔案，只讀，最大長度 4G LONG 型別，RAW 型別，LONG RAW 型別 均為較老的資料型別，Oracle 不建議使用。 LONG 型別儲存變長字串，最多達 2G 的位元組資料。儲存在 LONG 型別中的文字要進行字元集轉換。支援 LONG 列只是為了保證向後相容性。LONG 型別的限制如下： 一個表中只有一列可以為 LONG 型。 LONG 列不能定義為主鍵或唯一約束 不能建立索引 LONG 資料不能指定正則表示式。 函式或儲存過程不能接受 LONG 資料型別的引數。 LONG 列不能出現在 WHERE 子句或完整性約束（除了可能會出現 NULL 和 NOT NULL 約束） LONG RAW 型別，能儲存 2GB 的原始二進位制資料（不用進行字元集轉換的資料） RAW 型別用於儲存二進位制或字元型別資料，變長二進位制資料型別，這說明採用這種資料型別儲存的資料不會發生字元集轉換。這種型別最多可以儲存 2000 位元組的資訊 ROWID UROWID 型別 在資料庫中的每一行都有一個地址。然而，一些錶行的地址不是物理或永久的，或者不是 ORACLE 資料庫生成的。例如，索引組織錶行地址儲存在索引的葉子，可以移動。例如，外部表的 ROWID（如透過閘道器訪問 DB2 表）不是標準的 ORACLE 的 rowid。 ORACLE 使用通用的 ROWID（UROWIDs）的儲存地址的索引組織表和外表。10 個位元組，格式為： ， 為 0 或 1。NROWID 型別為二進位制資料表中記錄的唯一行號，最大長度 4000 位元組 索引組織表有邏輯 urowids 的，和外表的外 urowids。UROWID 這兩種型別的儲存在 ROWID（堆組織的表的物理行 id）。 建立基於邏輯的 rowid 在表中的主鍵。邏輯的 rowid 不會改變，只要主鍵不改變。索引組織表的 ROWID 偽 UROWID 資料型別。你可以訪問這個偽列，你會堆組織表的 ROWID 偽（即使用一個 SELECT ROWID 語句）。如果你想儲存的 rowid 索引組織表，那麼你就可以定義一列的表型 UROWID 到列檢索值的 ROWID 偽。 指定列的資料型別 定義一個變數，其型別是指定表的指定列的資料型別： Variable_name Table_nameColumn_name type 自定義型別 程式設計師自定義型別： type data_type is record field_1 type_1 xyz field_2 type_2 xyz field_n type_n xyz 例如： declare type t_address is record name addressname type street addressstreet type street_number addressstreet_number type postcode addresspostcode type v_address t_address begin select name street street_number postcode into v_address from address where rownum 1 end 可以使用點表示（dotnotation）獲取結構中的域： v_addressstreet High Street 自增長資料型別 Oracle 的資料型別裡沒有自增長（autoincremental）欄位型別，Oracle 的官方解決方案是採用 sequence 實現。insert 的時候需要用 sequencenextval。需要增加一張專用表來儲存自增長欄位的表和欄位名，每次新增記錄時都把這個記錄值加 1 再取出使用。 基本程式 條件語句 以下的程式碼展示了 IFTHENELSIF 結構。ELSIF 和 ELSE 部分是可選的，從而可以建立更簡單的 IFTHEN 或者 IFTHENELSE 結構。 IF x 1 THEN sequence_of_statements_1 ELSIF x 2 THEN sequence_of_statements_2 ELSIF x 3 THEN sequence_of_statements_3 ELSIF x 4 THEN sequence_of_statements_4 ELSIF x 5 THEN sequence_of_statements_5 ELSE sequence_of_statements_N END IF CASE 語句簡化了一些大的 IFTHENELSE 結構。 CASE WHEN x 1 THEN sequence_of_statements_1 WHEN x 2 THEN sequence_of_statements_2 WHEN x 3 THEN sequence_of_statements_3 WHEN x 4 THEN sequence_of_statements_4 WHEN x 5 THEN sequence_of_statements_5 ELSE sequence_of_statements_N END CASE CASE 語句可以使用預定義的選擇符： CASE x WHEN 1 THEN sequence_of_statements_1 WHEN 2 THEN sequence_of_statements_2 WHEN 3 THEN sequence_of_statements_3 WHEN 4 THEN sequence_of_statements_4 WHEN 5 THEN sequence_of_statements_5 ELSE sequence_of_statements_N END CASE 陣列 PLSQL 將陣列稱為 集合（collection）。 該語言提供三種類型的集合： 關聯陣列（索引表） 巢狀表 Varray（可變大小陣列） 程式設計師必須為變數指定上限，但不需要為索引表或巢狀表指定上限。 該語言包含多種用於操作集合元素的集合方法：例如 FIRST、LAST、NEXT、PRIOR、EXTEND、TRIM、DELETE 等。索引表可用於模擬關聯陣列。 關聯陣列（索引表） 對於索引表，可以透過數字或字串對陣列進行索引。 它與 Java 對映類似，由鍵值對組成。 只有一維且無界。 巢狀表 對於，程式設計師需要了解巢狀的內容。 在這裡，建立了一個可能由多個元件組成的新型別。 然後可以使用該型別在表中建立一列，並在該列中巢狀這些元件。 With nested tables the programmer needs to understand what is nested Here a new type is created that may be composed of a number of components That type can then be used to make a column in a table and nested within that column are those components Varray（可變大小陣列） 對於 Varray，需要了解 可變大小陣列 短語中的 變數 一詞並不像想象的那樣適用於陣列的大小。 宣告陣列的大小實際上是固定的。 陣列中元素的數量是可變的，最多可達宣告的大小。 可以說，可變大小的陣列的大小並不是那麼可變。 迴圈 從過程語言的，PLSQL 提供了多種迭代結構，包括基本的 LOOP 語句、WHILE 迴圈、FOR 迴圈和 Cursor FOR 迴圈。 從 Oracle 73 開始，引入了 REF CURSOR 型別，以允許從儲存過程和函式返回記錄集。 Oracle 9i 引入了預定義的 SYS_REFCURSOR 型別，這意味著我們不再需要定義自己的 REF CURSOR 型別。 如果退出迴圈，則必須使用 exit 語句終止迴圈。exit 語句分兩種格式： exit：該格式的語句用於無條件強迫終止迴圈。 exitwhen：該格式用於有條件終止迴圈，首先檢測 when 的條件是否滿足。 例 1： loop ifthen exit； end if； end loop； 例 2： loop exit when； end loop； LOOP 語句 parent_loop LOOP statements child_loop loop statements exit parent_loop when condition Terminates both loops exit when condition Returns control to parent_loop end loop child_loop if condition then continue continue to next iteration end if exit when condition END LOOP parent_loop Loop 可用 EXIT 關鍵字或丟擲異常來終止。 FOR 迴圈 DECLARE var NUMBER BEGIN NB for loop variables in PLSQL are new declarations with scope only inside the loop FOR var IN 0 10 LOOP DBMS_OUTPUTPUT_LINE var END LOOP IF var IS NULL THEN DBMS_OUTPUTPUT_LINE var is null ELSE DBMS_OUTPUTPUT_LINE var is not null END IF END 輸出 0 1 2 3 4 5 6 7 8 9 10 var is null forloop 迴圈可以限定迴圈的次數例如： declare div_name varchar2 20 div_num integer1 begin for div_num in 19 loop select name into div_name from div_tab where div_authorA000to_char div_num end loop end 例如： declare div_name varchar2 20 div_num integer1 begin for div_num in 19 loop EXIT WHEN div_num 7 DBMS_OUTPUTput_line div_num end loop end Cursor FOR 迴圈 FOR RecordIndex IN SELECT person_code FROM people_table LOOP DBMS_OUTPUTPUT_LINE RecordIndexperson_code END LOOP Cursorfor 迴圈自動開啟一個 cursor，讀入其資料並再次關閉遊標。 作為替代方案，PLSQL 程式設計師可以提前預定義遊標的 SELECT 語句，以（例如）允許重用或使程式碼更易於理解（在長查詢或複雜查詢的情況下特別有用）。 DECLARE CURSOR cursor_person IS SELECT person_code FROM people_table BEGIN FOR RecordIndex IN cursor_person LOOP DBMS_OUTPUTPUT_LINE recordIndexperson_code END LOOP END FOR 迴圈中 person_code 的概念用點符號表示 RecordIndexperson_code while 迴圈 whileloop whileloop 迴圈在執行語句時，首先檢測條件的值。例如： declare div_name varchar2 20 div_num integer1 begin while div_num10 loop select name into div_name from div_tab where div_author A000to_char div_num div_numdiv_num1 end loop end 遊標 遊標是指向私有 SQL 區域的指標，該區域儲存來自 SELECT 或資料操作語言 DML 語句（INSERT、UPDATE、DELETE 或 MERGE）的資訊。遊標儲存 SQL 語句返回的行（一行或多行）。遊標所儲存的行集稱為活動集（active set）。 遊標可以是顯式的或隱式的。在 FOR 迴圈中，如果要重用查詢，則應使用顯式遊標，否則首選隱式遊標。如果在迴圈內使用遊標，則在需要批次收集或需要動態 SQL 時，建議使用 FETCH。 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 SYS_REFCURSOR 型遊標，該遊標是 Oracle 以預先定義的遊標，可作出引數進行傳遞 create or replace procedure test1 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 中可使用三個狀態屬性： NOTFOUND 未找到記錄資訊 FOUND 找到記錄資訊 ROWCOUNT 然後當前遊標所指向的行位置 dbms_outputputline name end LOOP rsCursor cursor end test1 儲存過程 檢視儲存過程： select text from USER_SOURCE where nameMy_Store_Precedure_Name order by LINE 類似的語言 功能近似 PLSQL 的程式語言和其他關係型資料庫： Sybase ASE Microsoft SQL Server 的 TransactSQL PostgreSQL 資料庫的 PLpgSQL（模仿 PLSQL） IBM DB2 的 SQL PLSQL PL 符合 ISO SQL 的 SQLPSM 標準。 PLSQL 的工作方式類似於與其他關係資料庫關聯的嵌入式過程語言。 例如，Sybase ASE 和 Microsoft SQL Server 具有 TransactSQL，PostgreSQL 具有 PLpgSQL（在一定程度上模擬 PLSQL），MariaDB 包括 PLSQL 相容性解析器，而 IBM Db2 包括 SQL 過程語言，符合 ISO SQL 的 SQLPSM 標準。 PLSQL 的設計者將其語法建模為 Ada 的語法。 Ada 和 PLSQL 都以 Pascal 語言作為共同的祖先，因此 PLSQL 在大多數方面也類似於 Pascal。 然而，PLSQL 包的結構與 Borland Delphi 或 Free Pascal 單元實現的基本 Object Pascal 程式結構並不相似。 程式設計師可以在 PLSQL 包中定義公共和私有全域性資料型別、常量和靜態變數。 PLSQL 還允許定義類並將它們例項化為 PLSQL 程式碼中的物件。 這類似於面向物件程式語言（如 Object Pascal、C 和 Java）中的用法。 PLSQL 將類稱為 抽象資料型別ADT 或 使用者定義型別UDT，並將其定義為 Oracle SQL 資料型別而不是 PLSQL 使用者定義型別，從而允許 它在 Oracle SQL 引擎和 Oracle PLSQL 引擎中的使用。 抽象資料型別的建構函式和方法是用 PLSQL 編寫的。 生成的抽象資料型別可以作為 PLSQL 中的物件類進行操作。 此類物件還可以作為 Oracle 資料庫表中的列值保留。 儘管表面上相似，但 PLSQL 與 TransactSQL 本質上是不同的。 將程式碼從一種語言移植到另一種語言通常涉及不平凡的工作，這不僅是因為兩種語言的功能集存在差異，還因為 Oracle 和 SQL Server 處理併發的方式存在非常顯著的差異 和鎖定。 註釋 參考文獻 外部連結 參見 Oracle 資料庫 SQL TransactSQL 關聯式資料庫管理系統 CategorySQL Category 甲骨文公司軟體 CategoryAda 程式語言家族