PL/SQL ( Procedural Language for SQL ) は、Oracle CorporationのSQLおよびOracle リレーショナル データベース用のプロシージャ拡張機能です。PL/SQL は、Oracle Database (バージョン 6 以降 - バージョン 7 以降は格納された PL/SQL プロシージャ/関数/パッケージ/トリガー)、TimesTen インメモリ データベース(バージョン 11.2.1 以降)、およびIBM Db2 (バージョン 9.7 以降) で使用できます。[ 1 ] Oracle Corporation は通常、Oracle Database の各リリースで PL/SQL の機能を拡張しています。
PL/SQLには、条件やループなどの手続き型言語要素が含まれており、例外(実行時エラー)を処理できます。定数と変数、プロシージャ、関数、パッケージ、型とその型の変数、およびトリガーの宣言が可能です。配列は、PL/SQLコレクションを使用してサポートされます。Oracle Databaseバージョン8以降の実装には、オブジェクト指向に関連する機能が含まれています。プロシージャ、関数、パッケージ、型、トリガーなどのPL/SQLユニットを作成し、Oracle Databaseのプログラミングインターフェースを使用するアプリケーションで再利用できるようにデータベースに格納できます。
PL/SQL定義の最初の公開バージョン[ 2 ]は1995年に発表されました。これはISO SQL/PSM標準を実装しています。[ 3 ]
SQL(非手続き型)の主な特徴は同時に欠点でもあります。SQLのみを使用する場合、制御文(意思決定や反復制御)は使用できません。PL/SQLは、意思決定や反復など、他の手続き型プログラミング言語の機能を提供します。PL/SQLプログラムユニットは、PL/SQL匿名ブロック、プロシージャ、関数、パッケージ仕様、パッケージ本体、トリガー、型仕様、型本体、ライブラリのいずれかです。プログラムユニットは、開発、コンパイルされ、最終的にデータベース上で実行されるPL/SQLソースコードです。[ 4 ]
PL/SQLソースプログラムの基本単位はブロックであり、関連する宣言とステートメントをグループ化します。PL/SQLブロックは、キーワードDECLARE、BEGIN、EXCEPTION、およびENDによって定義されます。これらのキーワードは、ブロックを宣言部、実行部、および例外処理部に分割します。宣言部はオプションであり、定数と変数を定義および初期化するために使用できます。変数が初期化されていない場合、デフォルト値はNULLになります。オプションの例外処理部は、実行時エラーを処理するために使用されます。実行部のみが必須です。ブロックにはラベルを付けることができます。[ 5 ]
例えば:
<<label>> -- これはオプションですDECLARE -- このセクションはオプションですnumber1 NUMBER ( 2 ); number2 number1 %TYPE := 17 ; -- 値のデフォルト値text1 VARCHAR2 ( 12 ) := ' Hello world ' ; text2 DATE := SYSDATE ; -- 現在の日時BEGIN -- このセクションは必須です。少なくとも 1 つの実行可能なステートメントを含める必要がありますSELECT street_number INTO number1 FROM address WHERE name = 'INU' ; EXCEPTION -- このセクションはオプションですWHEN OTHERS THEN DBMS_OUTPUT . PUT_LINE ( 'エラー コードは ' || TO_CHAR ( sqlcode )); DBMS_OUTPUT . PUT_LINE ( 'エラー メッセージは ' || sqlerrm ); END ;この記号は、値を変数に格納するための代入演算子:=として機能します。
ブロックはネストできます。つまり、ブロックは実行可能なステートメントであるため、実行可能なステートメントが許可されている場所であれば、他のブロック内にも配置できます。ブロックは、対話型ツール(SQL*Plusなど)に送信したり、OracleプリコンパイラまたはOCIプログラムに埋め込んだりできます。対話型ツールまたはプログラムは、ブロックを一度実行します。ブロックはデータベースに保存されないため、ラベルが付いていても匿名ブロックと呼ばれます。
PL/SQL関数の目的は、一般的に単一の値を計算して返すことです。返される値は、単一のスカラー値(数値、日付、文字列など)または単一のコレクション(ネストされたテーブルや配列など)である場合があります。 ユーザー定義関数は、 Oracle Corporationが提供する組み込み関数を補完します。[ 6 ]
PL/SQL関数の形式は次のとおりです。
CREATE OR REPLACE FUNCTION < function_name > [(入力/出力変数宣言)] RETURN return_type [ AUTHID < CURRENT_USER | DEFINER > ] < IS | AS > -- 見出し部分金額数値; -- 宣言ブロックBEGIN -- 実行部分<戻り値ステートメントを含むPL / SQLブロック> RETURN < return_value > ; [ Exception none ] RETURN < return_value > ; END ;パイプライン化されたテーブル関数はコレクション[ 7 ]を返し 、次の形式をとります。
CREATE OR REPLACE FUNCTION < function_name > [(入力/出力変数宣言)] RETURN return_type [ AUTHID < CURRENT_USER | DEFINER > ] [ < AGGREGATE | PIPELINED > ] < IS | USING > [宣言ブロック] BEGIN <戻り値ステートメントを含むPL / SQLブロック> PIPE ROW <戻り値タイプ> ; RETURN ; [例外例外ブロック] PIPE ROW <戻り値タイプ> ; RETURN ; END ;関数は、デフォルトのIN型パラメータのみを使用する必要があります。関数から出力される値は、関数が返す値のみであるべきです。
プロシージャは、繰り返し呼び出すことができる名前付きプログラム単位であるという点で関数に似ています。主な違いは、関数はSQL文で使用できるのに対し、プロシージャは使用できないことです。もう1つの違いは、プロシージャは複数の値を返すことができるのに対し、関数は単一の値しか返さないことです。[ 8 ]
プロシージャは、プロシージャ名とオプションでプロシージャパラメータリストを格納する必須のヘッダー部分から始まります。次に、PL/SQLの匿名ブロックと同様に、宣言部分、実行部分、例外処理部分が続きます。簡単なプロシージャは次のようになります。
CREATE PROCEDURE create_email_address ( -- プロシージャのヘッダー部分の開始name1 VARCHAR2 , name2 VARCHAR2 , company VARCHAR2 , email OUT VARCHAR2 ) -- プロシージャのヘッダー部分の終了AS -- 宣言部分の開始 (オプション) error_message VARCHAR2 ( 30 ) := 'メールアドレスが長すぎます。' ; BEGIN -- 実行可能部分の開始 (必須) email := name1 || '.' || name2 || '@' || company ; EXCEPTION -- 例外処理部分の開始 (オプション) WHEN VALUE_ERROR THEN DBMS_OUTPUT . PUT_LINE ( error_message ); END create_email_address ;上記の例はスタンドアロンプロシージャを示しています。このタイプのプロシージャは、CREATE PROCEDURE文を使用してデータベーススキーマに作成および格納されます。プロシージャはPL/SQLパッケージ内に作成することもできます。これはパッケージプロシージャと呼ばれます。PL/SQL匿名ブロック内に作成されたプロシージャは、ネストされたプロシージャと呼ばれます。データベースに格納されるスタンドアロンプロシージャまたはパッケージプロシージャは、「ストアドプロシージャ」と呼ばれます。
手順には、IN、OUT、IN OUTの3種類のパラメータがあります。
PL/SQLはOracleデータベースの標準ext-procプロセスを介して外部プロシージャもサポートしています。[ 9 ]
パッケージは、概念的にリンクされた関数、プロシージャ、変数、PL/SQL テーブルおよびレコード TYPE ステートメント、定数、カーソルなどのグループです。パッケージを使用すると、コードの再利用が促進されます。パッケージは、パッケージ仕様とオプションのパッケージ本体で構成されます。仕様はアプリケーションへのインターフェースであり、使用可能な型、変数、定数、例外、カーソル、およびサブルーチンを宣言します。本体はカーソルとサブルーチンを完全に定義し、仕様を実装します。パッケージの 2 つの利点は次のとおりです。[ 10 ]
データベーストリガーは、指定されたイベントが発生するたびにOracle Databaseが自動的に呼び出すストアドプロシージャのようなものです。データベースに格納される名前付きPL/SQLユニットであり、繰り返し呼び出すことができます。ストアドプロシージャとは異なり、トリガーは有効化と無効化が可能ですが、明示的に呼び出すことはできません。トリガーが有効になっている間は、トリガーイベントが発生するたびにデータベースが自動的にトリガーを呼び出します(つまり、トリガーが起動します)。トリガーが無効になっている間は、トリガーは起動しません。
トリガーは、CREATE TRIGGER ステートメントを使用して作成します。トリガーとなるイベントは、トリガーステートメントと、それらが作用する対象項目によって指定します。トリガーは、対象項目(テーブル、ビュー、スキーマ、またはデータベース)に対して作成または定義されます。また、トリガーがトリガーステートメントの実行前か実行後か、およびトリガーステートメントが影響を与える各行に対してトリガーが実行されるかどうかを決定するタイミングポイントも指定します。
トリガーがテーブルまたはビュー上に作成される場合、トリガーイベントはDMLステートメントで構成され、そのトリガーはDMLトリガーと呼ばれます。トリガーがスキーマまたはデータベース上に作成される場合、トリガーイベントはDDLステートメントまたはデータベース操作ステートメントで構成され、そのトリガーはシステムトリガーと呼ばれます。
INSTEAD OF トリガーとは、ビューに対して作成された DML トリガー、または CREATE ステートメントに対して定義されたシステム トリガーのいずれかです。データベースは、トリガーとなるステートメントを実行する代わりに、INSTEAD OF トリガーを起動します。
トリガーは、以下の目的で作成できます。
PL/SQLの主なデータ型には、NUMBER、CHAR、VARCHAR2、DATE、TIMESTAMPなどがあります。
変数名番号([ P , S ]) := 0 ;数値変数を定義するには、プログラマーは変数名の定義に変数型「NUMBER」を追加します。精度(P)と小数点以下桁数(S)を指定するには、これらを丸括弧で囲み、カンマで区切って追加します。(ここでいう「精度」とは変数が保持できる桁数を指し、「小数点以下桁数」とは小数点以下の桁数を指します。)
数値変数に使用できるその他のデータ型としては、binary_float、binary_double、dec、decimal、double precision、float、integer、int、numeric、real、small-int、binary_integer などがあります。
variable_name varchar2 ( 20 ) := 'Text' ;-- 例: address varchar2 ( 20 ) := 'lake view road' ;文字変数を定義する場合、プログラマーは通常、変数名の定義に変数型「VARCHAR2」を追加します。その後に括弧で囲んで、変数に格納できる最大文字数を指定します。
文字変数に使用できるその他のデータ型には、varchar、char、long、raw、long raw、nchar、nchar2、clob、blob、bfileなどがあります。
variable_name date := to_date ( '01-01-2005 14:20:23' , 'DD-MM-YYYY hh24:mi:ss' );日付変数には日付と時刻を含めることができます。時刻を省略することはできますが、時刻のみを含む変数を定義する方法はありません。DATETIME 型はありません。TIME 型はありますが、ミリ秒またはナノ秒までの細かいタイムスタンプを格納できる TIMESTAMP 型はありません。このTO_DATE関数は、文字列を日付値に変換するために使用できます。この関数は、2 番目の引用符付き文字列を定義として使用して、最初の引用符付き文字列を日付に変換します。例:
to_date ( '31-12-2004' , 'dd-mm-yyyy' )または
to_date ( '31-Dec-2004' , 'dd-mon-yyyy' , 'NLS_DATE_LANGUAGE = American' )日付を文字列に変換するには、関数を使用しますTO_CHAR (date_string, format_string)。
PL/SQLはANSI日付および間隔リテラルの使用もサポートしています。[ 11 ]次の句は18か月の範囲を指定します。
WHERE dateField BETWEEN DATE '2004-12-30' - INTERVAL '1-6' YEAR TO MONTH AND DATE '2004-12-30'例外(コード実行中のエラー)には、ユーザー定義の例外と事前定義の例外の2種類があります。
ユーザー定義例外は、プログラマが通常の実行を継続することが不可能だと判断した状況で、常に明示的に、RAISEまたはコマンドを使用して発生します。コマンドの構文は次のとおりです。RAISE_APPLICATION_ERRORRAISE
例外名をRAISEする;Oracle Corporationは、、などのいくつかの例外を事前に定義しています。各例外には、SQLエラー番号とSQLエラーメッセージが関連付けられています。プログラマーは、および関数 を使用してこれらにアクセスできます。NO_DATA_FOUNDTOO_MANY_ROWSSQLCODESQLERRM
変数名テーブル名.列名%型;
この構文は、参照されるテーブル上の参照される列の型の変数を定義します。
プログラマーは、以下の構文でユーザー定義データ型を指定します。
type data_typeはrecord ( field_1 type_1 := xyz , field_2 type_2 := xyz , ... , field_n type_n := xyz );例えば:
declare type t_address is record ( name address . name %type , street address . street %type , street_number address . street_number %type , postcode address . postcode %type ); v_address t_address ; begin select name , street , street_number , postcode into v_address from address where rownum = 1 ; end ;このサンプルプログラムは、 t_addressという独自のデータ型を定義しており、 name、street、street_number、postcodeというフィールドが含まれています。
この例によれば、データベースからプログラムのフィールドにデータをコピーすることができる。
このデータ型を使用して、プログラマーはv_addressという変数を定義し、ADDRESSテーブルからデータをロードしました。
プログラマーは、ドット表記法を用いて、このような構造内の個々の属性にアクセスできます。
v_address.street := 'ハイストリート';
以下のコード例は、IF-THEN-ELSIF-ELSE構文を示しています。ELSIFとELSEの部分は省略可能なので、よりシンプルなIF-THEN構文やIF-THEN-ELSE構文を作成することも可能です。
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文は、大規模なIF-THEN-ELSIF-ELSE構造を簡略化します。
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 ;PL/SQLでは配列を「コレクション」と呼びます。この言語では、次の3種類のコレクションが提供されています。
プログラマは可変配列の上限を指定する必要がありますが、インデックス付きテーブルやネストされたテーブルの場合は指定する必要はありません。この言語には、コレクション要素を操作するために使用されるいくつかのコレクションメソッドが含まれています。たとえば、FIRST、LAST、NEXT、PRIOR、EXTEND、TRIM、DELETE などです。インデックス付きテーブルは、PL/SQL の Ackermann 関数のメモ関数の例のように、連想配列をシミュレートするために使用できます。
インデックス付きテーブルでは、配列を数値または文字列でインデックス付けできます。これは、キーと値のペアで構成されるJavaのマップに相当します。次元は1つだけで、制限はありません。
ネストされたテーブルでは、プログラマーはネストされている内容を理解する必要があります。ここでは、複数のコンポーネントで構成される新しい型が作成されます。その型を使用してテーブルの列を作成することができ、その列の中にコンポーネントがネストされます。
可変サイズ配列(Varrays)を使う場合、「可変サイズ配列」という表現の「可変」という言葉は、皆さんが想像するような配列のサイズを指すものではないことを理解しておく必要があります。配列の宣言時に指定されるサイズは実際には固定されています。配列内の要素数は、宣言されたサイズまで可変です。つまり、可変サイズ配列は、実際にはそれほどサイズが可変ではないと言えるでしょう。
カーソルは、SELECT文またはデータ操作言語(DML)文(INSERT、UPDATE、DELETE、MERGE)から取得した情報を格納するプライベートなSQL領域へのポインタです。カーソルは、SQL文によって返された行(1つ以上)を保持します。カーソルが保持する行のセットは、アクティブセットと呼ばれます。[ 12 ]
カーソルは明示的または暗黙的に使用できます。FORループでは、クエリを再利用する場合は明示的なカーソルを使用し、そうでない場合は暗黙的なカーソルを使用することをお勧めします。ループ内でカーソルを使用する場合は、一括収集が必要な場合や動的SQLが必要な場合はFETCHを使用することをお勧めします。
PL/SQLは定義上手続き型言語であるため、基本的なLOOP文、WHILEループ、FORループ、カーソルFORループなど、いくつかの反復構造を提供します。Oracle 7.3以降、レコードセットをストアドプロシージャや関数から返すことができるように、REF CURSOR型が導入されました。Oracle 9iでは、事前定義されたSYS_REFCURSOR型が導入されたため、独自のREF CURSOR型を定義する必要がなくなりました。
<<parent_loop>>ループ文<<child_loop>>ループステートメントexit parent_loop when < condition > ; -- 両方のループを終了exit when < condition > ; -- 制御を parent_loop に戻すend loop child_loop ; if < condition > then continue ; -- 次のイテレーションに進むend if ;<条件>が満たされたら終了する; END LOOP parent_loop ;EXITループは、キーワードを使用するか、例外を発生させることによって終了できます。
DECLARE var NUMBER ; BEGIN /* 注: PL/SQL の for ループ変数は新規宣言であり、スコープはループ内のみです */ FOR var IN 0 .. 10 LOOP DBMS_OUTPUT . PUT_LINE ( var ); END LOOP ;IF var IS NULL THEN DBMS_OUTPUT . PUT_LINE ( 'var is null' ); ELSE DBMS_OUTPUT . PUT_LINE ( 'var is not null' ); END IF ; END ;出力:
0 1 2 3 4 5 6 7 8 9 10 var は null です
FOR RecordIndex IN ( SELECT person_code FROM people_table ) LOOP DBMS_OUTPUT . PUT_LINE ( RecordIndex . person_code ); END LOOP ;カーソルforループは、自動的にカーソルを開き、データを読み込み、カーソルを閉じます。
代替案として、PL/SQLプログラマはカーソルのSELECT文を事前に定義しておくことで、(例えば)再利用を可能にしたり、コードをより理解しやすくしたりすることができます(特に、長くて複雑なクエリの場合に役立ちます)。
DECLARE CURSOR cursor_person IS SELECT person_code FROM people_table ; BEGIN FOR RecordIndex IN cursor_person LOOP DBMS_OUTPUT . PUT_LINE ( recordIndex . person_code ); END LOOP ; END ;FORループ内のperson_codeの概念は、ドット表記(".")で表されます。
RecordIndex.person_codeプログラマーは、単純なSQL文を用いることで、データ操作言語(DML)文をPL/SQLコードに直接容易に埋め込むことができますが、データ定義言語(DDL)では、PL/SQLコード内に、より複雑な「動的SQL」文が必要となります。しかしながら、一般的なソフトウェアアプリケーションでは、PL/SQLコードの大部分はDML文によって支えられています。
PL/SQLの動的SQLの場合、Oracle Databaseの初期バージョンでは複雑なOracleDBMS_SQLパッケージライブラリを使用する必要がありました。しかし、より新しいバージョンでは、よりシンプルな「ネイティブ動的SQL」と、それに関連するEXECUTE IMMEDIATE構文が導入されています。
PL/SQLは、他のリレーショナルデータベースに関連付けられている組み込みの手続き型言語と類似した動作をします。たとえば、Sybase ASEとMicrosoft SQL ServerにはTransact-SQLがあり、PostgreSQLにはPL/pgSQL(ある程度PL/SQLをエミュレートします)があり、MariaDBにはPL/SQL互換パーサーが含まれており[ 14 ]、IBM Db2にはISO SQLのSQL/PSM標準 に準拠したSQL手続き型言語が含まれています[ 15 ]。
PL/SQL の設計者は、その構文をAdaの構文を参考にしました。Ada と PL/SQL はどちらもPascal を共通の祖先としており、そのため PL/SQL はほとんどの点で Pascal に似ています。ただし、PL/SQL パッケージの構造は、Borland DelphiやFree Pascalユニットで実装される基本的なObject Pascalプログラム構造とは似ていません。プログラマは、PL/SQL パッケージ内でパブリックおよびプライベートのグローバルデータ型、定数、静的変数を定義できます。[ 16 ]
PL/SQLでは、クラスを定義し、PL/SQLコード内でオブジェクトとしてインスタンス化することも可能です。これは、Object Pascal、C++、Javaなどのオブジェクト指向プログラミング言語での使用方法に似ています。PL/SQLでは、クラスを「抽象データ型」(ADT)または「ユーザー定義型」(UDT)と呼び、PL/SQLのユーザー定義型ではなくOracle SQLのデータ型として定義するため、 Oracle SQLエンジンとOracle PL/SQLエンジンの両方で使用できます。抽象データ型のコンストラクタとメソッドはPL/SQLで記述します。結果として得られる抽象データ型は、PL/SQLのオブジェクトクラスとして動作できます。このようなオブジェクトは、Oracleデータベーステーブルの列値として永続化することもできます。
PL/SQLは、表面的な類似点があるにもかかわらず、 Transact-SQLとは根本的に異なります。一方から他方へコードを移植するには、通常、簡単な作業ではありません。これは、2つの言語の機能セットの違い[ 17 ]だけでなく、OracleとSQL Serverが並行処理とロックを処理する方法に大きな違いがあるためです。
StepSqlite製品は、人気の小規模データベースSQLite用の PL/SQL コンパイラで、PL/SQL 構文のサブセットをサポートしています。Oracle のBerkeley DB 11g R2 リリースでは、Berkeley DB に SQLite のバージョンを含めることで、人気の SQLite API に基づくSQLのサポートが追加されました。 [ 18 ]そのため、StepSqlite は、Berkeley DB 上で PL/SQL コードを実行するためのサードパーティ ツールとしても使用できます。[ 19 ]
{{cite web}}: CS1 maint: 複数の名前: 著者リスト (リンク)パイプラインテーブル関数は、結果セットをコレクションとして反復的に返します。各行がコレクションに割り当てられる準備が整うと、関数から「パイプアウト」されます。
/SQLランタイムエンジンが外部プロシージャ呼び出しを検出すると、Oracle Databaseはextprocプロセスを開始します。データベースは呼び出し仕様から受け取った情報をプロセスに渡しextproc、プロセスはライブラリ内の外部プロシージャを特定し、指定されたパラメータを使用して実行します。extprocプロセスは動的リンクライブラリをロードし、外部プロシージャを実行して、結果をデータベースに返します。
DB は PL/SQL をサポートしていますか?