Oracle® Developer データベース互換性Guide
 
 
 
EDB Postgres™Advanced Server 11
2018年11月20日
 
 
 
 
1 はじめに
オラクルの データベース互換性とは、アプリケーションがOracle環境だけでなく、 EDB Postgres Advanced Server(Advanced Server)環境で動作し、アプリケーションコードをほとんど変更しないか、またはまったく変更しないことを意味します。 Advanced Server でOracleデータベースと互換性のあるアプリケーションを開発するには、アプリケーションの構築にどの機能が使用されているかを特に注意する必要があります。たとえば、 互換性のあるアプリケーションを開発するということは、
SQLステートメントおよびプロシージャー・ロジックで使用するためのシステムおよび組み込み関数
ストアド・プロシージャ 、ファンクション、トリガー、およびパッケージのデータベース・サーバー側アプリケーション・ロジックを作成するときは、 ストアド・プロシージャー言語SPL )を使用します。
Oracleのデータ・ディクショナリと互換性のあるシステム・カタログ・ビュー
互換性のあるSQL構文、データ型、およびビューの詳細は、 「Oracle Developer Reference Guide」のデータベース互換性 を参照してください
ビルトイン・パッケージの一部であるプロシージャとファンクションで提供される 互換性については、「Oracle Developerのビルトイン・パッケージ データベース互換性ガイド」に記載されています。
Advanced Serverインストールに含まれている互換ツールおよびユーティリティ(EDB * Plus、EDB * Loader、DRITA、およびEDB * Wrap)の使用については、「 Oracle Developer Tools and Utilities Guide」のデータベース互換性 を参照してください
Oracle Call Interface (OCI) を使用して作成されたアプリケーションの場合 、EnterpriseDBの Open Client Library OCL )は、これらのアプリケーションとの相互運用性を提供します。 Open Client Libraryの使用方法の詳細については、「 EDB Postgres Advanced Server OCI Connector Guide」 を参照してください
Advanced Serverには、 PostgreSQLまたはOracle用のデータベースアプリケーションの開発を可能にする豊富な機能が含まれています 。 Advanced Serverのすべての機能の詳細については、EnterpriseDBのWebサイトにあるユーザーマニュアルを参照してください。
Advanced Serverのドキュメントは次の場所から入手できます。
https://www.enterprisedb.com/resources/product-documentation
1.1 新機能
Advanced Server 11を作成するためにAdvanced Server 10に 以下の Oracle機能のデータベース互換性が追加されました
Advanced Serverは、任意のSPLブロック内でPRAGMA AUTONOMOUS_TRANSACTION指示文を サポートし 、自律型トランザクション機能を提供するようになりました。詳細は、 3.6.3項を参照してください。
1.2 このガイドで使用される表記規則
このマニュアルでは、さまざまなコマンド、文、プログラム、例などの意味と使用法を明確にするために、特定の表記規則が使用されています。このセクションでは、これらの規則の概要を説明します。
以下の説明では、 用語は、言語キーワード、ユーザ提供値、リテラルなどの任意の単語または単語群を指す。用語の正確な意味は、それが使用される文脈に依存する。
イタリック体のフォントで は、通常、最初に定義された文章に新しい用語が導入されています。
固定幅(単間隔)フォント は、 SQL コマンド、例で使用されている特定のテーブルとカラム名、プログラミング言語キーワード など、文字通り与えなければならない用語に使用され ます 。たとえば、 SELECT * FROM emp;
イタリック固定幅フォント は、ユーザーが実際の使用で値を置き換える必要がある用語に使用されます。たとえば、 DELETE FROM table_name ;
角括弧[]は、囲まれた用語の1つまたはいずれかが置換されている可能性があることを示します。たとえば、 [a | b]は 、「 a 」または「 b 」のいずれかを選択するか、またはどちらも選択しないことを意味します。
中括弧{}は、囲まれた選択肢のうちの1つを指定する必要があることを示します。たとえば、 {a | b}は 、 " a "または " b "のうちの1つを指定する必要があることを意味します。
楕円形...とは、進行中の用語を繰り返すことができることを意味します。たとえば、 [a | b] ...は、あなたがシーケンス「 baaba 」を持っているかもしれないことを意味します。
1.3 Oracleデータベースと互換性のある構成パラメータ
EDB Postgres Advanced Serverは、 PostgreSQLおよびOracle互換性のあるアプリケーションの開発と実行をサポートします 。いくつかのシステム動作は、より多くのPostgreSQLまたはよりOracleに準拠した方法で動作するように変更することができます。これらの動作は構成パラメータによって制御されます。ユーザーまたはグループが唯一の彼らのセッションを行うには、コマンドラインでパラメータ値を設定することができながら、postgresql.confファイル内のパラメータを変更すると、クラスタ内のすべてのデータベースの動作を変更します。これらのパラメータは次のとおりです。
edb_redwood_date - DATE列に時刻コンポーネントを格納するかどうかを制御します。 Oracleデータベース互換性のある動作の場合は、 edb_redwood_dateTRUEに設定します 。セクションを参照 1.3.1
edb_redwood_raw_names - Oracleシステムカタログから見たときにデータベースオブジェクト名を大文字で表示するか小文字で表示するかを制御します。 Oracleデータベース互換性のある動作の場合、 edb_redwood_raw_namesはデフォルト値のFALSEに設定されます 。実際にPostgreSQLシステムカタログに格納されているデータベースオブジェクト名を表示するには、 edb_redwood_raw_namesTRUEに設定します。 1.3.2節を参照してください。
edb_redwood_strings - 文字列連結操作のために空の文字列にnullを指定します。 Oracleデータベース互換性のある動作の場合は、 edb_redwood_stringstrueに設定します1.3.3節を参照してください。
edb_stmt_level_tx - 中断されたSQLコマンドの自動ロールバックを文レベルのロールバックのみに分離します。デフォルトのPostgreSQLの動作と同様に、現在のトランザクション全体が自動的にロールバックされません。 Oracleデータベース互換性のある動作の 場合はedb_stmt_level_txtrueに設定します 。ただし、絶対に必要な場合にのみ使用してください。 1.3.4節を参照してください。
o racle_home - Advanced Serverを正しいOracleインストール・ディレクトリにポイントします。 1.3.5項を参照してください。
 
1.3.1 edb_redwood_date
場合 DATE、コマンドの列のデータ・タイプとして表示され、I Tは、設定パラメータedb_redwood_dateが trueに設定されている場合、テーブル定義はデータベースに格納された時点でタイムスタンプに変換されます。したがって、時間成分も日付とともに列に格納されます。これは、 OracleDATEデータ型と一致しています
edb_redwood_datefalseに設定されている場合CREATE TABLEまたはALTER TABLEコマンドのカラムのデータ型は、元のPostgreSQL DATEデータ型のままで、そのままデータベースに格納されます。 PostgreSQLの DATEデータ型は、列に時間コンポーネントを含まない日付のみを格納します。
関係なく設定の 日付は 、このようなSPL宣言セクション内の変数のデータ・タイプ、またはSPLプロシージャまたはSPL関数で仮パラメータのデータ型、または他の任意の文脈でデータ型として現れedb_redwood_date、 SPL関数の戻り型では、常に内部的にTIMESTAMPに変換されるため、存在する場合は時間コンポーネントを処理できます
日付/時刻データ型の詳細は、「 Oracle Developer Reference Guide」 Database Compatibilityを 参照してください
1.3.2 edb_redwood_raw_names
とき edb_redwood_raw_namesが FALSEのデフォルト値に設定されているOracleカタログから見たとき、などのテーブル名、列名、トリガー名、プログラム名、ユーザ名、などのデータベース・オブジェクト名は、サポートされているカタログの完全なリストについては、(大文字で表示されますOracle Developer Reference Reference GuideのDatabase Compatibilityを参照してください)。さらに、引用符は、囲み引用符で作成された名前を囲みます。
edb_redwood_raw_namesTRUEに設定されている場合 、データベースオブジェクト名は、Oracleカタログから見たときにPostgreSQLシステムカタログに格納されているとおりに表示されます。したがって、引用符を囲まずに作成された名前は、PostgreSQLで期待どおり小文字で表示されます。囲み引用符で作成された名前は、作成されたとおりに正確に表示されますが、引用符は使用しません。
たとえば、次のユーザー名が作成され、そのユーザーがセッションを開始します。
CREATE USER reduser IDENTIFIED BY password;
edb=# \c - reduser
Password for user reduser:
You are now connected to database "edb" as user "reduser".
reduser としてデータベースに接続すると、次の表が作成されます。
CREATE TABLE all_lower (col INTEGER);
CREATE TABLE ALL_UPPER (COL INTEGER);
CREATE TABLE "Mixed_Case" ("Col" INTEGER);
edb_redwood_raw_namesをデフォルト値FALSEに設定したOracleカタログ USER_TABLES から見た 場合 、名前はMixed_Case名を除いて大文字で表示されます。名前は作成されたものとして表示され、引用符で囲まれて表示されます。
edb=> SELECT * FROM USER_TABLES;
schema_name | table_name | tablespace_name | status | temporary
-------------+--------------+-----------------+--------+-----------
REDUSER | ALL_LOWER | | VALID | N
REDUSER | ALL_UPPER | | VALID | N
REDUSER | "Mixed_Case" | | VALID | N
(3 rows)
で見た場合 TRUEに設定edb_redwood_raw_names、名前が作成されたとして表示されますが、今で囲む引用符Mixed_Case名を除いて小文字で表示されます。
edb=> SET edb_redwood_raw_names TO true;
SET
edb=> SELECT * FROM USER_TABLES;
schema_name | table_name | tablespace_name | status | temporary
-------------+------------+-----------------+--------+-----------
reduser | all_lower | | VALID | N
reduser | all_upper | | VALID | N
reduser | Mixed_Case | | VALID | N
(3 rows)
これらの名前は、PostgreSQLの pg_tablesカタログから見た場合と一致します。
edb=> SELECT schemaname, tablename, tableowner FROM pg_tables WHERE tableowner = 'reduser';
schemaname | tablename | tableowner
------------+------------+------------
reduser | all_lower | reduser
reduser | all_upper | reduser
reduser | Mixed_Case | reduser
(3 rows)
1.3.3 edb_redwood_strings
オラクル 、文字列はヌル変数またはnullカラムと連結されている場合、結果は、元の文字列です。しかし、 PostgreSQLでは、文字列を変数nullまたはNULLで連結すると、結果がNULLになります。 edb_redwood_stringsパラメータがtrueに設定されている場合 、前述の連結操作では、 Oracleによって行われた元の文字列が返されますedb_redwood_stringsfalseに設定されている場合、ネイティブのPostgreSQLの動作は維持されます。
次の例は、その違いを示しています。
次のセクションで紹介するサンプル・アプリケーションには、従業員の表が含まれています。この表には、ほとんどの従業員にとってNULLであるcommという名前の列があります。次のクエリは、 edb_redwood_stringfalseに設定して実行します 。ヌル列と空でない文字列を連結すると、最終的な結果がNULLになるため、コミッションを持つ従業員だけがクエリ結果に表示されます。他のすべての従業員の出力行はNULLです。
SET edb_redwood_strings TO off;
 
SELECT RPAD(ename,10) || ' ' || TO_CHAR(sal,'99,999.99') || ' ' || TO_CHAR(comm,'99,999.99') "EMPLOYEE COMPENSATION" FROM emp;
 
EMPLOYEE COMPENSATION
----------------------------------
 
ALLEN 1,600.00 300.00
WARD 1,250.00 500.00
 
MARTIN 1,250.00 1,400.00
 
 
 
 
TURNER 1,500.00 .00
 
 
 
 
(14 rows)
以下は、 edb_redwood_stringsTRUEに設定されているときに実行される同じクエリです。ここでは、NULL列の値は空の文字列として扱われます。空の文字列を空でない文字列と連結すると、空でない文字列が生成されます。この結果は、同じクエリに対してOracleによって生成された結果と一致します。
SET edb_redwood_strings TO on;
 
SELECT RPAD(ename,10) || ' ' || TO_CHAR(sal,'99,999.99') || ' ' || TO_CHAR(comm,'99,999.99') "EMPLOYEE COMPENSATION" FROM emp;
 
EMPLOYEE COMPENSATION
----------------------------------
SMITH 800.00
ALLEN 1,600.00 300.00
WARD 1,250.00 500.00
JONES 2,975.00
MARTIN 1,250.00 1,400.00
BLAKE 2,850.00
CLARK 2,450.00
SCOTT 3,000.00
KING 5,000.00
TURNER 1,500.00 .00
ADAMS 1,100.00
JAMES 950.00
FORD 3,000.00
MILLER 1,300.00
(14 rows)
1.3.4 edb_stmt_level_tx
ランタイムエラーは、SQLコマンドで発生したときに、Oracle、その単一のコマンドによって引き起こされるデータベース上のすべての更新がロールバックされます。これは、 文レベルのトランザクション分離と呼ばれます 。たとえば、1つのUPDATEコマンドが5行を正常に更新するが、6行目を更新しようとすると例外が発生した場合、このUPDATEコマンドによって作成された6行すべての更新がロールバックされます。コミットまたはロールバックされていない以前のSQLコマンドの影響は、 COMMITコマンドまたはROLLBACKコマンドが実行されるまで保留されます。
では SQLコマンドの実行中に例外が発生した場合のPostgreSQL、トランザクションの開始以来、データベース上のすべての更新がロールバックされます。さらに、トランザクションは中止状態のままであり、別のトランザクションを開始する前にCOMMITまたはROLLBACKコマンドを発行する必要があります。
edb_stmt_level_txTRUEに設定されている場合 、例外はコミットされていないデータベースの更新を自動的にロールバックして、 Oracleの動作をエミュレートしません。 edb_stmt_level_txFALSEに設定されている場合 、例外はコミットされていないデータベースの更新をロールバックします。
注意:絶対に必要な場合にのみ、 edb_stmt_level_txTRUEに設定してください。パフォーマンスに悪影響を与える可能性があります。
次の例ではedb_stmt_level_txFALSEの場合 、2番目のINSERTコマンドのアボートによって最初のINSERTコマンドがロールバックされること PSQLで示されていますPSQLでは、コマンド\ set AUTOCOMMIT offを発行する必要があります。そうないと、すべての文が自動的にedb_stmt_level_txの効果のデモンストレーションの目的を破棄します。
\set AUTOCOMMIT off
SET edb_stmt_level_tx TO off;
 
INSERT INTO emp (empno,ename,deptno) VALUES (9001, 'JONES', 40);
INSERT INTO emp (empno,ename,deptno) VALUES (9002, 'JONES', 00);
ERROR: insert or update on table "emp" violates foreign key constraint "emp_ref_dept_fk"
DETAIL: Key (deptno)=(0) is not present in table "dept".
 
COMMIT;
SELECT empno, ename, deptno FROM emp WHERE empno > 9000;
 
empno | ename | deptno
-------+-------+--------
(0 rows)
次の例では、 edb_stmt_level_txTRUEに設定して、2番目のINSERTコマンドで最初のINSERTコマンドがエラーの後にロールバックされていません。この時点で、最初のINSERTコマンドをコミットまたはロールバックできます。
\set AUTOCOMMIT off
SET edb_stmt_level_tx TO on;
 
INSERT INTO emp (empno,ename,deptno) VALUES (9001, 'JONES', 40);
INSERT INTO emp (empno,ename,deptno) VALUES (9002, 'JONES', 00);
ERROR: insert or update on table "emp" violates foreign key constraint "emp_ref_dept_fk"
DETAIL: Key (deptno)=(0) is not present in table "dept".
 
SELECT empno, ename, deptno FROM emp WHERE empno > 9000;
 
empno | ename | deptno
-------+-------+--------
9001 | JONES | 40
(1 row)
 
COMMIT;
ROLLBACKコマンドは、代わりに社員番号9001の挿入が同様にロールバックされていたであろう、その場合には、COMMITコマンドを発行されている可能性があります。
1.3.5 oracle_home
Oracleサーバーへのリンクを作成する前に、Advanced Serverを正しいOracleホーム・ディレクトリに誘導する必要があります。設定する OracleのクライアントのインストールディレクトリのlibディレクトリにLD _ _ LIBRARY PATH環境変数Linux上で(またはWindows上のパスを )。
Windowsの場合のみ、代わりpostgresqlに oracle _ home構成パラメータの値を設定できます。 confファイル。 oracle _ home構成パラメータで指定された値は、Windows PATH環境変数よりも優先されます。
LDは、_ _ LIBRARY Linux上のPATH環境変数(PATH環境変数またはWindows上のORACLE_HOME設定パラメータ)を適切に使用すると、Advanced Serverを起動するたびに設定する必要があります。
Linuxサービススクリプトを使用してAdvanced Serverを起動する場合は、 LD_LIBRARY_PATHがサービススクリプト内に設定されていることを確認しください。スクリプトがpg_ctlユーティリティを呼び出してAdvanced Serverを起動したときに有効になります。
Windowsの場合のみ: postgresqlに oracle _ home構成パラメータを設定します。 confファイルを編集し、次の行を追加してファイルを編集します。
oracle_home = ' lib_directory '
oci を含むWindowsディレクトリの名前に 置き換えてくださいlib_directoryのためのdll
設定後 のOracle _ ホーム設定パラメータを、変更を有効にするには、サーバーを再起動する必要があります。 Windowsサービスコンソールからサーバーを再起動します。
 
1.4 このガイドで使用されているサンプルについて
このガイドに示す例は、 PSQL プログラム を使用して示してい ます。 これらの例では、 PSQLの 使用時に通常表示されるプロンプト は省略されています。
Examples and output from examples are shown in fixed-width, blue font on a light blue background.
また、次の点に注意してください。
EDB Postgres Advanced Serverの インストール中に 、このガイドに示す例と同じ結果を再現するために、Oracleデータベースと互換性のある構成とデフォルトの選択を選択する必要があります。デフォルトの互換性のある構成は、 PSQLで次のコマンドを発行し、以下に示すように同じ結果を得ることによって検証できます。
SHOW edb_redwood_date;
 
edb_redwood_date
------------------
on
 
SHOW datestyle;
 
DateStyle
--------------
Redwood, DMY
 
SHOW edb_redwood_strings;
 
edb_redwood_strings
---------------------
on
この例では、 Advanced Serverの インストール 作成およびロードされる サンプル表 dept emp および jobhistを 使用しています EMP テーブルは、このマニュアルに示されるように同じ結果を再現するために無効にされなければならないトリガーがインストールされています。 Enterprisedb スーパーユーザー として Advanced Serverに ログオンし 、次のコマンドを実行してトリガーを無効にします。
ALTER TABLE emp DISABLE TRIGGER USER;
emp テーブル のトリガは、 後で次のコマンドで再アクティブ化できます。
ALTER TABLE emp ENABLE TRIGGER USER;
2 SQLチュートリアル
このセクションでは、新規のリレーショナル・データベース管理システム SQL言語の概要を説明します。テーブルの作成、移入、クエリ、更新などの基本的な操作については、例とともに説明します。
ビュー、外部キー、トランザクションなど、より高度な概念についても説明します。
2.1 はじめに
Advanced Serverは、 リレーショナルデータベース管理システムRDBMS )です。つまり、 関係に格納されたデータを管理するシステムです。関係とは本質的に表のための数学的な用語です。テーブルにデータを格納するという考え方は、本質的に明らかであるように今日はあまり普及していませんが、データベースを整理する他の多くの方法があります。 Unixライクなオペレーティングシステム上のファイルとディレクトリは、階層型データベースの一例です。より現代的な開発は、オブジェクト指向のデータベースです。
各テーブルは、名前付きの 行の 集合です 。与えられた表の各行は同じ名前付き列のセットを持ち、各列は特定のデータ型です。各行には列の順序が固定されていますが、 SQLはテーブル内の行の順序を保証するものではありません(明示的に並べ替えて表示できます)。
テーブルは データベースグループ化され、1つのAdvanced Serverインスタンスによって管理されるデータベースの集まりがデータベースクラスタを構成します。
 
2.1.1 サンプルデータベース
このドキュメントでは、サンプルデータベースを使用して、基本レベルから高度なレベルのデータベースの概念について説明します。
2.1.1.1 サンプル・データベースのインストール
とき Advanced Serverが名前のサンプル・データベースをインストールされている、EDB、自動的に作成されます。このサンプル・データベースには、 / usr / edb / as11 / shareディレクトリーにあるスクリプトedb-sample.sqlを実行することにより、この文書全体で使用される表とプログラムが入っています
このスクリプトは次の処理を行います。
テーブルとプログラムは、現在のユーザーがテーブルとプロシージャを作成する権限を持っている検索パスの最初のスキーマに作成されます。検索パスを表示するには、次のコマンドを発行します。
SHOW SEARCH_PATH;
検索パスを変更するには、 PSQLの コマンドを使用します
2.1.1.2 サンプルデータベースの説明
サンプルデータベースは、組織内の従業員を表します。
従業員、部署、および従業員の履歴レコードの3種類のレコードが含まれています。
各従業員には、識別番号、名前、雇用日、給与、および管理者があります。一部の従業員は給与に加えて手数料をもらう。従業員関連の情報はすべて empテーブルに格納されます。
サンプル企業は地域的に多様なため、データベースは部門の所在を追跡します。各社員は部門に割り当てられています。各部門は、固有の部門番号と短い名前で識別されます。各部門は1つの場所に関連付けられています。部門に関するすべての情報は、 deptテーブルに保管されます。
同社はまた、従業員が保有する雇用に関する情報を追跡します。従業員の中には、長年にわたり会社と一緒にいて、異なるポジション、昇給、交換部門などを持っている人もいます。従業員ステータスの変更が発生すると、会社は元のポジションの終了日を記録します。新しいジョブレコードが追加され、開始日と新しい職務の役職、部門、給与、およびステータス変更の理由が記録されます。すべての従業員履歴は、 求職者テーブルに保持されます。
次に、サンプルのデータベーステーブルのエンティティ関係図を示します。
 
次は、 edb-sample.sqlスクリプトです。
--
-- Script that creates the 'sample' tables, views, procedures,
-- functions, triggers, etc.
--
-- Start new transaction - commit all or nothing
--
BEGIN;
/
--
-- Create and load tables used in the documentation examples.
--
-- Create the 'dept' table
--
CREATE TABLE dept (
deptno NUMBER(2) NOT NULL CONSTRAINT dept_pk PRIMARY KEY,
dname VARCHAR2(14) CONSTRAINT dept_dname_uq UNIQUE,
loc VARCHAR2(13)
);
--
-- Create the 'emp' table
--
CREATE TABLE emp (
empno NUMBER(4) NOT NULL CONSTRAINT emp_pk PRIMARY KEY,
ename VARCHAR2(10),
job VARCHAR2(9),
mgr NUMBER(4),
hiredate DATE,
sal NUMBER(7,2) CONSTRAINT emp_sal_ck CHECK (sal > 0),
comm NUMBER(7,2),
deptno NUMBER(2) CONSTRAINT emp_ref_dept_fk
REFERENCES dept(deptno)
);
--
-- Create the 'jobhist' table
--
CREATE TABLE jobhist (
empno NUMBER(4) NOT NULL,
startdate DATE NOT NULL,
enddate DATE,
job VARCHAR2(9),
sal NUMBER(7,2),
comm NUMBER(7,2),
deptno NUMBER(2),
chgdesc VARCHAR2(80),
CONSTRAINT jobhist_pk PRIMARY KEY (empno, startdate),
CONSTRAINT jobhist_ref_emp_fk FOREIGN KEY (empno)
REFERENCES emp(empno) ON DELETE CASCADE,
CONSTRAINT jobhist_ref_dept_fk FOREIGN KEY (deptno)
REFERENCES dept (deptno) ON DELETE SET NULL,
CONSTRAINT jobhist_date_chk CHECK (startdate <= enddate)
);
--
-- Create the 'salesemp' view
--
CREATE OR REPLACE VIEW salesemp AS
SELECT empno, ename, hiredate, sal, comm FROM emp WHERE job = 'SALESMAN';
--
-- Sequence to generate values for function 'new_empno'.
--
CREATE SEQUENCE next_empno START WITH 8000 INCREMENT BY 1;
--
-- Issue PUBLIC grants
--
GRANT ALL ON emp TO PUBLIC;
GRANT ALL ON dept TO PUBLIC;
GRANT ALL ON jobhist TO PUBLIC;
GRANT ALL ON salesemp TO PUBLIC;
GRANT ALL ON next_empno TO PUBLIC;
--
-- Load the 'dept' table
--
INSERT INTO dept VALUES (10,'ACCOUNTING','NEW YORK');
INSERT INTO dept VALUES (20,'RESEARCH','DALLAS');
INSERT INTO dept VALUES (30,'SALES','CHICAGO');
INSERT INTO dept VALUES (40,'OPERATIONS','BOSTON');
--
-- Load the 'emp' table
--
INSERT INTO emp VALUES (7369,'SMITH','CLERK',7902,'17-DEC-80',800,NULL,20);
INSERT INTO emp VALUES (7499,'ALLEN','SALESMAN',7698,'20-FEB-81',1600,300,30);
INSERT INTO emp VALUES (7521,'WARD','SALESMAN',7698,'22-FEB-81',1250,500,30);
INSERT INTO emp VALUES (7566,'JONES','MANAGER',7839,'02-APR-81',2975,NULL,20);
INSERT INTO emp VALUES (7654,'MARTIN','SALESMAN',7698,'28-SEP-81',1250,1400,30);
INSERT INTO emp VALUES (7698,'BLAKE','MANAGER',7839,'01-MAY-81',2850,NULL,30);
INSERT INTO emp VALUES (7782,'CLARK','MANAGER',7839,'09-JUN-81',2450,NULL,10);
INSERT INTO emp VALUES (7788,'SCOTT','ANALYST',7566,'19-APR-87',3000,NULL,20);
INSERT INTO emp VALUES (7839,'KING','PRESIDENT',NULL,'17-NOV-81',5000,NULL,10);
INSERT INTO emp VALUES (7844,'TURNER','SALESMAN',7698,'08-SEP-81',1500,0,30);
INSERT INTO emp VALUES (7876,'ADAMS','CLERK',7788,'23-MAY-87',1100,NULL,20);
INSERT INTO emp VALUES (7900,'JAMES','CLERK',7698,'03-DEC-81',950,NULL,30);
INSERT INTO emp VALUES (7902,'FORD','ANALYST',7566,'03-DEC-81',3000,NULL,20);
INSERT INTO emp VALUES (7934,'MILLER','CLERK',7782,'23-JAN-82',1300,NULL,10);
--
-- Load the 'jobhist' table
--
INSERT INTO jobhist VALUES (7369,'17-DEC-80',NULL,'CLERK',800,NULL,20,'New Hire');
INSERT INTO jobhist VALUES (7499,'20-FEB-81',NULL,'SALESMAN',1600,300,30,'New Hire');
INSERT INTO jobhist VALUES (7521,'22-FEB-81',NULL,'SALESMAN',1250,500,30,'New Hire');
INSERT INTO jobhist VALUES (7566,'02-APR-81',NULL,'MANAGER',2975,NULL,20,'New Hire');
INSERT INTO jobhist VALUES (7654,'28-SEP-81',NULL,'SALESMAN',1250,1400,30,'New Hire');
INSERT INTO jobhist VALUES (7698,'01-MAY-81',NULL,'MANAGER',2850,NULL,30,'New Hire');
INSERT INTO jobhist VALUES (7782,'09-JUN-81',NULL,'MANAGER',2450,NULL,10,'New Hire');
INSERT INTO jobhist VALUES (7788,'19-APR-87','12-APR-88','CLERK',1000,NULL,20,'New Hire');
INSERT INTO jobhist VALUES (7788,'13-APR-88','04-MAY-89','CLERK',1040,NULL,20,'Raise');
INSERT INTO jobhist VALUES (7788,'05-MAY-90',NULL,'ANALYST',3000,NULL,20,'Promoted to Analyst');
INSERT INTO jobhist VALUES (7839,'17-NOV-81',NULL,'PRESIDENT',5000,NULL,10,'New Hire');
INSERT INTO jobhist VALUES (7844,'08-SEP-81',NULL,'SALESMAN',1500,0,30,'New Hire');
INSERT INTO jobhist VALUES (7876,'23-MAY-87',NULL,'CLERK',1100,NULL,20,'New Hire');
INSERT INTO jobhist VALUES (7900,'03-DEC-81','14-JAN-83','CLERK',950,NULL,10,'New Hire');
INSERT INTO jobhist VALUES (7900,'15-JAN-83',NULL,'CLERK',950,NULL,30,'Changed to Dept 30');
INSERT INTO jobhist VALUES (7902,'03-DEC-81',NULL,'ANALYST',3000,NULL,20,'New Hire');
INSERT INTO jobhist VALUES (7934,'23-JAN-82',NULL,'CLERK',1300,NULL,10,'New Hire');
--
-- Populate statistics table and view (pg_statistic/pg_stats)
--
ANALYZE dept;
ANALYZE emp;
ANALYZE jobhist;
--
-- Procedure that lists all employees' numbers and names
-- from the 'emp' table using a cursor.
--
CREATE OR REPLACE PROCEDURE list_emp
IS
v_empno NUMBER(4);
v_ename VARCHAR2(10);
CURSOR emp_cur IS
SELECT empno, ename FROM emp ORDER BY empno;
BEGIN
OPEN emp_cur;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH emp_cur INTO v_empno, v_ename;
EXIT WHEN emp_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_ename);
END LOOP;
CLOSE emp_cur;
END;
/
--
-- Procedure that selects an employee row given the employee
-- number and displays certain columns.
--
CREATE OR REPLACE PROCEDURE select_emp (
p_empno IN NUMBER
)
IS
v_ename emp.ename%TYPE;
v_hiredate emp.hiredate%TYPE;
v_sal emp.sal%TYPE;
v_comm emp.comm%TYPE;
v_dname dept.dname%TYPE;
v_disp_date VARCHAR2(10);
BEGIN
SELECT ename, hiredate, sal, NVL(comm, 0), dname
INTO v_ename, v_hiredate, v_sal, v_comm, v_dname
FROM emp e, dept d
WHERE empno = p_empno
AND e.deptno = d.deptno;
v_disp_date := TO_CHAR(v_hiredate, 'MM/DD/YYYY');
DBMS_OUTPUT.PUT_LINE('Number : ' || p_empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || v_ename);
DBMS_OUTPUT.PUT_LINE('Hire Date : ' || v_disp_date);
DBMS_OUTPUT.PUT_LINE('Salary : ' || v_sal);
DBMS_OUTPUT.PUT_LINE('Commission: ' || v_comm);
DBMS_OUTPUT.PUT_LINE('Department: ' || v_dname);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Employee ' || p_empno || ' not found');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('The following is SQLERRM:');
DBMS_OUTPUT.PUT_LINE(SQLERRM);
DBMS_OUTPUT.PUT_LINE('The following is SQLCODE:');
DBMS_OUTPUT.PUT_LINE(SQLCODE);
END;
/
--
-- Procedure that queries the 'emp' table based on
-- department number and employee number or name. Returns
-- employee number and name as IN OUT parameters and job,
-- hire date, and salary as OUT parameters.
--
CREATE OR REPLACE PROCEDURE emp_query (
p_deptno IN NUMBER,
p_empno IN OUT NUMBER,
p_ename IN OUT VARCHAR2,
p_job OUT VARCHAR2,
p_hiredate OUT DATE,
p_sal OUT NUMBER
)
IS
BEGIN
SELECT empno, ename, job, hiredate, sal
INTO p_empno, p_ename, p_job, p_hiredate, p_sal
FROM emp
WHERE deptno = p_deptno
AND (empno = p_empno
OR ename = UPPER(p_ename));
END;
/
--
-- Procedure to call 'emp_query_caller' with IN and IN OUT
-- parameters. Displays the results received from IN OUT and
-- OUT parameters.
--
CREATE OR REPLACE PROCEDURE emp_query_caller
IS
v_deptno NUMBER(2);
v_empno NUMBER(4);
v_ename VARCHAR2(10);
v_job VARCHAR2(9);
v_hiredate DATE;
v_sal NUMBER;
BEGIN
v_deptno := 30;
v_empno := 0;
v_ename := 'Martin';
emp_query(v_deptno, v_empno, v_ename, v_job, v_hiredate, v_sal);
DBMS_OUTPUT.PUT_LINE('Department : ' || v_deptno);
DBMS_OUTPUT.PUT_LINE('Employee No: ' || v_empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || v_ename);
DBMS_OUTPUT.PUT_LINE('Job : ' || v_job);
DBMS_OUTPUT.PUT_LINE('Hire Date : ' || v_hiredate);
DBMS_OUTPUT.PUT_LINE('Salary : ' || v_sal);
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('More than one employee was selected');
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No employees were selected');
END;
/
--
-- Function to compute yearly compensation based on semimonthly
-- salary.
--
CREATE OR REPLACE FUNCTION emp_comp (
p_sal NUMBER,
p_comm NUMBER
) RETURN NUMBER
IS
BEGIN
RETURN (p_sal + NVL(p_comm, 0)) * 24;
END;
/
--
-- Function that gets the next number from sequence, 'next_empno',
-- and ensures it is not already in use as an employee number.
--
CREATE OR REPLACE FUNCTION new_empno RETURN NUMBER
IS
v_cnt INTEGER := 1;
v_new_empno NUMBER;
BEGIN
WHILE v_cnt > 0 LOOP
SELECT next_empno.nextval INTO v_new_empno FROM dual;
SELECT COUNT(*) INTO v_cnt FROM emp WHERE empno = v_new_empno;
END LOOP;
RETURN v_new_empno;
END;
/
--
-- EDB-SPL function that adds a new clerk to table 'emp'. This function
-- uses package 'emp_admin'.
--
CREATE OR REPLACE FUNCTION hire_clerk (
p_ename VARCHAR2,
p_deptno NUMBER
) RETURN NUMBER
IS
v_empno NUMBER(4);
v_ename VARCHAR2(10);
v_job VARCHAR2(9);
v_mgr NUMBER(4);
v_hiredate DATE;
v_sal NUMBER(7,2);
v_comm NUMBER(7,2);
v_deptno NUMBER(2);
BEGIN
v_empno := new_empno;
INSERT INTO emp VALUES (v_empno, p_ename, 'CLERK', 7782,
TRUNC(SYSDATE), 950.00, NULL, p_deptno);
SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno INTO
v_empno, v_ename, v_job, v_mgr, v_hiredate, v_sal, v_comm, v_deptno
FROM emp WHERE empno = v_empno;
DBMS_OUTPUT.PUT_LINE('Department : ' || v_deptno);
DBMS_OUTPUT.PUT_LINE('Employee No: ' || v_empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || v_ename);
DBMS_OUTPUT.PUT_LINE('Job : ' || v_job);
DBMS_OUTPUT.PUT_LINE('Manager : ' || v_mgr);
DBMS_OUTPUT.PUT_LINE('Hire Date : ' || v_hiredate);
DBMS_OUTPUT.PUT_LINE('Salary : ' || v_sal);
DBMS_OUTPUT.PUT_LINE('Commission : ' || v_comm);
RETURN v_empno;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('The following is SQLERRM:');
DBMS_OUTPUT.PUT_LINE(SQLERRM);
DBMS_OUTPUT.PUT_LINE('The following is SQLCODE:');
DBMS_OUTPUT.PUT_LINE(SQLCODE);
RETURN -1;
END;
/
--
-- PostgreSQL PL/pgSQL function that adds a new salesman
-- to table 'emp'.
--
CREATE OR REPLACE FUNCTION hire_salesman (
p_ename VARCHAR,
p_sal NUMERIC,
p_comm NUMERIC
) RETURNS NUMERIC
AS $$
DECLARE
v_empno NUMERIC(4);
v_ename VARCHAR(10);
v_job VARCHAR(9);
v_mgr NUMERIC(4);
v_hiredate DATE;
v_sal NUMERIC(7,2);
v_comm NUMERIC(7,2);
v_deptno NUMERIC(2);
BEGIN
v_empno := new_empno();
INSERT INTO emp VALUES (v_empno, p_ename, 'SALESMAN', 7698,
CURRENT_DATE, p_sal, p_comm, 30);
SELECT INTO
v_empno, v_ename, v_job, v_mgr, v_hiredate, v_sal, v_comm, v_deptno
empno, ename, job, mgr, hiredate, sal, comm, deptno
FROM emp WHERE empno = v_empno;
RAISE INFO 'Department : %', v_deptno;
RAISE INFO 'Employee No: %', v_empno;
RAISE INFO 'Name : %', v_ename;
RAISE INFO 'Job : %', v_job;
RAISE INFO 'Manager : %', v_mgr;
RAISE INFO 'Hire Date : %', v_hiredate;
RAISE INFO 'Salary : %', v_sal;
RAISE INFO 'Commission : %', v_comm;
RETURN v_empno;
EXCEPTION
WHEN OTHERS THEN
RAISE INFO 'The following is SQLERRM:';
RAISE INFO '%', SQLERRM;
RAISE INFO 'The following is SQLSTATE:';
RAISE INFO '%', SQLSTATE;
RETURN -1;
END;
$$ LANGUAGE 'plpgsql';
/
--
-- Rule to INSERT into view 'salesemp'
--
CREATE OR REPLACE RULE salesemp_i AS ON INSERT TO salesemp
DO INSTEAD
INSERT INTO emp VALUES (NEW.empno, NEW.ename, 'SALESMAN', 7698,
NEW.hiredate, NEW.sal, NEW.comm, 30);
--
-- Rule to UPDATE view 'salesemp'
--
CREATE OR REPLACE RULE salesemp_u AS ON UPDATE TO salesemp
DO INSTEAD
UPDATE emp SET empno = NEW.empno,
ename = NEW.ename,
hiredate = NEW.hiredate,
sal = NEW.sal,
comm = NEW.comm
WHERE empno = OLD.empno;
--
-- Rule to DELETE from view 'salesemp'
--
CREATE OR REPLACE RULE salesemp_d AS ON DELETE TO salesemp
DO INSTEAD
DELETE FROM emp WHERE empno = OLD.empno;
--
-- After statement-level trigger that displays a message after
-- an insert, update, or deletion to the 'emp' table. One message
-- per SQL command is displayed.
--
CREATE OR REPLACE TRIGGER user_audit_trig
AFTER INSERT OR UPDATE OR DELETE ON emp
DECLARE
v_action VARCHAR2(24);
BEGIN
IF INSERTING THEN
v_action := ' added employee(s) on ';
ELSIF UPDATING THEN
v_action := ' updated employee(s) on ';
ELSIF DELETING THEN
v_action := ' deleted employee(s) on ';
END IF;
DBMS_OUTPUT.PUT_LINE('User ' || USER || v_action || TO_CHAR(SYSDATE,'YYYY-MM-DD'));
END;
/
--
-- Before row-level trigger that displays employee number and
-- salary of an employee that is about to be added, updated,
-- or deleted in the 'emp' table.
--
CREATE OR REPLACE TRIGGER emp_sal_trig
BEFORE DELETE OR INSERT OR UPDATE ON emp
FOR EACH ROW
DECLARE
sal_diff NUMBER;
BEGIN
IF INSERTING THEN
DBMS_OUTPUT.PUT_LINE('Inserting employee ' || :NEW.empno);
DBMS_OUTPUT.PUT_LINE('..New salary: ' || :NEW.sal);
END IF;
IF UPDATING THEN
sal_diff := :NEW.sal - :OLD.sal;
DBMS_OUTPUT.PUT_LINE('Updating employee ' || :OLD.empno);
DBMS_OUTPUT.PUT_LINE('..Old salary: ' || :OLD.sal);
DBMS_OUTPUT.PUT_LINE('..New salary: ' || :NEW.sal);
DBMS_OUTPUT.PUT_LINE('..Raise : ' || sal_diff);
END IF;
IF DELETING THEN
DBMS_OUTPUT.PUT_LINE('Deleting employee ' || :OLD.empno);
DBMS_OUTPUT.PUT_LINE('..Old salary: ' || :OLD.sal);
END IF;
END;
/
--
 
2.1.2 新しいテーブルを作成する
新しい表は、表名をすべての列名とその型とともに指定することによって作成されます。以下は、表を定義するために必要な最小限の情報を持つempサンプル表の簡略版です
CREATE TABLE emp (
empno NUMBER(4),
ename VARCHAR2(10),
job VARCHAR2(9),
mgr NUMBER(4),
hiredate DATE,
sal NUMBER(7,2),
comm NUMBER(7,2),
deptno NUMBER(2)
);
これを改行でPSQLに 入力することができますPSQLは、コマンドがセミコロンまで終了していないことを認識します。
空白(空白、タブ、改行など)は、 SQLコマンドで自由に使用できます。これは、上記とは異なる方法で、またはすべてを1行に並べてコマンドを入力できることを意味します。 2つのダッシュ( " - " )はコメントを導入します。それに続くものは、行末まで無視されます。 SQLでは 、キーワードと識別子については大文字と小文字が区別されません。大文字と小文字を区別するために二重引用符が使用されている場合は例外です。
VARCHAR2(10)は、最大10文字の任意の文字列を格納できるデータ型を指定します。 NUMBER(7,2)は、精度7と位取り2の固定小数点数です.NUMBER (4)は、精度4と位取り0の整数です。
Advanced Serverは、通常のSQLデータ型INTEGERSMALLINTNUMBERREALDOUBLE PRECISIONCHARVARCHAR2DATE 、およびTIMESTAMP 、およびこれらのタイプのさまざまな同義語をサポートしています
テーブルをもう必要としない場合や、別の方法でテーブルを再作成したい場合は、次のコマンドを使用して削除することができます。
DROP TABLE tablename ;
 
2.1.3 表に行を移入する
INSERT文は行を持つ表を移入するために使用されます。
INSERT INTO emp VALUES (7369,'SMITH','CLERK',7902,'17-DEC-80',800,NULL,20);
すべてのデータ型はかなり明白な入力形式を使用することに注意してください。単純な数値ではない定数は、通常 、この例のように一重引用符( ' )で囲む必要がありますDATE型は実際には受け入れられるものにかなり柔軟ですが、このチュートリアルではここに示す明確な形式に固執します。
これまで使用されていた構文では、列の順序を覚えておく必要があります。別の構文では、列を明示的に一覧表示できます。
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno)
VALUES (7499,'ALLEN','SALESMAN',7698,'20-FEB-81',1600,300,30);
手数料が不明な場合など、いくつかの列を希望または省略する場合は、列の順序を変えることができます。
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,deptno)
VALUES (7369,'SMITH','CLERK',7902,'17-DEC-80',800,20);
多くの開発者は、暗黙的に順序に依存するよりも、列を明示的に優れたスタイルで表示することを検討しています。
 
2.1.4 テーブルのクエリ
テーブルからデータを取得するには、テーブルが 照会されます。これを行うには、 SQL SELECT文が使用されます。この文は、選択リスト(返される列をリストする部分)、表リスト(データを取り出す表をリストする部分)、およびオプションの修飾(制限を指定する部分)に分かれています。 。次の問合せでは、表内のすべての従業員のすべての列が特定の順序でリストされます。
SELECT * FROM emp;
ここで、選択リストの「*」はすべての列を意味します。このクエリの出力は次のとおりです。
empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+--------+-----------+------+--------------------+---------+---------+--------
7369 | SMITH | CLERK | 7902 | 17-DEC-80 00:00:00 | 800.00 | | 20
7499 | ALLEN | SALESMAN | 7698 | 20-FEB-81 00:00:00 | 1600.00 | 300.00 | 30
7521 | WARD | SALESMAN | 7698 | 22-FEB-81 00:00:00 | 1250.00 | 500.00 | 30
7566 | JONES | MANAGER | 7839 | 02-APR-81 00:00:00 | 2975.00 | | 20
7654 | MARTIN | SALESMAN | 7698 | 28-SEP-81 00:00:00 | 1250.00 | 1400.00 | 30
7698 | BLAKE | MANAGER | 7839 | 01-MAY-81 00:00:00 | 2850.00 | | 30
7782 | CLARK | MANAGER | 7839 | 09-JUN-81 00:00:00 | 2450.00 | | 10
7788 | SCOTT | ANALYST | 7566 | 19-APR-87 00:00:00 | 3000.00 | | 20
7839 | KING | PRESIDENT | | 17-NOV-81 00:00:00 | 5000.00 | | 10
7844 | TURNER | SALESMAN | 7698 | 08-SEP-81 00:00:00 | 1500.00 | 0.00 | 30
7876 | ADAMS | CLERK | 7788 | 23-MAY-87 00:00:00 | 1100.00 | | 20
7900 | JAMES | CLERK | 7698 | 03-DEC-81 00:00:00 | 950.00 | | 30
7902 | FORD | ANALYST | 7566 | 03-DEC-81 00:00:00 | 3000.00 | | 20
7934 | MILLER | CLERK | 7782 | 23-JAN-82 00:00:00 | 1300.00 | | 10
(14 rows)
選択リストに任意の式を指定できます。たとえば、次のようにすることができます。
SELECT ename, sal, sal * 24 AS yearly_salary, deptno FROM emp;
 
ename | sal | yearly_salary | deptno
--------+---------+---------------+--------
SMITH | 800.00 | 19200.00 | 20
ALLEN | 1600.00 | 38400.00 | 30
WARD | 1250.00 | 30000.00 | 30
JONES | 2975.00 | 71400.00 | 20
MARTIN | 1250.00 | 30000.00 | 30
BLAKE | 2850.00 | 68400.00 | 30
CLARK | 2450.00 | 58800.00 | 10
SCOTT | 3000.00 | 72000.00 | 20
KING | 5000.00 | 120000.00 | 10
TURNER | 1500.00 | 36000.00 | 30
ADAMS | 1100.00 | 26400.00 | 20
JAMES | 950.00 | 22800.00 | 30
FORD | 3000.00 | 72000.00 | 20
MILLER | 1300.00 | 31200.00 | 10
(14 rows)
AS句を使用して出力列のラベルを変更する方法に注目してください 。 ( AS句はオプションです)。
問合せは、どの行が必要かを指定する WHERE句を追加することで修飾できますWHERE句にはブール(真理値)式が含まれ、ブール式が真である行のみが返されます。通常のブール演算子( ANDOR 、およびNOT )は、修飾で使用できます。たとえば、次の例では、部門20の従業員を$ 1000.00以上の給与で取得します。
SELECT ename, sal, deptno FROM emp WHERE deptno = 20 AND sal > 1000;
 
ename | sal | deptno
-------+---------+--------
JONES | 2975.00 | 20
SCOTT | 3000.00 | 20
ADAMS | 1100.00 | 20
FORD | 3000.00 | 20
(4 rows)
問合せの結果がソート順に返されるように要求できます。
SELECT ename, sal, deptno FROM emp ORDER BY ename;
 
ename | sal | deptno
--------+---------+--------
ADAMS | 1100.00 | 20
ALLEN | 1600.00 | 30
BLAKE | 2850.00 | 30
CLARK | 2450.00 | 10
FORD | 3000.00 | 20
JAMES | 950.00 | 30
JONES | 2975.00 | 20
KING | 5000.00 | 10
MARTIN | 1250.00 | 30
MILLER | 1300.00 | 10
SCOTT | 3000.00 | 20
SMITH | 800.00 | 20
TURNER | 1500.00 | 30
WARD | 1250.00 | 30
(14 rows)
クエリの結果から重複する行を削除するように要求できます。
SELECT DISTINCT job FROM emp;
 
job
-----------
ANALYST
CLERK
MANAGER
PRESIDENT
SALESMAN
(5 rows)
次のセクションでは、1つのクエリで複数のテーブルから行を取得する方法を示します。
 
2.1.5 テーブル間のジョイン
これまでのところ、クエリは一度に1つのテーブルにしかアクセスしていませんでした。クエリは、一度に複数のテーブルにアクセスすることも、同じテーブルに複数の行が同時に処理されるようにアクセスすることもできます。一度に同じまたは異なるテーブルの複数の行にアクセス するクエリを結合クエリといいます。たとえば、すべての従業員レコードを関連部門の名前と場所とともに一覧表示するとします。これを行うには、 emp表の各行のdeptno列とdept表のすべての行のdeptno列を比較し、これらの値が一致する行のペアを選択する必要があります。これは、次のクエリによって実行されます。
SELECT emp.ename, emp.sal, dept.deptno, dept.dname, dept.loc FROM emp, dept WHERE emp.deptno = dept.deptno;
 
ename | sal | deptno | dname | loc
--------+---------+--------+------------+----------
MILLER | 1300.00 | 10 | ACCOUNTING | NEW YORK
CLARK | 2450.00 | 10 | ACCOUNTING | NEW YORK
KING | 5000.00 | 10 | ACCOUNTING | NEW YORK
SCOTT | 3000.00 | 20 | RESEARCH | DALLAS
JONES | 2975.00 | 20 | RESEARCH | DALLAS
SMITH | 800.00 | 20 | RESEARCH | DALLAS
ADAMS | 1100.00 | 20 | RESEARCH | DALLAS
FORD | 3000.00 | 20 | RESEARCH | DALLAS
WARD | 1250.00 | 30 | SALES | CHICAGO
TURNER | 1500.00 | 30 | SALES | CHICAGO
ALLEN | 1600.00 | 30 | SALES | CHICAGO
BLAKE | 2850.00 | 30 | SALES | CHICAGO
MARTIN | 1250.00 | 30 | SALES | CHICAGO
JAMES | 950.00 | 30 | SALES | CHICAGO
(14 rows)
結果セットについて2つのことを観察します。
部門40の結果行はありません。これは部門40の emp表に一致する項目がないためです 。そのため、結合はdept表の不一致行を無視します。まもなく、これがどのように修正されるかを見ていきます。
SELECT ename, sal, dept.deptno, dname, loc FROM emp, dept WHERE emp.deptno = dept.deptno;
すべての列は異なる名前(修飾されている必要があるdeptno除く )を持つため、パーサーはどの表に属しているかを自動的に検出しましたが、結合問合せで列名を完全修飾するのは適切な方法です。
これまでに見られた種類の結合クエリは、この代替形式でも記述できます。
SELECT emp.ename, emp.sal, dept.deptno, dept.dname, dept.loc FROM emp INNER JOIN dept ON emp.deptno = dept.deptno;
この構文は上記のように一般的に使用されていませんが、ここでは次のトピックを理解するのに役立ちます。
上記のすべての結合結果では、部門40に属する従業員は返されず、結果として部門40の記録は表示されません。ここでは、一致する従業員がいないにもかかわらず、結果に部門40レコードをどのように取得できるかを把握します。問合せでは、 deptをスキャンし、各行に対して一致するemp行を検索します。一致する行が見つからない場合は、 empテーブルの列の代わりに "空の"値を使用します。この種の問合せは外部結合と呼ばれます。 (これまで見てきた結合内部結合です。)コマンドは次のようになります。
SELECT emp.ename, emp.sal, dept.deptno, dept.dname, dept.loc FROM dept LEFT OUTER JOIN emp ON emp.deptno = dept.deptno;
 
ename | sal | deptno | dname | loc
--------+---------+--------+------------+----------
MILLER | 1300.00 | 10 | ACCOUNTING | NEW YORK
CLARK | 2450.00 | 10 | ACCOUNTING | NEW YORK
KING | 5000.00 | 10 | ACCOUNTING | NEW YORK
SCOTT | 3000.00 | 20 | RESEARCH | DALLAS
JONES | 2975.00 | 20 | RESEARCH | DALLAS
SMITH | 800.00 | 20 | RESEARCH | DALLAS
ADAMS | 1100.00 | 20 | RESEARCH | DALLAS
FORD | 3000.00 | 20 | RESEARCH | DALLAS
WARD | 1250.00 | 30 | SALES | CHICAGO
TURNER | 1500.00 | 30 | SALES | CHICAGO
ALLEN | 1600.00 | 30 | SALES | CHICAGO
BLAKE | 2850.00 | 30 | SALES | CHICAGO
MARTIN | 1250.00 | 30 | SALES | CHICAGO
JAMES | 950.00 | 30 | SALES | CHICAGO
| | 40 | OPERATIONS | BOSTON
(15 rows)
この問合せは、 左外部結合 と呼ばれます。これは、結合演算子の左側に記載されている表には、出力の各行が少なくとも1回は存在しますが、右側の表には、左のテーブル。右テーブルの一致がない左テーブルの行が選択された場合、右テーブルの列には空の( NULL )値が代入されます。
外部結合の別の構文は、 WHERE内の結合条件で外部結合演算子 "(+)"を使用することです。外部結合演算子は、一致しない行の代わりにNULL値を代入する必要がある表の列名の後に置かれます。したがって、 emp表に一致する行がないdept表のすべての行に対して、 Advanced Serverempの列を含む選択リスト式に対してnullを戻します。したがって、上記の例は次のように書き直すことができます。
SELECT emp.ename, emp.sal, dept.deptno, dept.dname, dept.loc FROM dept, emp WHERE emp.deptno(+) = dept.deptno;
 
ename | sal | deptno | dname | loc
--------+---------+--------+------------+----------
MILLER | 1300.00 | 10 | ACCOUNTING | NEW YORK
CLARK | 2450.00 | 10 | ACCOUNTING | NEW YORK
KING | 5000.00 | 10 | ACCOUNTING | NEW YORK
SCOTT | 3000.00 | 20 | RESEARCH | DALLAS
JONES | 2975.00 | 20 | RESEARCH | DALLAS
SMITH | 800.00 | 20 | RESEARCH | DALLAS
ADAMS | 1100.00 | 20 | RESEARCH | DALLAS
FORD | 3000.00 | 20 | RESEARCH | DALLAS
WARD | 1250.00 | 30 | SALES | CHICAGO
TURNER | 1500.00 | 30 | SALES | CHICAGO
ALLEN | 1600.00 | 30 | SALES | CHICAGO
BLAKE | 2850.00 | 30 | SALES | CHICAGO
MARTIN | 1250.00 | 30 | SALES | CHICAGO
JAMES | 950.00 | 30 | SALES | CHICAGO
| | 40 | OPERATIONS | BOSTON
(15 rows)
我々はまた、それ自体に対してテーブルに参加することもできます。これは 自己結合 と呼ばれます。例として、各従業員の名前とその従業員のマネージャの名前を検索したいとします。したがって、各emp行のmgr列と他のすべてのemp行のempno列を比較する必要があります。
SELECT e1.ename || ' works for ' || e2.ename AS "Employees and their Managers" FROM emp e1, emp e2 WHERE e1.mgr = e2.empno;
 
Employees and their Managers
------------------------------
FORD works for JONES
SCOTT works for JONES
WARD works for BLAKE
TURNER works for BLAKE
MARTIN works for BLAKE
JAMES works for BLAKE
ALLEN works for BLAKE
MILLER works for CLARK
ADAMS works for SCOTT
CLARK works for KING
BLAKE works for KING
JONES works for KING
SMITH works for FORD
(13 rows)
ここでは、 emp表は選択リストおよび結合条件の従業員行を表すe1 、および選択リストおよび結合条件のマネージャとして機能する一致する従業員行を表すe2として再ラベル付けされています。次のように、これらのエイリアスを他のクエリで使用して入力を節約できます。
SELECT e.ename, e.mgr, d.deptno, d.dname, d.loc FROM emp e, dept d WHERE e.deptno = d.deptno;
 
ename | mgr | deptno | dname | loc
--------+------+--------+------------+----------
MILLER | 7782 | 10 | ACCOUNTING | NEW YORK
CLARK | 7839 | 10 | ACCOUNTING | NEW YORK
KING | | 10 | ACCOUNTING | NEW YORK
SCOTT | 7566 | 20 | RESEARCH | DALLAS
JONES | 7839 | 20 | RESEARCH | DALLAS
SMITH | 7902 | 20 | RESEARCH | DALLAS
ADAMS | 7788 | 20 | RESEARCH | DALLAS
FORD | 7566 | 20 | RESEARCH | DALLAS
WARD | 7698 | 30 | SALES | CHICAGO
TURNER | 7698 | 30 | SALES | CHICAGO
ALLEN | 7698 | 30 | SALES | CHICAGO
BLAKE | 7839 | 30 | SALES | CHICAGO
MARTIN | 7698 | 30 | SALES | CHICAGO
JAMES | 7698 | 30 | SALES | CHICAGO
(14 rows)
このような簡略化のスタイルは非常に頻繁に遭遇するでしょう。
 
2.1.6 集計関数
他のほとんどのリレーショナルデータベース製品と同様に、 Advanced Serverは集合関数をサポートしています。集合関数は、複数の入力行から単一の結果を計算します。たとえば、一連の行に対してCOUNTSUMAVG (平均)、 MAX (最大)、 MIN (最小)を計算する集計があります。
一例として、最高給与と最低給与は次のクエリで確認できます。
SELECT MAX(sal) highest_salary, MIN(sal) lowest_salary FROM emp;
 
highest_salary | lowest_salary
----------------+---------------
5000.00 | 800.00
(1 row)
最大の給与を持つ従業員を見つけたい場合は、次のように試してみるとよいでしょう:
SELECT ename FROM emp WHERE sal = MAX(sal);
 
ERROR: aggregates not allowed in WHERE clause
集計関数 MAXWHERE節で使用できないため、これは機能しませんWHERE句は集計ステージに入る行を決定し、集計関数が計算される前に評価される必要があるため、この制限があります。ただし、 サブクエリを使用して目的の結果を達成するために、クエリを再作成することができます。
SELECT ename FROM emp WHERE sal = (SELECT MAX(sal) FROM emp);
 
ename
-------
KING
(1 row)
副問合せは、外部問合せとは別に独自の結果を取得する独立した計算です。
集約は、 GROUP BYと組み合わせても非常に便利です 。たとえば、次の問合せでは、各部門で最高の給与が得られます。
SELECT deptno, MAX(sal) FROM emp GROUP BY deptno;
 
deptno | max
--------+---------
10 | 5000.00
20 | 3000.00
30 | 2850.00
(3 rows)
このクエリは部門ごとに1つの出力行を生成します。各集計結果は、その部門に一致する行に対して計算されます。これらのグループ化された行は、 HAVINGを使用してフィルタリングできます
SELECT deptno, MAX(sal) FROM emp GROUP BY deptno HAVING AVG(sal) > 2000;
 
deptno | max
--------+---------
10 | 5000.00
20 | 3000.00
(2 rows)
このクエリは、2000を超える平均給与を持つ部門についてのみ同じ結果を示します。
最後に、次のクエリでは、各部門のアナリストである最高給与従業員のみが考慮されます。
SELECT deptno, MAX(sal) FROM emp WHERE job = 'ANALYST' GROUP BY deptno HAVING AVG(sal) > 2000;
 
deptno | max
--------+---------
20 | 3000.00
(1 row)
WHERE句とHAVING句の間には微妙な違いがあります。 WHERE句は、グループ化が発生し、集約関数が適用される前に行をフィルタリングします。 HAVING句は、行がグループ化され、各グループに対して集計関数が計算された後の結果にフィルタを適用します。
したがって、前の例では、アナリストである従業員だけが考慮されています。このサブセットから、従業員は部門別にグループ化され、グループ内のアナリストの平均給与が2000を超えるグループのみが最終結果になります。これは部門20のグループのみに該当し、部門20の最大アナリスト給与は3000.00です。
 
2.1.7 アップデート
既存の行の列値は、 UPDATEコマンドを使用して変更できます 。たとえば、次のコマンドシーケンスは、マネージャである全員に10%のレイズを与える前後の結果を示しています。
SELECT ename, sal FROM emp WHERE job = 'MANAGER';
 
ename | sal
-------+---------
JONES | 2975.00
BLAKE | 2850.00
CLARK | 2450.00
(3 rows)
 
UPDATE emp SET sal = sal * 1.1 WHERE job = 'MANAGER';
 
SELECT ename, sal FROM emp WHERE job = 'MANAGER';
 
ename | sal
-------+---------
JONES | 3272.50
BLAKE | 3135.00
CLARK | 2695.00
(3 rows)
 
2.1.8 削除
行は、 DELETEコマンドを使用して表から除去することができます 。たとえば、次のコマンドシーケンスは、部門20のすべての従業員を削除する前後の結果を示しています。
SELECT ename, deptno FROM emp;
 
ename | deptno
--------+--------
SMITH | 20
ALLEN | 30
WARD | 30
JONES | 20
MARTIN | 30
BLAKE | 30
CLARK | 10
SCOTT | 20
KING | 10
TURNER | 30
ADAMS | 20
JAMES | 30
FORD | 20
MILLER | 10
(14 rows)
 
DELETE FROM emp WHERE deptno = 20;
 
SELECT ename, deptno FROM emp;
ename | deptno
--------+--------
ALLEN | 30
WARD | 30
MARTIN | 30
BLAKE | 30
CLARK | 10
KING | 10
TURNER | 30
JAMES | 30
MILLER | 10
(9 rows)
次のようなWHERE句を指定せずにDELETEコマンドを実行することには十分注意してください
DELETE FROM tablename ;
このステートメントは、指定されたテーブルからすべての行を削除し、完全に空にします。これを行う前に、システムは確認を要求しません。
2.1.9 SQL言語
Advanced Serverは、Oracle構文と互換性のあるSQL言語、拡張機能(Oracleとのデータベース互換性を提供しない機能、またはOracleスタイルのアプリケーションをサポートする機能)のための構文およびコマンドをサポートします。
「Oracle Database開発者ガイド」のデータベース互換性をサポートする「リファレンス・ガイド」には、次の詳細情報が記載されています。
互換性のあるSQL構文および言語要素
サポートされている SQLコマンド構文
リファレンスガイドのコピーを確認するには、次のAdvanced ServerのWebサイトを参照してください。
https://www.enterprisedb.com/resources/product-documentation
2.2 高度な概念
前のセクションでは、 SQL使用してAdvanced Serverでデータを保存およびアクセスするための基本について説明しました 。このセクションでは、管理を簡素化し、データの損失や破損を防ぐより高度なSQL機能について説明します。
2.2.1 ビュー
次の SELECTコマンドを考えてみましょう
SELECT ename, sal, sal * 24 AS yearly_salary, deptno FROM emp;
 
ename | sal | yearly_salary | deptno
--------+---------+---------------+--------
SMITH | 800.00 | 19200.00 | 20
ALLEN | 1600.00 | 38400.00 | 30
WARD | 1250.00 | 30000.00 | 30
JONES | 2975.00 | 71400.00 | 20
MARTIN | 1250.00 | 30000.00 | 30
BLAKE | 2850.00 | 68400.00 | 30
CLARK | 2450.00 | 58800.00 | 10
SCOTT | 3000.00 | 72000.00 | 20
KING | 5000.00 | 120000.00 | 10
TURNER | 1500.00 | 36000.00 | 30
ADAMS | 1100.00 | 26400.00 | 20
JAMES | 950.00 | 22800.00 | 30
FORD | 3000.00 | 72000.00 | 20
MILLER | 1300.00 | 31200.00 | 10
(14 rows)
これが繰り返し使用されるクエリの場合、毎回SELECTコマンド全体を再入力せずにこのクエリを再利用するという簡単な方法は、以下に示すようなビューを作成することです。
CREATE VIEW employee_pay AS SELECT ename, sal, sal * 24 AS yearly_salary, deptno FROM emp;
ビュー名 employee_payを通常のテーブル名のように使用してクエリを実行できるようになりました。
SELECT * FROM employee_pay;
 
ename | sal | yearly_salary | deptno
--------+---------+---------------+--------
SMITH | 800.00 | 19200.00 | 20
ALLEN | 1600.00 | 38400.00 | 30
WARD | 1250.00 | 30000.00 | 30
JONES | 2975.00 | 71400.00 | 20
MARTIN | 1250.00 | 30000.00 | 30
BLAKE | 2850.00 | 68400.00 | 30
CLARK | 2450.00 | 58800.00 | 10
SCOTT | 3000.00 | 72000.00 | 20
KING | 5000.00 | 120000.00 | 10
TURNER | 1500.00 | 36000.00 | 30
ADAMS | 1100.00 | 26400.00 | 20
JAMES | 950.00 | 22800.00 | 30
FORD | 3000.00 | 72000.00 | 20
MILLER | 1300.00 | 31200.00 | 10
(14 rows)
ビューの自由な使用は、優れた SQLデータベース設計の重要な側面です 。ビューは、テーブルの構造の詳細をカプセル化し、アプリケーションが進化するにつれて変化する一貫したインタフェースを提供します。
ビューは、実際のテーブルを使用できるほぼすべての場所で使用できます。他のビューにビューを構築することは珍しいことではありません。
 
2.2.2 外部キー
すべての従業員が有効な部門に所属していることを確認したいとします。これは 、データの参照整合性維持と呼ばれます。シンプルなデータベースシステムでは、まず、 deptテーブルを調べて、一致するレコードが存在するかどうかを確認し、新しい従業員レコードを挿入または拒否します。このアプローチは多くの問題を有し、非常に不便である。 Advanced Serverを使用すると、より簡単に使用できます。
セクション2.1.2に示されている empテーブルの変更されたバージョンが、このセクションでは、外部キー制約の追加とともに示されています。変更されたempテーブルは、次のようになります。
CREATE TABLE emp (
empno NUMBER(4) NOT NULL CONSTRAINT emp_pk PRIMARY KEY,
ename VARCHAR2(10),
job VARCHAR2(9),
mgr NUMBER(4),
hiredate DATE,
sal NUMBER(7,2),
comm NUMBER(7,2),
deptno NUMBER(2) CONSTRAINT emp_ref_dept_fk
REFERENCES dept(deptno)
);
サンプルemp表で次の INSERTコマンドを発行しようとすると 、外部キー制約emp_ref_dept_fkによって部門50dept表に確実に存在します。そうしないので、コマンドは拒否されます。
INSERT INTO emp VALUES (8000,'JONES','CLERK',7902,'17-AUG-07',1200,NULL,50);
 
ERROR: insert or update on table "emp" violates foreign key constraint "emp_ref_dept_fk"
DETAIL: Key (deptno)=(50) is not present in table "dept".
外部キーの動作は、アプリケーションに細かく調整できます。外部キーを正しく使用することで、データベースアプリケーションの品質が確実に向上するため、詳細について学ぶことを強くお勧めします。
 
2.2.3 ROWNUM疑似カラム
ROWNUMは、疑似列であり、問​​合せから行が検索された順序に基づいて、各行に対して増分の一意の整数値が割り当てられます。したがって、最初に検索される行のROWNUM1になります。 2行目はROWNUM2のようになります。
この機能を使用すると、クエリによって取得された行数を制限できます。これは、次の例で示されます。
SELECT empno, ename, job FROM emp WHERE ROWNUM < 5;
 
empno | ename | job
-------+-------+----------
7369 | SMITH | CLERK
7499 | ALLEN | SALESMAN
7521 | WARD | SALESMAN
7566 | JONES | MANAGER
(4 rows)
結果セットの任意の並べ替えが行われる前にROWNUM値は、各列に割り当てられています。したがって、結果セットはORDER BY句で指定された順序で返されますが、 ROWNUM値は必ずしも昇順である必要はありません。
SELECT ROWNUM, empno, ename, job FROM emp WHERE ROWNUM < 5 ORDER BY ename;
 
rownum | empno | ename | job
--------+-------+-------+----------
2 | 7499 | ALLEN | SALESMAN
4 | 7566 | JONES | MANAGER
1 | 7369 | SMITH | CLERK
3 | 7521 | WARD | SALESMAN
(4 rows)
次の例は、 jobhistテーブルのすべての行にシーケンス番号を追加する方法を示して ます。まず、 seqnoという名前の新しい列がテーブルに追加され、 seqnoUPDATEコマンドのROWNUMに設定されます。
ALTER TABLE jobhist ADD seqno NUMBER(3);
UPDATE jobhist SET seqno = ROWNUM;
次の SELECTコマンドは、新しいseqno値を表示します。
SELECT seqno, empno, TO_CHAR(startdate,'DD-MON-YY') AS start, job FROM jobhist;
 
seqno | empno | start | job
-------+-------+-----------+-----------
1 | 7369 | 17-DEC-80 | CLERK
2 | 7499 | 20-FEB-81 | SALESMAN
3 | 7521 | 22-FEB-81 | SALESMAN
4 | 7566 | 02-APR-81 | MANAGER
5 | 7654 | 28-SEP-81 | SALESMAN
6 | 7698 | 01-MAY-81 | MANAGER
7 | 7782 | 09-JUN-81 | MANAGER
8 | 7788 | 19-APR-87 | CLERK
9 | 7788 | 13-APR-88 | CLERK
10 | 7788 | 05-MAY-90 | ANALYST
11 | 7839 | 17-NOV-81 | PRESIDENT
12 | 7844 | 08-SEP-81 | SALESMAN
13 | 7876 | 23-MAY-87 | CLERK
14 | 7900 | 03-DEC-81 | CLERK
15 | 7900 | 15-JAN-83 | CLERK
16 | 7902 | 03-DEC-81 | ANALYST
17 | 7934 | 23-JAN-82 | CLERK
(17 rows)
 
2.2.4 類義語
同義語は、SQLステートメント内の別のデータベース・オブジェクトを参照するために使用することができる識別子です。シノニムは、通常、データベース・オブジェクトがSQL文で適切に参照されるようにスキーマ名による完全修飾を必要とする場合に役立ちます 。そのオブジェクトに定義された同義語は、単一の修飾されていない名前への参照を簡素化します。
Advanced Serverは以下の同義語をサポートしています。
シノニムを作成する時点で、参照されているスキーマまたは参照されたオブジェクトが存在していないこと。シノニムは、存在しないオブジェクトまたはスキーマを参照することがあります。参照されたオブジェクトまたはスキーマを削除すると、同義語は無効になります。シノニムを明示的に削除して削除する必要があります。
その他のスキーマ・オブジェクトと同様に、Advanced Serverは検索パスを使用して修飾されていない同義語名を解決します。同じ名前のシノニムが2つある場合、シノニムへの修飾されていない参照は、検索パスで指定された名前の最初のシノニムに解決されます。場合は 、パブリックが検索パスにある、あなたはその名を修飾することなく、そのスキーマ内のシノニムを参照することができます。
Advanced ServerがSQLコマンドを実行すると、現在のユーザーの権限がシノニムの基礎となるデータベース・オブジェクトと照合されます。ユーザーにそのオブジェクトに対する適切な権限がない場合、SQLコマンドは失敗します。
シノニムの作成
シノニムを作成するには、 CREATE SYNONYMコマンドを使用します。構文は次のとおりです。
CREATE [OR REPLACE] [PUBLIC] SYNONYM [ スキーマ 。] syn _ name
FOR
オブジェクト _ スキーマ オブジェクト _ 名前 [ @dblink_name ];
 
 
パラメーター:
syn_name
syn_nameは同義語の名前です。シノニム名は、スキーマ内で一意でなければなりません。
スキーマ
schemaは、シノニムが存在するスキーマの名前を指定します。スキーマ名を指定しない場合、シノニムは検索パスの最初の既存スキーマに作成されます。
オブジェクト名
object_nameは、オブジェクトの名前を指定します。
object_schema
object_schemaは、オブジェクトが存在するスキーマの名前を指定します。
dblink_name
dblink_name は、ターゲットオブジェクトにアクセスするためのデータベースリンクの名前を指定します。
既存の同義語定義を新しい同義語定義に置き換えるには REPLACE句を含めます
パブリック・スキーマにシノニムを作成するには PUBLIC句を含めます。 Oracleデータベースと互換性のあるCREATE PUBLIC SYNONYMコマンドは、 パブリック・スキーマに存在するシノニムを作成します。
CREATE [OR REPLACE] PUBLIC SYNONYMの OBJECT_SCHEMA FOR シン _ object_name ;
これはちょっと書いた簡単な方法です:
CREATE [OR REPLACE] SYNONYM publicを作成します。 syn _ name FOR object_schema object_name ;
次の例ではenterprisedbを参照するpersonnelという名前の同義語を作成しますempテーブル。
CREATE SYNONYM personnel FOR enterprisedb.emp;
シノニムが CREATE SYNONYMコマンドでスキーマ修飾されていない場合、シノニムは検索パスの最初の既存スキーマに作成されます。次のコマンドを実行すると、検索パスを表示できます。
SHOW SEARCH_PATH;
 
search_path
-----------------------
development,accounting
(1 row)
 
この例では、 development という名前のスキーマが存在しない場合、synonymはaccountingという名前のスキーマに作成されます。
これで、 enterprisedbスキーマのemp表は、シノニム、 personnelを使用して、任意のSQL文( DDLまたはDML)で参照できます
INSERT INTO personnel VALUES (8142,'ANDERSON','CLERK',7902,'17-DEC-06',1300,NULL,20);
 
SELECT * FROM personnel;
 
empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+----------+-----------+------+--------------------+---------+---------+--------
7369 | SMITH | CLERK | 7902 | 17-DEC-80 00:00:00 | 800.00 | | 20
7499 | ALLEN | SALESMAN | 7698 | 20-FEB-81 00:00:00 | 1600.00 | 300.00 | 30
7521 | WARD | SALESMAN | 7698 | 22-FEB-81 00:00:00 | 1250.00 | 500.00 | 30
7566 | JONES | MANAGER | 7839 | 02-APR-81 00:00:00 | 2975.00 | | 20
7654 | MARTIN | SALESMAN | 7698 | 28-SEP-81 00:00:00 | 1250.00 | 1400.00 | 30
7698 | BLAKE | MANAGER | 7839 | 01-MAY-81 00:00:00 | 2850.00 | | 30
7782 | CLARK | MANAGER | 7839 | 09-JUN-81 00:00:00 | 2450.00 | | 10
7788 | SCOTT | ANALYST | 7566 | 19-APR-87 00:00:00 | 3000.00 | | 20
7839 | KING | PRESIDENT | | 17-NOV-81 00:00:00 | 5000.00 | | 10
7844 | TURNER | SALESMAN | 7698 | 08-SEP-81 00:00:00 | 1500.00 | 0.00 | 30
7876 | ADAMS | CLERK | 7788 | 23-MAY-87 00:00:00 | 1100.00 | | 20
7900 | JAMES | CLERK | 7698 | 03-DEC-81 00:00:00 | 950.00 | | 30
7902 | FORD | ANALYST | 7566 | 03-DEC-81 00:00:00 | 3000.00 | | 20
7934 | MILLER | CLERK | 7782 | 23-JAN-82 00:00:00 | 1300.00 | | 10
8142 | ANDERSON | CLERK | 7902 | 17-DEC-06 00:00:00 | 1300.00 | | 20
(15 rows)
 
シノニムの削除
シノニムを削除するには、 DROP SYNONYM コマンドを使用します。構文は次のとおりです。
DROP [PUBLIC] SYNONYM [ スキーマ 。] syn_name
パラメーター:
syn_name
syn_nameは同義語の名前です。シノニム名は、スキーマ内で一意でなければなりません。
スキーマ
schemaは、シノニムが存在するスキーマの名前を指定します。
スキーマ修飾が可能な他のオブジェクトと同様に、検索パスに同じ名前の2つの同義語がある場合があります。削除する同義語の名前を明確にするには、スキーマ名を含めます。シノニムが DROP SYNONYMコマンドでスキーマ修飾されていない場合、Advanced Serverは検索パスで見つかった同義語の最初のインスタンスを削除します。
必要に応じて、 PUBLIC句を追加して、 パブリック・スキーマにあるシノニムを削除できます。 Oracleデータベースとの互換性、 DROP PUBLIC SYNONYMコマンドは、 パブリック・スキーマに存在するシノニムを削除します。
DROP PUBLIC SYNONYM syn _ name ;
次の例では、同義語、低下 人員
DROP SYNONYM personnel;
 
2.2.5 階層問合せ
階層クエリは、親子関係を構成するデータに基づいて階層順に結果セットの行を返すクエリの種類です。階層は、典型的には、反転ツリー構造によって表される。ツリーは、相互接続されたノードで構成されています。各ノードは、1つまたは複数のノードに接続することができます。各ノードは、親を持たない上位ノードを除いて、1つのノードに接続されています。このノードはルートノードです。各ツリーにはちょうど1つのルートノードがあります。子を持たないノードはリーフノードと呼ばれます。ツリーには、少なくとも1つのリーフノードが常に存在します。たとえば、ツリーが1つのノードで構成されているという単純なケースです。この場合、ルートとリーフの両方です。
階層クエリでは、結果セットの行は1つ以上のツリーのノードを表します。
:指定された単一の行が複数のツリーに表示され、結果セットに複数回表示される可能性があります。
問合せの階層関係は、結果セットで行が戻される順序の基礎を形成するCONNECT BYによって記述されますCONNECT BY句とそれに関連するオプションの句がSELECTコマンドに現れるコンテキストを以下に示します。
SELECT select_list FROM table_expression [ WHERE ...]
[ START WITH start_expression ]
CONNECT BY { PRIOR parent_expr = child_expr |
child_expr = PRIOR parent_expr }
[ ORDER SIBLINGS BY column1 [ ASC | DESC ]
[, column2 [ ASC | DESC ] ] ...
[ GROUP BY ...]
[ HAVING ...]
[ other ...]
select_listは、結果セットのフィールドを構成する1つ以上の式です。 table_expressionは、結果セットの行の起点となる1つ以上の表またはビューです。 otherは、追加の法的なSELECTコマンド句です。次のセクションでは、階層問合せに関連するSTART WITHCONNECT BY 、およびORDER SIBLINGS BY節について説明します。
注意:現時点では、Advanced ServerはCONNECT BY句でのAND (または他の演算子)の使用をサポートしていません。
2.2.5.1 親子関係の定義
与えられた行に対して、その親とその子は CONNECT BYによって決定されます。 CONNECT BY句は、等号( = )演算子と比較して2つの式で構成する必要があります。さらに、これらの2つの式の1つの前にキーワードPRIORを付ける必要があります。
任意の行について、その子を決定する:
1。
指定された行のparent_expr評価する
2。
評価 table_expressionの評価から得られた他の任意の行にchild_expr
3。
場合 parent_expr = child_expr、この行は、所与の親の行の子ノードであります
4。
table_expressionの 残りのすべての行に対してこのプロセスを繰り返します。手順3の式を満たすすべての行は、指定された親行の子ノードです。
注意WHERE句をtable_expressionに適用する前に、 行が子ノードであるかどうかを判断する評価プロセスは、 table_expressionによって返されるすべての行で発生します。
前のステップで見つけられた各子ノードを親として扱うこのプロセスを反復して繰り返すことによって、ノードの反転ツリーが構築される。このプロセスは、子ノードの最終セットに独自の子がない場合に完了します。これらはリーフノードです。
CONNECT BY含むSELECTコマンドは、典型的には、START WITH含みます。 START WITH句は、ルート・ノードになる行、つまり前述のアルゴリズムが適用される最初の親ノードである行を決定します。これについては、次のセクションでさらに説明します。
2.2.5.2 ルートノードの選択
START WITHは、ルートノードとして使用されるtable_expressionによって選択された行(複数可)を決定するために使用されます。 start_expressionが評価table_expressionによって選択されたすべての行は、真のツリーのルートノードになるために。したがって、結果セット内の潜在的なツリーの数は、ルートノードの数に等しい。結果として、 START WITH句が省略されると、 table_expressionによって返されるすべての行は、それ自身のツリーのルートになります。
2.2.5.3 サンプルアプリケーションの組織ツリー
サンプル・アプリケーションのemp表を検討してくださいempテーブルの行は、従業員のマネージャの従業員番号を含むmgr列に基づいた階層を形成します。各従業員にはマネージャが最大で1人しかいません。 KINGは会社の社長であり、マネージャーがいないので、KINGのmgr列はnullです。また、従業員が複数の従業員のマネージャーとして行動することも可能です。この関係は、以下に示すような典型的なツリー構造の階層的組織図を形成します。
図2従業員組織の階層
この関係に基づいて階層クエリを形成するために、 SELECTコマンドにはCONNECT BY PRIOR empno = mgrという節が含まれています 。たとえば、従業員番号7839の社長KINGがあれば、 mgr列が7839の従業員は、 JONESBLAKECLARK (これはKINGの子ノードです)に該当するKINGに直接報告します。同様に、従業員JONESの場合、 mgr列が7566の他の従業員はJONESの子ノードです。この例ではSCOTTFORDです。
組織図の一番上が KINGなので、このツリーにルートノードが1つあります。 START WITH mgr IS NULL句は、最初のルートノードとしてKINGのみを選択します。
完全な SELECTコマンドを以下に示します。
SELECT ename, empno, mgr
FROM emp
START WITH mgr IS NULL
CONNECT BY PRIOR empno = mgr;
クエリ出力の行は、ルートからリーフまでの各ブランチを、上から下、左から右の順に移動します。以下はこのクエリの出力です。
ename | empno | mgr
--------+-------+------
KING | 7839 |
JONES | 7566 | 7839
SCOTT | 7788 | 7566
ADAMS | 7876 | 7788
FORD | 7902 | 7566
SMITH | 7369 | 7902
BLAKE | 7698 | 7839
ALLEN | 7499 | 7698
WARD | 7521 | 7698
MARTIN | 7654 | 7698
TURNER | 7844 | 7698
JAMES | 7900 | 7698
CLARK | 7782 | 7839
MILLER | 7934 | 7782
(14 rows)
2.2.5.4 ノードレベル
LEVELは、疑似列で、 SELECTコマンドで列を表示できる場所であればどこでも使用できます。結果セットの各行について、 LEVELは、この行によって表されるノードの階層内の深度を指定する非ゼロの整数値を戻します。ルートノードのLEVELは、ルートノードの直接の子のためのレベルは 2のように、そして1です。
以下の照会は、 LEVEL疑似列を追加した前の照会の変更です 。さらに、 LEVEL値を使用して従業員名をインデントし、各行の階層の深さをさらに強調します。
SELECT LEVEL, LPAD (' ', 2 * (LEVEL - 1)) || ename "employee", empno, mgr
FROM emp START WITH mgr IS NULL
CONNECT BY PRIOR empno = mgr;
このクエリの出力は次のとおりです。
level | employee | empno | mgr
-------+-------------+-------+------
1 | KING | 7839 |
2 | JONES | 7566 | 7839
3 | SCOTT | 7788 | 7566
4 | ADAMS | 7876 | 7788
3 | FORD | 7902 | 7566
4 | SMITH | 7369 | 7902
2 | BLAKE | 7698 | 7839
3 | ALLEN | 7499 | 7698
3 | WARD | 7521 | 7698
3 | MARTIN | 7654 | 7698
3 | TURNER | 7844 | 7698
3 | JAMES | 7900 | 7698
2 | CLARK | 7782 | 7839
3 | MILLER | 7934 | 7782
(14 rows)
共通の親を共有し、同じレベルにあるノードは 兄弟 と呼ばれます。たとえば、上記の出力では、 ALLENWARDMARTINTURNER 、およびJAMESの従業員はすべてレベル3で親BLAKEであるため、兄弟です。 JONESBLAKECLARKはレベル2にあり、 KINGは共通の親であるため、兄弟です。
2.2.5.5 兄弟姉妹の注文
ORDER SIBLINGS BYを使用して、選択した列の値によって兄弟が昇順または降順で表示されるように、結果セットを並べ替えることができます 。これは、階層問合せでのみ使用できるORDER BY句の特殊なケースです。
前の照会は、 ORDER SIBLINGS BY ename ASCを 追加してさらに変更されています
SELECT LEVEL, LPAD (' ', 2 * (LEVEL - 1)) || ename "employee", empno, mgr
FROM emp START WITH mgr IS NULL
CONNECT BY PRIOR empno = mgr
ORDER SIBLINGS BY ename ASC;
以前のクエリの出力が変更され、兄弟が名前の昇順に表示されるようになりました。兄弟 BLAKECLARKJONESKINGのアルファベット順に並んでいます。兄弟ALLENJAMESMARTINTURNERWARDBLAKEの下にアルファベット順に配置されています。
level | employee | empno | mgr
-------+-------------+-------+------
1 | KING | 7839 |
2 | BLAKE | 7698 | 7839
3 | ALLEN | 7499 | 7698
3 | JAMES | 7900 | 7698
3 | MARTIN | 7654 | 7698
3 | TURNER | 7844 | 7698
3 | WARD | 7521 | 7698
2 | CLARK | 7782 | 7839
3 | MILLER | 7934 | 7782
2 | JONES | 7566 | 7839
3 | FORD | 7902 | 7566
4 | SMITH | 7369 | 7902
3 | SCOTT | 7788 | 7566
4 | ADAMS | 7876 | 7788
(14 rows)
この最後の例は、 WHERE句を追加し、 3つのルートノードで開始します。ノードツリーが構築された後、 WHERE句はツリー内の行をフィルタリングして結果セットを形成します。
SELECT LEVEL, LPAD (' ', 2 * (LEVEL - 1)) || ename "employee", empno, mgr
FROM emp WHERE mgr IN (7839, 7782, 7902, 7788)
START WITH ename IN ('BLAKE','CLARK','JONES')
CONNECT BY PRIOR empno = mgr
ORDER SIBLINGS BY ename ASC;
クエリの出力には、 BLAKECLARK 、およびJONESの 3つのルートノード(レベル1)が表示されます 。さらに、 WHERE句を満たさない行は出力から削除されています。
level | employee | empno | mgr
-------+-----------+-------+------
1 | BLAKE | 7698 | 7839
1 | CLARK | 7782 | 7839
2 | MILLER | 7934 | 7782
1 | JONES | 7566 | 7839
3 | SMITH | 7369 | 7902
3 | ADAMS | 7876 | 7788
(6 rows)
2.2.5.6 CONNECT_BY_ROOTを使用したルート・ノードの取得
CONNECT_BY_ROOTは、現行の行に対してルート・ノードと見なされる行の列の値を戻すために列を修飾するために使用できる単項演算子です。
注: 単項演算子は単一のオペランド上で動作します。これは、 CONNECT_BY_ROOTの場合はCONNECT_BY_ROOTキーワードに続く列名です。
SELECTリストのコンテキストではCONNECT_BY_ROOT演算子は次のように表示されます。
SELECT [... ,] CONNECT_BY_ROOT column [, ...]
FROM table_expression ...
CONNECT_BY_ROOT演算子に関する注意点を次に示します
CONNECT_BY_ROOT 演算子 、WHERE 、GROUP BY、HAVING 、ORDER BY句、および ORDER兄弟 限り SELECT コマンドは階層クエリに そのままBY 、SELECTリスト で使用することができます
CONNECT_BY_ROOT オペレータ は、 句または 階層問合せのWITH START BY CONNECT で使用することができません
列を含む式にCONNECT_BY_ROOT を適用することは可能ですが、そのためには式をかっこで囲む必要があります。
次の問合せは、 CONNECT_BY_ROOT演算子を使用して、従業員BLAKECLARK 、およびJONESで始まるツリーに基づいて結果セットにリストされている各従業員のルート・ノードの従業員番号と従業員名を戻します。
SELECT LEVEL, LPAD (' ', 2 * (LEVEL - 1)) || ename "employee", empno, mgr,
CONNECT_BY_ROOT empno "mgr empno",
CONNECT_BY_ROOT ename "mgr ename"
FROM emp
START WITH ename IN ('BLAKE','CLARK','JONES')
CONNECT BY PRIOR empno = mgr
ORDER SIBLINGS BY ename ASC;
クエリからの出力では、列 mgr empnoおよびmgr ename 内のすべてのルートノードが、 START WITH句にリストされている従業員BLAKECLARK 、またはJONESのいずれかであることに注意してください
level | employee | empno | mgr | mgr empno | mgr ename
-------+-----------+-------+------+-----------+-----------
1 | BLAKE | 7698 | 7839 | 7698 | BLAKE
2 | ALLEN | 7499 | 7698 | 7698 | BLAKE
2 | JAMES | 7900 | 7698 | 7698 | BLAKE
2 | MARTIN | 7654 | 7698 | 7698 | BLAKE
2 | TURNER | 7844 | 7698 | 7698 | BLAKE
2 | WARD | 7521 | 7698 | 7698 | BLAKE
1 | CLARK | 7782 | 7839 | 7782 | CLARK
2 | MILLER | 7934 | 7782 | 7782 | CLARK
1 | JONES | 7566 | 7839 | 7566 | JONES
2 | FORD | 7902 | 7566 | 7566 | JONES
3 | SMITH | 7369 | 7902 | 7566 | JONES
2 | SCOTT | 7788 | 7566 | 7566 | JONES
3 | ADAMS | 7876 | 7788 | 7566 | JONES
(13 rows)
以下は同様のクエリですが、 mgrカラムがnull の単一の最上位の従業員で始まるツリーは1つだけ作成されます。
SELECT LEVEL, LPAD (' ', 2 * (LEVEL - 1)) || ename "employee", empno, mgr,
CONNECT_BY_ROOT empno "mgr empno",
CONNECT_BY_ROOT ename "mgr ename"
FROM emp START WITH mgr IS NULL
CONNECT BY PRIOR empno = mgr
ORDER SIBLINGS BY ename ASC;
次の出力では、列 mgr empnoおよびmgr ename のルートノードはすべて、この特定のクエリのルートとしてKINGを示しています。
level | employee | empno | mgr | mgr empno | mgr ename
-------+-------------+-------+------+-----------+-----------
1 | KING | 7839 | | 7839 | KING
2 | BLAKE | 7698 | 7839 | 7839 | KING
3 | ALLEN | 7499 | 7698 | 7839 | KING
3 | JAMES | 7900 | 7698 | 7839 | KING
3 | MARTIN | 7654 | 7698 | 7839 | KING
3 | TURNER | 7844 | 7698 | 7839 | KING
3 | WARD | 7521 | 7698 | 7839 | KING
2 | CLARK | 7782 | 7839 | 7839 | KING
3 | MILLER | 7934 | 7782 | 7839 | KING
2 | JONES | 7566 | 7839 | 7839 | KING
3 | FORD | 7902 | 7566 | 7839 | KING
4 | SMITH | 7369 | 7902 | 7839 | KING
3 | SCOTT | 7788 | 7566 | 7839 | KING
4 | ADAMS | 7876 | 7788 | 7839 | KING
(14 rows)
対照的に、次の例では START WITH句が省略され、結果的に14のツリーが作成されます。
SELECT LEVEL, LPAD (' ', 2 * (LEVEL - 1)) || ename "employee", empno, mgr,
CONNECT_BY_ROOT empno "mgr empno",
CONNECT_BY_ROOT ename "mgr ename"
FROM emp
CONNECT BY PRIOR empno = mgr
ORDER SIBLINGS BY ename ASC;
以下は、クエリの出力です。各ノードは 、リーフノードであっても独自のツリーの先頭を形成するので mgr empno列とmgr ename列の下にルートノードとして少なくとも1回表示されます。
level | employee | empno | mgr | mgr empno | mgr ename
-------+-------------+-------+------+-----------+-----------
1 | ADAMS | 7876 | 7788 | 7876 | ADAMS
1 | ALLEN | 7499 | 7698 | 7499 | ALLEN
1 | BLAKE | 7698 | 7839 | 7698 | BLAKE
2 | ALLEN | 7499 | 7698 | 7698 | BLAKE
2 | JAMES | 7900 | 7698 | 7698 | BLAKE
2 | MARTIN | 7654 | 7698 | 7698 | BLAKE
2 | TURNER | 7844 | 7698 | 7698 | BLAKE
2 | WARD | 7521 | 7698 | 7698 | BLAKE
1 | CLARK | 7782 | 7839 | 7782 | CLARK
2 | MILLER | 7934 | 7782 | 7782 | CLARK
1 | FORD | 7902 | 7566 | 7902 | FORD
2 | SMITH | 7369 | 7902 | 7902 | FORD
1 | JAMES | 7900 | 7698 | 7900 | JAMES
1 | JONES | 7566 | 7839 | 7566 | JONES
2 | FORD | 7902 | 7566 | 7566 | JONES
3 | SMITH | 7369 | 7902 | 7566 | JONES
2 | SCOTT | 7788 | 7566 | 7566 | JONES
3 | ADAMS | 7876 | 7788 | 7566 | JONES
1 | KING | 7839 | | 7839 | KING
2 | BLAKE | 7698 | 7839 | 7839 | KING
3 | ALLEN | 7499 | 7698 | 7839 | KING
3 | JAMES | 7900 | 7698 | 7839 | KING
3 | MARTIN | 7654 | 7698 | 7839 | KING
3 | TURNER | 7844 | 7698 | 7839 | KING
3 | WARD | 7521 | 7698 | 7839 | KING
2 | CLARK | 7782 | 7839 | 7839 | KING
3 | MILLER | 7934 | 7782 | 7839 | KING
2 | JONES | 7566 | 7839 | 7839 | KING
3 | FORD | 7902 | 7566 | 7839 | KING
4 | SMITH | 7369 | 7902 | 7839 | KING
3 | SCOTT | 7788 | 7566 | 7839 | KING
4 | ADAMS | 7876 | 7788 | 7839 | KING
1 | MARTIN | 7654 | 7698 | 7654 | MARTIN
1 | MILLER | 7934 | 7782 | 7934 | MILLER
1 | SCOTT | 7788 | 7566 | 7788 | SCOTT
2 | ADAMS | 7876 | 7788 | 7788 | SCOTT
1 | SMITH | 7369 | 7902 | 7369 | SMITH
1 | TURNER | 7844 | 7698 | 7844 | TURNER
1 | WARD | 7521 | 7698 | 7521 | WARD
(39 rows)
以下は、 CONNECT_BY_ROOTの 単項演算子効果を示しています。この例に示すように、カッコで囲まれていない式に適用すると、 CONNECT_BY_ROOT演算子は、その直後のenameという用語にのみ影響します。その後の連結|| '管理する' || enameCONNECT_BY_ROOT操作の一部ではないため、 enameの2番目の出現は現在処理されている行の値になり、 enameの最初の出現はルート・ノードからの値になります。
SELECT LEVEL, LPAD (' ', 2 * (LEVEL - 1)) || ename "employee", empno, mgr,
CONNECT_BY_ROOT ename || ' manages ' || ename "top mgr/employee"
FROM emp
START WITH ename IN ('BLAKE','CLARK','JONES')
CONNECT BY PRIOR empno = mgr
ORDER SIBLINGS BY ename ASC;
以下は、クエリの出力です。 トップのmgr / employee列の下に生成された値に注意してください
level | employee | empno | mgr | top mgr/employee
-------+-----------+-------+------+----------------------
1 | BLAKE | 7698 | 7839 | BLAKE manages BLAKE
2 | ALLEN | 7499 | 7698 | BLAKE manages ALLEN
2 | JAMES | 7900 | 7698 | BLAKE manages JAMES
2 | MARTIN | 7654 | 7698 | BLAKE manages MARTIN
2 | TURNER | 7844 | 7698 | BLAKE manages TURNER
2 | WARD | 7521 | 7698 | BLAKE manages WARD
1 | CLARK | 7782 | 7839 | CLARK manages CLARK
2 | MILLER | 7934 | 7782 | CLARK manages MILLER
1 | JONES | 7566 | 7839 | JONES manages JONES
2 | FORD | 7902 | 7566 | JONES manages FORD
3 | SMITH | 7369 | 7902 | JONES manages SMITH
2 | SCOTT | 7788 | 7566 | JONES manages SCOTT
3 | ADAMS | 7876 | 7788 | JONES manages ADAMS
(13 rows)
次の例では、カッコで囲まれた式に対して CONNECT_BY_ROOT演算子を使用しています。
SELECT LEVEL, LPAD (' ', 2 * (LEVEL - 1)) || ename "employee", empno, mgr,
CONNECT_BY_ROOT ('Manager ' || ename || ' is emp # ' || empno)
"top mgr/empno"
FROM emp
START WITH ename IN ('BLAKE','CLARK','JONES')
CONNECT BY PRIOR empno = mgr
ORDER SIBLINGS BY ename ASC;
クエリの出力は次のとおりです。 enameempno の両方の値は CONNECT_BY_ROOT演算子の影響を受けるため、 上位のmgr / empnoカラムの下に示すようにルートノードから値を返します。
level | employee | empno | mgr | top mgr/empno
-------+-----------+-------+------+-----------------------------
1 | BLAKE | 7698 | 7839 | Manager BLAKE is emp # 7698
2 | ALLEN | 7499 | 7698 | Manager BLAKE is emp # 7698
2 | JAMES | 7900 | 7698 | Manager BLAKE is emp # 7698
2 | MARTIN | 7654 | 7698 | Manager BLAKE is emp # 7698
2 | TURNER | 7844 | 7698 | Manager BLAKE is emp # 7698
2 | WARD | 7521 | 7698 | Manager BLAKE is emp # 7698
1 | CLARK | 7782 | 7839 | Manager CLARK is emp # 7782
2 | MILLER | 7934 | 7782 | Manager CLARK is emp # 7782
1 | JONES | 7566 | 7839 | Manager JONES is emp # 7566
2 | FORD | 7902 | 7566 | Manager JONES is emp # 7566
3 | SMITH | 7369 | 7902 | Manager JONES is emp # 7566
2 | SCOTT | 7788 | 7566 | Manager JONES is emp # 7566
3 | ADAMS | 7876 | 7788 | Manager JONES is emp # 7566
(13 rows)
2.2.5.7 SYS_CONNECT_BY_PATHを使用したパスの取得
SYS_CONNECT_BY_PATHは、現在のノードとルート・ノードの間にある指定された列の列値を取得するために、階層問合せ内で機能する関数です。関数のシグネチャは次のとおりです。
SYS_CONNECT_BY_PATH( 区切り文字
この関数は2つの引数をとります:
columnは、関数を呼び出す階層問合せで指定された表内にある列の名前です。
delimiterは、指定した列の各エントリを区切るvarchar値です。
次の例では、従業員名とそのマネージャのリストを返します。マネージャにマネージャがある場合、その名前が結果に追加されます。
edb=# SELECT level, ename , SYS_CONNECT_BY_PATH(ename, '/') managers
FROM emp
CONNECT BY PRIOR empno = mgr
START WITH mgr IS NULL
ORDER BY level, ename, managers;
level | ename | managers
-------+--------+-------------------------
1 | KING | /KING
2 | BLAKE | /KING/BLAKE
2 | CLARK | /KING/CLARK
2 | JONES | /KING/JONES
3 | ALLEN | /KING/BLAKE/ALLEN
3 | FORD | /KING/JONES/FORD
3 | JAMES | /KING/BLAKE/JAMES
3 | MARTIN | /KING/BLAKE/MARTIN
3 | MILLER | /KING/CLARK/MILLER
3 | SCOTT | /KING/JONES/SCOTT
3 | TURNER | /KING/BLAKE/TURNER
3 | WARD | /KING/BLAKE/WARD
4 | ADAMS | /KING/JONES/SCOTT/ADAMS
4 | SMITH | /KING/JONES/FORD/SMITH
(14 rows)
結果セット内:
レベル列は、クエリが返されるレベルの数を表示します。
ENAME列には、従業員の名前が表示されます。
経営者の欄には、管理者の階層リストが含まれています。
SYS_CONNECT_BY_PATH のAdvanced Server実装では、 次の使用をサポートしていません。
CONNECT_BY_PATH内のSYS_CONNECT_BY_PATH
SYS_CONNECT_BY_PATH内のSYS_CONNECT_BY_PATH
 
 
 
2.2.6 多次元分析
多次元分析とは、さまざまな次元の組み合わせを使用してデータを検査するデータ・ウェアハウス・アプリケーションで一般的に使用されるプロセスのことです。 ディメンションは、時間、地理、会社の部門、製品ラインなどのデータを分類するために使用されるカテゴリです。特定のディメンションセットに関連付けられた結果をファクトと呼びます。事実は、通常、製品の販売、利益、数量、数などに関連する数字です。
リレーショナル・データベース・システムで一連のディメンションに基づいてこれらのファクトを取得するには、SQL集約が一般的に使用されます。 SQL集計は、基本的に、データが特定の基準(ディメンション)に従ってグループ化され、結果セットが、各グループのデータのカウント、合計、平均などのファクトの集計で構成されていることを意味します。
SQL SELECTコマンド GROUP BY句は、集計結果の生成プロセスを簡素化する次の拡張をサポートしています。
ROLLUP拡張
CUBE拡張
GROUPING SETS拡張機能
さらに、 GROUPING関数とGROUPING_ID関数をSELECTリストまたはHAVING節で使用して、これらの拡張が使用されたときの結果の解釈を支援することができます。
注意:サンプルのdeptおよびemp表は、この例では使用例を提供するために広く使用されています。より有益な結果を得るために、以下の変更がこれらの表に適用されました。
UPDATE dept SET loc = 'BOSTON' WHERE deptno = 20;
INSERT INTO emp (empno,ename,job,deptno) VALUES (9001,'SMITH','CLERK',40);
INSERT INTO emp (empno,ename,job,deptno) VALUES (9002,'JONES','ANALYST',40);
INSERT INTO emp (empno,ename,job,deptno) VALUES (9003,'ROGERS','MANAGER',40);
emp表とdept表の結合の次の行が使用されます。
SELECT loc, dname, job, empno FROM emp e, dept d
WHERE e.deptno = d.deptno
ORDER BY 1, 2, 3, 4;
 
loc | dname | job | empno
----------+------------+-----------+-------
BOSTON | OPERATIONS | ANALYST | 9002
BOSTON | OPERATIONS | CLERK | 9001
BOSTON | OPERATIONS | MANAGER | 9003
BOSTON | RESEARCH | ANALYST | 7788
BOSTON | RESEARCH | ANALYST | 7902
BOSTON | RESEARCH | CLERK | 7369
BOSTON | RESEARCH | CLERK | 7876
BOSTON | RESEARCH | MANAGER | 7566
CHICAGO | SALES | CLERK | 7900
CHICAGO | SALES | MANAGER | 7698
CHICAGO | SALES | SALESMAN | 7499
CHICAGO | SALES | SALESMAN | 7521
CHICAGO | SALES | SALESMAN | 7654
CHICAGO | SALES | SALESMAN | 7844
NEW YORK | ACCOUNTING | CLERK | 7934
NEW YORK | ACCOUNTING | MANAGER | 7782
NEW YORK | ACCOUNTING | PRESIDENT | 7839
(17 rows)
LOC、DNAME、 ジョブ列は実施例で使用されるSQL集計の寸法のために使用されます。集計結果は、 COUNT(*)関数を使用して取得した従業員の数です。
locdname 、およびjob列をグループ化する基本的なクエリは、次のように与えられます。
SELECT loc, dname, job, COUNT(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY loc, dname, job
ORDER BY 1, 2, 3;
拡張子を持たない基本 GROUP BY句を使用してこの結果セットの行を基本 集約行と呼びます。
loc | dname | job | employees
----------+------------+-----------+-----------
BOSTON | OPERATIONS | ANALYST | 1
BOSTON | OPERATIONS | CLERK | 1
BOSTON | OPERATIONS | MANAGER | 1
BOSTON | RESEARCH | ANALYST | 2
BOSTON | RESEARCH | CLERK | 2
BOSTON | RESEARCH | MANAGER | 1
CHICAGO | SALES | CLERK | 1
CHICAGO | SALES | MANAGER | 1
CHICAGO | SALES | SALESMAN | 4
NEW YORK | ACCOUNTING | CLERK | 1
NEW YORK | ACCOUNTING | MANAGER | 1
NEW YORK | ACCOUNTING | PRESIDENT | 1
(12 rows)
ROLLUPCUBE拡張は、結果セットに小計の追加のレベルを提供することによって、ベース集約行に追加します。
GROUPINGは、単一の結果セットにグループの異なるタイプを組み合わせる能力を提供する拡張機能を設定します
GROUPINGおよびGROUPING_IDは 、結果セットの解釈に援助を機能します。
これらの拡張によって提供される追加については、以降のセクションで詳しく説明します。
 
2.2.6.1 ROLLUP拡張
ROLLUP拡張は、各階層グループならびに総計の小計とグループの階層的なセットを生成します。階層の順序は、 ROLLUP式リストで指定された式の順序によって決まります。階層の最上位はリストの一番左の項目です。右側に進む各連続する項目は階層の下に移動し、最も右側の項目が最も低いレベルになります。
単一の ROLLUP の構文は次のとおりです。
ROLLUP ( { expr_1 | ( expr_1a [, expr_1b ] ...) }
[, expr_2 | ( expr_2a [, expr_2b ] ...) ] ...)
exprは、結果セットのグループ化を決定する式です。 expr_1a expr_1b 、...)のように括弧で囲まれた場合、 expr_1aexpr_1bによって返される値の組み合わせは、階層の単一のグループ化レベルを定義します。
結果セットで返される集約の基本レベルは、式リストによって返される値の固有の組み合わせごとです。
さらに、リスト内の最初の項目( expr_1または expr_1a expr_1b 、...)のいずれかが指定されている組み合わせ)に対して、それぞれの一意の値に対して小計が戻されます。リスト内の2番目の項目( expr_2または expr_2a expr_2b 、...)のいずれかが指定されているいずれかの組み合わせ)が最初の項目の各グループ内で一意の値ごとに返されます。最後に、結果セット全体に対して総計が返されます。
小計の行については、小計が取られている項目に対してnullが返されます。
GROUP BY句のコンテキスト内で指定されたROLLUP拡張は、以下のように示されています。
SELECT select_list FROM ...
GROUP BY [... ,] ROLLUP ( expression_list ) [, ...]
select_listで 指定された項目は、 ROLLUPの expression_listにも表示されなければなりません。 COUNTSUMAVGMINMAXなどの集計関数である必要があります。または、戻り値がグループ内の個々の行とは無関係の定数または関数でなければなりません(たとえば、 SYSDATE関数)。
GROUP BYは、拡張機能や、個々の表現することで 、複数 ROLLUP拡張だけでなく、他のグループの複数の発生を指定することもできます。
出力を階層構造またはその他の意味のある構造で表示する場合は ORDER BY句を使用する必要があります。 ORDER BY句が指定されていない場合、結果セットの順序は保証されません。
グルーピング・レベルまたは合計の数は n + 1で、 nROLLUP式リスト内の項目数を表します。カッコで囲まれたリストは1つの項目としてカウントされます。
次のクエリは、列 locdnamejobの 階層に基づいてロールアップを生成します
SELECT loc, dname, job, COUNT(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY ROLLUP (loc, dname, job)
ORDER BY 1, 2, 3;
クエリの結果は次のとおりです。それぞれのユニークな組み合わせのために従業員の数のカウントがあり LOC、DNAME、および仕事だけでなく、LOCDNAMEの各ユニークな組み合わせの小計、LOCの一意の各値のために、そして最後の行に表示される総計は、 。
loc | dname | job | employees
----------+------------+-----------+-----------
BOSTON | OPERATIONS | ANALYST | 1
BOSTON | OPERATIONS | CLERK | 1
BOSTON | OPERATIONS | MANAGER | 1
BOSTON | OPERATIONS | | 3
BOSTON | RESEARCH | ANALYST | 2
BOSTON | RESEARCH | CLERK | 2
BOSTON | RESEARCH | MANAGER | 1
BOSTON | RESEARCH | | 5
BOSTON | | | 8
CHICAGO | SALES | CLERK | 1
CHICAGO | SALES | MANAGER | 1
CHICAGO | SALES | SALESMAN | 4
CHICAGO | SALES | | 6
CHICAGO | | | 6
NEW YORK | ACCOUNTING | CLERK | 1
NEW YORK | ACCOUNTING | MANAGER | 1
NEW YORK | ACCOUNTING | PRESIDENT | 1
NEW YORK | ACCOUNTING | | 3
NEW YORK | | | 3
| | | 17
(20 rows)
次のクエリは、括弧内のROLLUPリスト内の項目を結合する効果を示しています。
SELECT loc, dname, job, COUNT(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY ROLLUP (loc, (dname, job))
ORDER BY 1, 2, 3;
出力では、前の例のように、 locdnameの組み合わせの小計はないことに注意してください
loc | dname | job | employees
----------+------------+-----------+-----------
BOSTON | OPERATIONS | ANALYST | 1
BOSTON | OPERATIONS | CLERK | 1
BOSTON | OPERATIONS | MANAGER | 1
BOSTON | RESEARCH | ANALYST | 2
BOSTON | RESEARCH | CLERK | 2
BOSTON | RESEARCH | MANAGER | 1
BOSTON | | | 8
CHICAGO | SALES | CLERK | 1
CHICAGO | SALES | MANAGER | 1
CHICAGO | SALES | SALESMAN | 4
CHICAGO | | | 6
NEW YORK | ACCOUNTING | CLERK | 1
NEW YORK | ACCOUNTING | MANAGER | 1
NEW YORK | ACCOUNTING | PRESIDENT | 1
NEW YORK | | | 3
| | | 17
(16 rows)
ROLLUPリストの最初の2つの列が括弧で囲まれている場合、小計レベルも異なります。
SELECT loc, dname, job, COUNT(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY ROLLUP ((loc, dname), job)
ORDER BY 1, 2, 3;
今度は、一意の各 locdnameの組み合わせの小計がありますが、 locの一意の値はありません。
loc | dname | job | employees
----------+------------+-----------+-----------
BOSTON | OPERATIONS | ANALYST | 1
BOSTON | OPERATIONS | CLERK | 1
BOSTON | OPERATIONS | MANAGER | 1
BOSTON | OPERATIONS | | 3
BOSTON | RESEARCH | ANALYST | 2
BOSTON | RESEARCH | CLERK | 2
BOSTON | RESEARCH | MANAGER | 1
BOSTON | RESEARCH | | 5
CHICAGO | SALES | CLERK | 1
CHICAGO | SALES | MANAGER | 1
CHICAGO | SALES | SALESMAN | 4
CHICAGO | SALES | | 6
NEW YORK | ACCOUNTING | CLERK | 1
NEW YORK | ACCOUNTING | MANAGER | 1
NEW YORK | ACCOUNTING | PRESIDENT | 1
NEW YORK | ACCOUNTING | | 3
| | | 17
(17 rows)
 
2.2.6.2 CUBE拡張
CUBE拡張、ROLLUP拡張に似ています。しかし、ROLLUPリスト内の項目の右側のリストに左に基づく階層でグループ化し、結果を生成ROLLUPとは異なり、CUBEは CUBEリスト内のすべての項目のすべての順列に基づいてグループ化し、小計を生成します。したがって、結果セットには、同じ式リストで実行されたROLLUPより多くの行が含まれています。
単一の CUBE の構文は次のとおりです。
CUBE ( { expr_1 | ( expr_1a [, expr_1b ] ...) }
[, expr_2 | ( expr_2a [, expr_2b ] ...) ] ...)
exprは、結果セットのグループ化を決定する式です。 expr_1a expr_1b 、...)のように括弧で囲まれた場合、 expr_1aexpr_1bによって返される値の組み合わせは単一のグループを定義します。
結果セットで返される集約の基本レベルは、式リストによって返される値の固有の組み合わせごとです。
さらに、リスト内の最初の項目( expr_1または expr_1a expr_1b 、...)のいずれかが指定されている組み合わせ)に対して、それぞれの一意の値に対して小計が戻されます。リスト内の2番目の項目( expr_2または expr_2a expr_2b 、...)のいずれかが指定されています)の小計が各一意の値に対して戻されます。また、最初の項目と2番目の項目の固有の組み合わせごとに小計が返されます。同様に、第3のアイテムがある場合、第3のアイテムの各固有値、第3のアイテムおよび第1のアイテムの組み合わせのそれぞれの固有値、第3のアイテムおよび第2のアイテムの組み合わせのそれぞれの固有値、およびそれぞれの固有値第3のアイテム、第2のアイテム、および第1のアイテムの組み合わせのうちの1つを含む。最後に、結果セット全体に対して総計が返されます。
小計の行については、小計が取られている項目に対してnullが返されます。
GROUP BY句のコンテキスト内で指定されたキューブの拡張は、以下のように示されています。
SELECT select_list FROM ...
GROUP BY [... ,] CUBE ( expression_list ) [, ...]
select_listで 指定された項目は、 CUBEの expression_listにも表示される必要があります。 COUNTSUMAVGMINMAXなどの集計関数である必要があります。または、戻り値がグループ内の個々の行とは無関係の定数または関数でなければなりません(たとえば、 SYSDATE関数)。
GROUP BYは、拡張機能や、個々の表現することで 、複数 CUBE拡張だけでなく、他のグループの複数の発生を指定することもできます。
出力を意味のある構造で表示する場合は ORDER BY句を使用する必要があります。 ORDER BY句が指定されていない場合、結果セットの順序は保証されません。
グループレベルまたは合計の数であり 、nは CUBEリスト内の項目の数を表すn個のパワーに2を提起しました。カッコで囲まれたリストは1つの項目としてカウントされます。
次のクエリは、列 locdname 、およびjobの 順列に基づいてキューブを生成します
SELECT loc, dname, job, COUNT(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY CUBE (loc, dname, job)
ORDER BY 1, 2, 3;
クエリの結果は次のとおりです。 locdnamejobの 各組み合わせの従業員数 、およびlocdnameの各組み合わせの小計、 dnamejobの組み合わせごとの、それぞれのlocjobの組み合わせのカウントがありますジョブの一意の値ごとにdnameの一意の値ごとにlocの一意の値、最後の行に表示される総計。
loc | dname | job | employees
----------+------------+-----------+-----------
BOSTON | OPERATIONS | ANALYST | 1
BOSTON | OPERATIONS | CLERK | 1
BOSTON | OPERATIONS | MANAGER | 1
BOSTON | OPERATIONS | | 3
BOSTON | RESEARCH | ANALYST | 2
BOSTON | RESEARCH | CLERK | 2
BOSTON | RESEARCH | MANAGER | 1
BOSTON | RESEARCH | | 5
BOSTON | | ANALYST | 3
BOSTON | | CLERK | 3
BOSTON | | MANAGER | 2
BOSTON | | | 8
CHICAGO | SALES | CLERK | 1
CHICAGO | SALES | MANAGER | 1
CHICAGO | SALES | SALESMAN | 4
CHICAGO | SALES | | 6
CHICAGO | | CLERK | 1
CHICAGO | | MANAGER | 1
CHICAGO | | SALESMAN | 4
CHICAGO | | | 6
NEW YORK | ACCOUNTING | CLERK | 1
NEW YORK | ACCOUNTING | MANAGER | 1
NEW YORK | ACCOUNTING | PRESIDENT | 1
NEW YORK | ACCOUNTING | | 3
NEW YORK | | CLERK | 1
NEW YORK | | MANAGER | 1
NEW YORK | | PRESIDENT | 1
NEW YORK | | | 3
| ACCOUNTING | CLERK | 1
| ACCOUNTING | MANAGER | 1
| ACCOUNTING | PRESIDENT | 1
| ACCOUNTING | | 3
| OPERATIONS | ANALYST | 1
| OPERATIONS | CLERK | 1
| OPERATIONS | MANAGER | 1
| OPERATIONS | | 3
| RESEARCH | ANALYST | 2
| RESEARCH | CLERK | 2
| RESEARCH | MANAGER | 1
| RESEARCH | | 5
| SALES | CLERK | 1
| SALES | MANAGER | 1
| SALES | SALESMAN | 4
| SALES | | 6
| | ANALYST | 3
| | CLERK | 5
| | MANAGER | 4
| | PRESIDENT | 1
| | SALESMAN | 4
| | | 17
(50 rows)
次のクエリは、かっこ内のCUBEリスト内のアイテムを組み合わせる効果を示しています。
SELECT loc, dname, job, COUNT(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY CUBE (loc, (dname, job))
ORDER BY 1, 2, 3;
出力ノートでは一切関与順列の小計がないこと LOCDNAMEの組み合わせを、LOC、 ジョブの組み合わせ、またはそれ自体でdnameのため、またはジョブのためには、それ自体で。
loc | dname | job | employees
----------+------------+-----------+-----------
BOSTON | OPERATIONS | ANALYST | 1
BOSTON | OPERATIONS | CLERK | 1
BOSTON | OPERATIONS | MANAGER | 1
BOSTON | RESEARCH | ANALYST | 2
BOSTON | RESEARCH | CLERK | 2
BOSTON | RESEARCH | MANAGER | 1
BOSTON | | | 8
CHICAGO | SALES | CLERK | 1
CHICAGO | SALES | MANAGER | 1
CHICAGO | SALES | SALESMAN | 4
CHICAGO | | | 6
NEW YORK | ACCOUNTING | CLERK | 1
NEW YORK | ACCOUNTING | MANAGER | 1
NEW YORK | ACCOUNTING | PRESIDENT | 1
NEW YORK | | | 3
| ACCOUNTING | CLERK | 1
| ACCOUNTING | MANAGER | 1
| ACCOUNTING | PRESIDENT | 1
| OPERATIONS | ANALYST | 1
| OPERATIONS | CLERK | 1
| OPERATIONS | MANAGER | 1
| RESEARCH | ANALYST | 2
| RESEARCH | CLERK | 2
| RESEARCH | MANAGER | 1
| SALES | CLERK | 1
| SALES | MANAGER | 1
| SALES | SALESMAN | 4
| | | 17
(28 rows)
次のクエリは、最初の式が CUBE拡張の外側で指定される別のバリ​​エーションを示しています
SELECT loc, dname, job, COUNT(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY loc, CUBE (dname, job)
ORDER BY 1, 2, 3;
この出力では、順列は locの各グループ内のdnamejob に対して実行され ます
loc | dname | job | employees
----------+------------+-----------+-----------
BOSTON | OPERATIONS | ANALYST | 1
BOSTON | OPERATIONS | CLERK | 1
BOSTON | OPERATIONS | MANAGER | 1
BOSTON | OPERATIONS | | 3
BOSTON | RESEARCH | ANALYST | 2
BOSTON | RESEARCH | CLERK | 2
BOSTON | RESEARCH | MANAGER | 1
BOSTON | RESEARCH | | 5
BOSTON | | ANALYST | 3
BOSTON | | CLERK | 3
BOSTON | | MANAGER | 2
BOSTON | | | 8
CHICAGO | SALES | CLERK | 1
CHICAGO | SALES | MANAGER | 1
CHICAGO | SALES | SALESMAN | 4
CHICAGO | SALES | | 6
CHICAGO | | CLERK | 1
CHICAGO | | MANAGER | 1
CHICAGO | | SALESMAN | 4
CHICAGO | | | 6
NEW YORK | ACCOUNTING | CLERK | 1
NEW YORK | ACCOUNTING | MANAGER | 1
NEW YORK | ACCOUNTING | PRESIDENT | 1
NEW YORK | ACCOUNTING | | 3
NEW YORK | | CLERK | 1
NEW YORK | | MANAGER | 1
NEW YORK | | PRESIDENT | 1
NEW YORK | | | 3
(28 rows)
 
2.2.6.3 GROUPING SETS拡張機能
GROUP BY句内 GROUPING SETS拡張子を使用すると、異なるグループ化に基づいて複数の結果セットを実際に連結した結果セットを生成することができます。つまり、複数のグループ化の結果セットを1つの結果セットに結合するUNION ALL操作が実行されます。
UNION ALL操作、したがってGROUPING SETS拡張は、結合されている結果セットから重複した行を削除しないことに注意してください
単一の GROUPING SETS拡張の構文は次のとおりです。
GROUPING SETS (
{ expr_1 | ( expr_1a [, expr_1b ] ...) |
ROLLUP ( expr_list ) | CUBE ( expr_list )
} [, ...] )
GROUPINGは、拡張子が1つまたは複数のカンマで区切られた式、括弧で囲まれた式のリスト、ROLLUP拡張 、およびCUBEの拡張子の任意の組み合わせを含めることができます設定します
グループ化は、以下で示されるように拡張がGROUP BY句のコンテキスト内で指定されている設定します
SELECT select_list FROM ...
GROUP BY [... ,] GROUPING SETS ( expression_list ) [, ...]
select_listで 指定された項目は、 GROUPING SETSの expression_listにも表示する必要があります。 COUNTSUMAVGMINMAXなどの集計関数である必要があります。または、戻り値がグループ内の個々の行とは無関係の定数または関数でなければなりません(たとえば、 SYSDATE関数)。
複数のグループを指定することがGROUP BYは、拡張だけでなく、拡張機能や個々の表現BY他のグループの複数の出現を設定します
出力を意味のある構造で表示する場合は ORDER BY句を使用する必要があります。 ORDER BY句が指定されていない場合、結果セットの順序は保証されません。
次のクエリは、列 locdname 、およびjob によって与えられるグループの和集合を生成します
SELECT loc, dname, job, COUNT(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY GROUPING SETS (loc, dname, job)
ORDER BY 1, 2, 3;
結果は次のとおりです。
loc | dname | job | employees
----------+------------+-----------+-----------
BOSTON | | | 8
CHICAGO | | | 6
NEW YORK | | | 3
| ACCOUNTING | | 3
| OPERATIONS | | 3
| RESEARCH | | 5
| SALES | | 6
| | ANALYST | 3
| | CLERK | 5
| | MANAGER | 4
| | PRESIDENT | 1
| | SALESMAN | 4
(12 rows)
これは、 UNION ALL演算子を使用する次の問合せと同じです。
SELECT loc AS "loc", NULL AS "dname", NULL AS "job", COUNT(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY loc
UNION ALL
SELECT NULL, dname, NULL, COUNT(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY dname
UNION ALL
SELECT NULL, NULL, job, COUNT(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY job
ORDER BY 1, 2, 3;
UNION ALL問合せからの出力は、 GROUPING SETS出力と同じです。
loc | dname | job | employees
----------+------------+-----------+-----------
BOSTON | | | 8
CHICAGO | | | 6
NEW YORK | | | 3
| ACCOUNTING | | 3
| OPERATIONS | | 3
| RESEARCH | | 5
| SALES | | 6
| | ANALYST | 3
| | CLERK | 5
| | MANAGER | 4
| | PRESIDENT | 1
| | SALESMAN | 4
(12 rows)
次の例は、さまざまな種類の GROUP BY拡張をGROUPING SETS式リスト内で一緒に使用する方法を示しています
SELECT loc, dname, job, COUNT(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY GROUPING SETS (loc, ROLLUP (dname, job), CUBE (job, loc))
ORDER BY 1, 2, 3;
このクエリの出力は次のとおりです。
loc | dname | job | employees
----------+------------+-----------+-----------
BOSTON | | ANALYST | 3
BOSTON | | CLERK | 3
BOSTON | | MANAGER | 2
BOSTON | | | 8
BOSTON | | | 8
CHICAGO | | CLERK | 1
CHICAGO | | MANAGER | 1
CHICAGO | | SALESMAN | 4
CHICAGO | | | 6
CHICAGO | | | 6
NEW YORK | | CLERK | 1
NEW YORK | | MANAGER | 1
NEW YORK | | PRESIDENT | 1
NEW YORK | | | 3
NEW YORK | | | 3
| ACCOUNTING | CLERK | 1
| ACCOUNTING | MANAGER | 1
| ACCOUNTING | PRESIDENT | 1
| ACCOUNTING | | 3
| OPERATIONS | ANALYST | 1
| OPERATIONS | CLERK | 1
| OPERATIONS | MANAGER | 1
| OPERATIONS | | 3
| RESEARCH | ANALYST | 2
| RESEARCH | CLERK | 2
| RESEARCH | MANAGER | 1
| RESEARCH | | 5
| SALES | CLERK | 1
| SALES | MANAGER | 1
| SALES | SALESMAN | 4
| SALES | | 6
| | ANALYST | 3
| | CLERK | 5
| | MANAGER | 4
| | PRESIDENT | 1
| | SALESMAN | 4
| | | 17
| | | 17
(38 rows)
出力は基本的に、 GROUP BY locGROUP BY ROLLUP(dname、job) 、およびGROUP BY CUBE(job、loc) から個別に生成される結果セットの連結です 。これらの個々のクエリは以下のように表示されます。
SELECT loc, NULL AS "dname", NULL AS "job", COUNT(*) AS "employees"
FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY loc
ORDER BY 1;
以下は GROUP BYのlocからの結果セットです。
loc | dname | job | employees
----------+-------+-----+-----------
BOSTON | | | 8
CHICAGO | | | 6
NEW YORK | | | 3
(3 rows)
次のクエリは、 GROUP BY ROLLUP(dname、job)句を使用します。
SELECT NULL AS "loc", dname, job, COUNT(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY ROLLUP (dname, job)
ORDER BY 2, 3;
以下は、 GROUP BY ROLLUP(dname、job)からの結果セットです。
loc | dname | job | employees
-----+------------+-----------+-----------
| ACCOUNTING | CLERK | 1
| ACCOUNTING | MANAGER | 1
| ACCOUNTING | PRESIDENT | 1
| ACCOUNTING | | 3
| OPERATIONS | ANALYST | 1
| OPERATIONS | CLERK | 1
| OPERATIONS | MANAGER | 1
| OPERATIONS | | 3
| RESEARCH | ANALYST | 2
| RESEARCH | CLERK | 2
| RESEARCH | MANAGER | 1
| RESEARCH | | 5
| SALES | CLERK | 1
| SALES | MANAGER | 1
| SALES | SALESMAN | 4
| SALES | | 6
| | | 17
(17 rows)
次のクエリでは、 GROUP BY CUBE(job、loc)句が使用されます。
SELECT loc, NULL AS "dname", job, COUNT(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY CUBE (job, loc)
ORDER BY 1, 3;
以下は、 GROUP BY CUBE(job、loc)から設定された結果です。
loc | dname | job | employees
----------+-------+-----------+-----------
BOSTON | | ANALYST | 3
BOSTON | | CLERK | 3
BOSTON | | MANAGER | 2
BOSTON | | | 8
CHICAGO | | CLERK | 1
CHICAGO | | MANAGER | 1
CHICAGO | | SALESMAN | 4
CHICAGO | | | 6
NEW YORK | | CLERK | 1
NEW YORK | | MANAGER | 1
NEW YORK | | PRESIDENT | 1
NEW YORK | | | 3
| | ANALYST | 3
| | CLERK | 5
| | MANAGER | 4
| | PRESIDENT | 1
| | SALESMAN | 4
| | | 17
(18 rows)
前の3つのクエリを UNION ALL演算子と組み合わせると 、3つの結果セットの連結が生成されます。
SELECT loc AS "loc", NULL AS "dname", NULL AS "job", COUNT(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY loc
UNION ALL
SELECT NULL, dname, job, count(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY ROLLUP (dname, job)
UNION ALL
SELECT loc, NULL, job, count(*) AS "employees" FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY CUBE (job, loc)
ORDER BY 1, 2, 3;
以下は、 GROUP BY GROUPING SETS(loc、ROLLUP(dname、job)、CUBE(job、loc))節が使用されているときと同じ出力です。
loc | dname | job | employees
----------+------------+-----------+-----------
BOSTON | | ANALYST | 3
BOSTON | | CLERK | 3
BOSTON | | MANAGER | 2
BOSTON | | | 8
BOSTON | | | 8
CHICAGO | | CLERK | 1
CHICAGO | | MANAGER | 1
CHICAGO | | SALESMAN | 4
CHICAGO | | | 6
CHICAGO | | | 6
NEW YORK | | CLERK | 1
NEW YORK | | MANAGER | 1
NEW YORK | | PRESIDENT | 1
NEW YORK | | | 3
NEW YORK | | | 3
| ACCOUNTING | CLERK | 1
| ACCOUNTING | MANAGER | 1
| ACCOUNTING | PRESIDENT | 1
| ACCOUNTING | | 3
| OPERATIONS | ANALYST | 1
| OPERATIONS | CLERK | 1
| OPERATIONS | MANAGER | 1
| OPERATIONS | | 3
| RESEARCH | ANALYST | 2
| RESEARCH | CLERK | 2
| RESEARCH | MANAGER | 1
| RESEARCH | | 5
| SALES | CLERK | 1
| SALES | MANAGER | 1
| SALES | SALESMAN | 4
| SALES | | 6
| | ANALYST | 3
| | CLERK | 5
| | MANAGER | 4
| | PRESIDENT | 1
| | SALESMAN | 4
| | | 17
| | | 17
(38 rows)
 
2.2.6.4 GROUPING関数
使用する場合 ROLLUP、CUBE、またはGROUPING GROUP BY句の拡張機能を設定し 、時々 、結果セット内の拡張、ならびにベース集約行によって生成された小計の様々なレベルを区別することが困難であってもよいです。 GROUPING関数は、この区別を行う手段を提供します。
GROUPING関数の一般的な構文は次のようになります。
SELECT [ expr ...,] GROUPING( col_expr ) [, expr ] ...
FROM ...
GROUP BY [...,]
{ ROLLUP | CUBE | GROUPING SETS }( [...,] col_expr
[, ...] ) [, ...]
GROUPING関数、ROLLUP、CUBE、またはGROUPINGの式リストに指定されたディメンション列の発現は、GROUP BY句の拡張を設定しなければならない単一のパラメータを取ります。
GROUPING関数の戻り値は、 0または1のいずれかです。クエリの結果セットでは、行がその列の複数の値に対する小計を表しているため、 GROUPING関数で指定された列式がNULLの場合、 GROUPING関数は値が1です。行がGROUPING関数で指定された列の特定の値に基づいて結果を戻す場合、 GROUPING関数は値0を戻します。後者の場合、列はNULLでも非NULLでもかまいませんいずれの場合でも、その列の特定の値であり、複数の値にまたがる小計ではありません。
次のクエリは、 GROUPING関数の戻り値が小計行にどのように対応しているかを示しています
SELECT loc, dname, job, COUNT(*) AS "employees",
GROUPING(loc) AS "gf_loc",
GROUPING(dname) AS "gf_dname",
GROUPING(job) AS "gf_job"
FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY ROLLUP (loc, dname, job)
ORDER BY 1, 2, 3;
GROUPING関数の出力を表示する3つの右端の列には、対応する列の値に小計が取られている場合は、小計の行に値1が表示されます。
loc | dname | job | employees | gf_loc | gf_dname | gf_job
----------+------------+-----------+-----------+--------+----------+--------
BOSTON | OPERATIONS | ANALYST | 1 | 0 | 0 | 0
BOSTON | OPERATIONS | CLERK | 1 | 0 | 0 | 0
BOSTON | OPERATIONS | MANAGER | 1 | 0 | 0 | 0
BOSTON | OPERATIONS | | 3 | 0 | 0 | 1
BOSTON | RESEARCH | ANALYST | 2 | 0 | 0 | 0
BOSTON | RESEARCH | CLERK | 2 | 0 | 0 | 0
BOSTON | RESEARCH | MANAGER | 1 | 0 | 0 | 0
BOSTON | RESEARCH | | 5 | 0 | 0 | 1
BOSTON | | | 8 | 0 | 1 | 1
CHICAGO | SALES | CLERK | 1 | 0 | 0 | 0
CHICAGO | SALES | MANAGER | 1 | 0 | 0 | 0
CHICAGO | SALES | SALESMAN | 4 | 0 | 0 | 0
CHICAGO | SALES | | 6 | 0 | 0 | 1
CHICAGO | | | 6 | 0 | 1 | 1
NEW YORK | ACCOUNTING | CLERK | 1 | 0 | 0 | 0
NEW YORK | ACCOUNTING | MANAGER | 1 | 0 | 0 | 0
NEW YORK | ACCOUNTING | PRESIDENT | 1 | 0 | 0 | 0
NEW YORK | ACCOUNTING | | 3 | 0 | 0 | 1
NEW YORK | | | 3 | 0 | 1 | 1
| | | 17 | 1 | 1 | 1
(20 rows)
これらの指標は、特定の小計のスクリーニング基準として使用することができます。たとえば、前のクエリを使用すると、 HAVING句でGROUPING関数を使用して、 locdnameの組み合わせの小計のみを表示できます
SELECT loc, dname, job, COUNT(*) AS "employees",
GROUPING(loc) AS "gf_loc",
GROUPING(dname) AS "gf_dname",
GROUPING(job) AS "gf_job"
FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY ROLLUP (loc, dname, job)
HAVING GROUPING(loc) = 0
AND GROUPING(dname) = 0
AND GROUPING(job) = 1
ORDER BY 1, 2;
このクエリは、次の結果を生成します。
loc | dname | job | employees | gf_loc | gf_dname | gf_job
----------+------------+-----+-----------+--------+----------+--------
BOSTON | OPERATIONS | | 3 | 0 | 0 | 1
BOSTON | RESEARCH | | 5 | 0 | 0 | 1
CHICAGO | SALES | | 6 | 0 | 0 | 1
NEW YORK | ACCOUNTING | | 3 | 0 | 0 | 1
(4 rows)
GROUPING関数は、ベース集計行から、または式リスト内の項目の一つが表現は、1つ以上のヌルである基づいている列の結果としてnullを返す特定の小計行の小計行を区別するために使用することができます列の小計を表すのではなく、表の行を使用します。
この点を説明するために、次の行が empテーブルに追加されています。これにより、 ジョブ列にヌル値を持つ行が提供されます。
INSERT INTO emp (empno,ename,deptno) VALUES (9004,'PETERS',40);
明確にするために、減少した行数を使用して次のクエリが発行されます。
SELECT loc, job, COUNT(*) AS "employees",
GROUPING(loc) AS "gf_loc",
GROUPING(job) AS "gf_job"
FROM emp e, dept d
WHERE e.deptno = d.deptno AND loc = 'BOSTON'
GROUP BY CUBE (loc, job)
ORDER BY 1, 2;
出力には、 BOSTONloc列に、スペースがジョブ列に含まれる2つの行 (表の4番目と5番目の項目) が含まれていることに注意してください
loc | job | employees | gf_loc | gf_job
--------+---------+-----------+--------+--------
BOSTON | ANALYST | 3 | 0 | 0
BOSTON | CLERK | 3 | 0 | 0
BOSTON | MANAGER | 2 | 0 | 0
BOSTON | | 1 | 0 | 0
BOSTON | | 9 | 0 | 1
| ANALYST | 3 | 1 | 0
| CLERK | 3 | 1 | 0
| MANAGER | 2 | 1 | 0
| | 1 | 1 | 0
| | 9 | 1 | 1
(10 rows)
ジョブ列( gf_job GROUPING関数が1を返す5番目の行は、これがすべてのジョブの小計であることを示します。行には、 employees列に小計の値9が含まれていることに注意してください。
ジョブ列とloc GROUPING関数が0を返す4番目の行は、 locBOSTONjobがnull(この例では挿入された行)であるすべての行の基本集約であることを示します。 従業員の列には、挿入されたそのような単一の行のカウントである1が含まれます。
また、9行目(次の最後まで)に注意 LOCカラム上でグループ化機能は、これがジョブ列がヌルであるすべての場所の上に小計であることを示す1を返しながら、 ジョブ列GROUPING関数は再び、であり、0を返しますこの例で挿入された単一行のカウント。
 
2.2.6.5 GROUPING_IDファンクション
GROUPING_ID関数は、拡張を設定 ROLLBACK、CUBE、またはGROUPINGからの結果セット内の行の小計レベルを決定するために、GROUPING関数の簡略化を提供します。
GROUPING関数は1列のみ発現を取り、列が与えられた列のすべての値にわたって小計であるか否かの指示を返します。したがって、複数のグループ化機能を持つクエリの小計のレベルを解釈するには、複数のGROUPING関数が必要になることがあります。
GROUPING_ID関数ROLLBACK、 キューブに使用されている1つ以上の列表現を受け入れる、またはグループ化の拡張機能を設定し、これらの列の小計が集約されたオーバーを決定するために使用することができる単一の整数を返します。
GROUPING_ID関数の一般的な構文は次のようになります。
SELECT [ expr ...,]
GROUPING_ID( col_expr_1 [, col_expr_2 ] ... )
[, expr ] ...
FROM ...
GROUP BY [...,]
{ ROLLUP | CUBE | GROUPING SETS }( [...,] col_expr_1
[, col_expr_2 ] [, ...] ) [, ...]
GROUPING_ID機能ROLLUP、CUBE、またはGROUPINGの式リストに指定されたディメンション列の式でGROUP BY句の拡張機能を設定しなければならない1つ以上のパラメータを取ります。
GROUPING_ID関数は、整数値を返します。この値は、 GROUPING_IDで指定されたパラメータの順序と同じ左から右の順序で指定された一連のGROUPING関数によって返される、連結された1と0からなるビットベクトルのベース10解釈に対応します関数。
次のクエリは 、列gidで表されるGROUPING_ID関数の戻り値が、locおよびdnameの 2つのGROUPING関数によって返された値にどのように対応するかを示しています。
SELECT loc, dname, COUNT(*) AS "employees",
GROUPING(loc) AS "gf_loc", GROUPING(dname) AS "gf_dname",
GROUPING_ID(loc, dname) AS "gid"
FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY CUBE (loc, dname)
ORDER BY 6, 1, 2;
次の出力では、 gf_loc値とgf_dname値で構成されるビットベクトルgidで指定された整数との比較を確認してください。
loc | dname | employees | gf_loc | gf_dname | gid
----------+------------+-----------+--------+----------+-----
BOSTON | OPERATIONS | 3 | 0 | 0 | 0
BOSTON | RESEARCH | 5 | 0 | 0 | 0
CHICAGO | SALES | 6 | 0 | 0 | 0
NEW YORK | ACCOUNTING | 3 | 0 | 0 | 0
BOSTON | | 8 | 0 | 1 | 1
CHICAGO | | 6 | 0 | 1 | 1
NEW YORK | | 3 | 0 | 1 | 1
| ACCOUNTING | 3 | 1 | 0 | 2
| OPERATIONS | 3 | 1 | 0 | 2
| RESEARCH | 5 | 1 | 0 | 2
| SALES | 6 | 1 | 0 | 2
| | 17 | 1 | 1 | 3
(12 rows)
以下の表は、特定の例を提供出力の4行のGROUPING関数の戻り値に基づいて、GROUPING_ID関数の計算を。
loc
gid
0 * 2 1 + 0 * 2 0
0
0 * 2 1 + 1 * 2 0
1
1 * 2 1 + 0 * 2 0
2
1 * 2 1 + 1 * 2 0
3
次の表は、 GROUPING_IDファンクションの戻り値が、集計が行われるグループ化列に対応する方法をまとめたものです。
gid
0 0
0
loc
0 1
1
1 0
2
1 1
3
したがって、 dname小計のみを表示するには、 GROUPING_ID関数に基づいてHAVING句を使用して、次の簡略化されたクエリを使用できます。
SELECT loc, dname, COUNT(*) AS "employees",
GROUPING(loc) AS "gf_loc", GROUPING(dname) AS "gf_dname",
GROUPING_ID(loc, dname) AS "gid"
FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY CUBE (loc, dname)
HAVING GROUPING_ID(loc, dname) = 2
ORDER BY 6, 1, 2;
クエリの結果は次のとおりです。
loc | dname | employees | gf_loc | gf_dname | gid
-----+------------+-----------+--------+----------+-----
| ACCOUNTING | 3 | 1 | 0 | 2
| OPERATIONS | 3 | 1 | 0 | 2
| RESEARCH | 5 | 1 | 0 | 2
| SALES | 6 | 1 | 0 | 2
(4 rows)
2.3 プロファイル管理
Advanced Serverを使用すると、データベースのスーパーユーザーは、 プロファイル 。各プロファイルは、 パスワードmd5認証を強化するパスワード管理のルールを定義しています。プロファイル内のルールは次のことができます。
プロファイルは、同等の認証要件を共有するロールのグループを簡単に管理できるようにする、名前付きの一連のパスワード属性です。パスワード要件が変更された場合、そのプロファイルに関連付けられている各ユーザーに新しい要件が適用されるようにプロファイルを変更できます。
プロファイルを作成したら、そのプロファイルを1人以上のユーザーに関連付けることができます。ユーザーがサーバーに接続すると、サーバーはログインロールに関連付けられているプロファイルを適用します。プロファイルはクラスタ内のすべてのデータベースで共有されますが、各クラスタには複数のプロファイルが存在する場合があります。複数のデータベースにアクセスできる1人のユーザーは、クラスタ内の各データベースに接続するときに同じプロファイルを使用します。
Advanced Serverは 、代替プロファイルが指定されていない限り、ロールの作成時に新しいロールに関連付けられた defaultという名前のプロファイルを作成します。以前のサーバーバージョンからAdvanced Serverにアップグレードすると、既存のロールが自動的にデフォルトプロファイルに割り当てられます 既定の プロファイル は削除できません
デフォルトの プロファイルは、次の属性を指定します。
FAILED_LOGIN_ATTEMPTS 無制限
PASSWORD_LOCK_TIME 無制限
PASSWORD_LIFE_TIME無制限
PASSWORD_GRACE_TIME無制限
PASSWORD_REUSE_TIME無制限
PASSWORD_REUSE_MAX無制限
PASSWORD_VERIFY_FUNCTION NULL
データベースのスーパーユーザーは、 ALTER PROFILE コマンドを 使用 して、 デフォルト プロファイルで 指定された値を変更します 。プロファイルの変更の詳細については、 2.3.2 項を参照してください
 
2.3.1 新規プロファイルの作成
新しいプロファイルを作成するには、 CREATE PROFILEコマンドを使用します。構文は次のとおりです。
CREATE PROFILE profile_name
[LIMIT { パラメータ } ...];
Advanced Serverによって実行されるルールを指定するには LIMIT 句と1つ以上のスペース区切り パラメータ / 値の ペアを 含め ます。
パラメーター:
profile_nameは、プロファイルの名前を指定します。
パラメータ は、プロファイルによって制限される属性を指定します。
value はパラメータの制限を指定します。
Advanced Serverは、 パラメータ について以下 値を サポートしてい ます
FAILED_LOGIN_ATTEMPTSは、サーバーがPASSWORD_LOCK_TIMEで指定された時間、アカウントからユーザーをロックする前に、ユーザーが失敗したログイン試行の回数を指定します。サポートされる値は次のとおりです。
0 以上 の整数
DEFAULT - DEFAULT プロファイルで 指定された FAILED_LOGIN_ATTEMPTS の値
無制限 - 接続しているユーザーは、失敗したログイン試行回数を無制限にすることがあります。
PASSWORD_LOCK_TIME は、サーバーが FAILED_LOGIN_ATTEMPTSの ためにロックされたアカウントのロックを解除するまでの時間を指定します サポートされる値は次のとおりです。
0以上 数値 。 1日の小数部分を指定するには、小数値を指定します。たとえば、値4.5を使用して412時間を指定します。
DEFAULT - DEFAULTプロファイルで指定されたPASSWORD_LOCK_TIMEの値。
無制限 -アカウントはデータベーススーパーユーザーによって手動でロック解除されるまでロックされます。
PASSWORD_LIFE_TIMEは、ユーザーに新しいパスワードを入力する前に現在のパスワードを使用する日数を指定します。 PASSWORD _ LIFE _ TIME句を使用する場合は、 PASSWORD _ GRACE _ TIME句を含めて、ロールによる接続が拒否されるまでにパスワードが期限切れになってから経過する日数を指定します。 PASSWORD _ GRACE _ TIMEが指定されていない場合、パスワードはPASSWORD _ GRACE _ TIMEのデフォルト値で指定された日に期限切れになり、ユーザーは新しいパスワードが提供されるまでコマンドを実行できなくなります。サポートされる値は次のとおりです。
0 以上 数値 1日の小数部分を指定するには、小数値を指定します。たとえば、値4.5を使用して412時間を指定します。
DEFAULT - DEFAULT プロファイルで 指定された PASSWORD_LIFE_TIME の値
無制限 - パスワードの有効期限はありません。
PASSWORD_GRACE_TIME パスワードが期限切れになった後、ユーザがパスワードを変更するまでの猶予期間の長さを示します。猶予期間が切れると、ユーザーは接続を許可されますが、期限切れのパスワードを更新するまでコマンドを実行することはできません 。サポートされる値は次のとおりです。
0 以上 数値 1日の小数部分を指定するには、小数値を指定します。たとえば、値4.5を使用して412時間を指定します。
DEFAULT - DEFAULT プロファイルで 指定された PASSWORD_GRACE_TIME の値
無制限 - 猶予期間は無限です。
PASSWORD_REUSE_TIME、ユーザーがパスワードを使用するまで待機する日数を指定ます。 PASSWORD _ REUSE _ TIMEPASSWORD _ REUSE _ MAXパラメーターは、一緒に使用するためのものです。これらのパラメータの1つに有限値を指定し、他のパラメータを無制限に指定すると 、古いパスワードを決して再利用することはできません。両方のパラメータがUNLIMITEDに設定されている場合は、パスワードの再利用に制限はありません。サポートされる値は次のとおりです。
0 以上 数値 1日の小数部分を指定するには、小数値を指定します。たとえば、値4.5を使用して412時間を指定します。
DEFAULT - DEFAULT プロファイルで 指定された PASSWORD_REUSE_TIME の値
無制限 - パスワードは制限なしで再利用できます。
PASSWORD_REUSE_MAX、パスワードを再利用できるようにするために必要なパスワードの変更回数を指定します。 PASSWORD _ REUSE _ TIMEPASSWORD _ REUSE _ MAXパラメーターは、一緒に使用するためのものです。これらのパラメータの1つに有限値を指定し、他のパラメータを無制限に指定すると 、古いパスワードを決して再利用することはできません。両方のパラメータがUNLIMITEDに設定されている場合は、パスワードの再利用に制限はありません。サポートされる値は次のとおりです。
0 以上 INTEGER
DEFAULT - DEFAULT プロファイルで 指定された PASSWORD_REUSE_MAX の値
無制限 - パスワードは制限なしで再利用できます。
PASSWORD_VERIFY_FUNCTIONはパスワードの複雑さを指定します。サポートされる値は次のとおりです。
DEFAULT - DEFAULT プロファイルで 指定された PASSWORD_VERIFY_FUNCTION の値
ノート
プロファイルを削除するには、 DROP PROFILEコマンドを使用します。
次のコマンドは、 acctg という名前のプロファイルを作成します 。このプロファイルでは、ユーザーが5回の試行で正しいパスワードで認証されなかった場合、そのアカウントは1日ロックされます。
CREATE PROFILE acctg LIMIT
FAILED_LOGIN_ATTEMPTS 5
PASSWORD_LOCK_TIME 1;
次のコマンドは、 sales という名前のプロファイルを作成します 。プロファイルでは、90日ごとにパスワードを変更する必要があることを指定しています。
CREATE PROFILE sales LIMIT
PASSWORD_LIFE_TIME 90
PASSWORD_GRACE_TIME 3;
プロファイルで指定された90日が経過する前にユーザーがパスワードを変更していない場合は、ログイン時に警告が表示されます。 3日間の猶予期間が経過すると、パスワードを変更するまでアカウントのコマンドを呼び出すことができなくなります。
次のコマンドは、 accts という名前のプロファイルを作成します 。このプロファイルでは、パスワードを最後に使用してから180日以内にユーザーがパスワードを再使用できないように指定しています。パスワードを再使用する前に少なくとも5回パスワードを変更する必要があります。
CREATE PROFILE accts LIMIT
PASSWORD_REUSE_TIME 180
PASSWORD_REUSE_MAX 5;
次のコマンドは、 resources という名前のプロファイルを作成します 。プロファイルは、指定されたパスワードが複雑さの基準を満たしていることを確認するpassword_rulesという名前のユーザー定義関数を呼び出します。
CREATE PROFILE resources LIMIT
PASSWORD_VERIFY_FUNCTION password_rules;
2.3.1.1 パスワード機能の作成
指定する場合 PASSWORD_VERIFY_FUNCTIONを、あなたは、ユーザーが自分のパスワードを変更するときに適用されるセキュリティルールを指定し、カスタマイズ機能を提供することができます。たとえば、新しいパスワードが少なくともn文字以上でなければならず、特定の値を含まないようにするルールを指定できます。
パスワード関数のシグネチャは次のとおりです。
function _ name ユーザー _ VARCHAR2、
新しい _ パスワード VARCHAR2、
old _ password VARCHAR2)RETURNブール値
場所:
user _ nameユーザーの 名前です。
new _ passwordは新しいパスワードです。
old _ passwordはユーザーの以前のパスワードです。関数内でこのパラメータを参照する場合は、次のようにします。
データベースのスーパーユーザーがパスワードを変更すると、3番目のパラメータは常に NULLに なり ます
CREATEROLE属性を持つ ユーザーがパスワードを変更すると、その文にREPLACE句が含まれている場合、パラメータは以前のパスワードを渡します。 REPLACE句は、 CREATEROLE権限を持つユーザのオプションの構文です
データベーススーパーユーザーではなく、 CREATEROLE属性を持たないユーザーがパスワードを変更すると、3番目のパラメータにロールの以前のパスワードが含まれます。
この関数はブール値を返します。関数がtrueを返し、例外を発生しない場合、パスワードは受け入れられます。関数がfalseを返すか、例外を発生させると、パスワードは拒否されます。関数が例外を発生させると、指定されたエラーメッセージがユーザーに表示されます。関数が例外を発生させずにfalseを返す場合は、次のエラーメッセージが表示されます。
エラー:指定されたパスワードのパスワード検証に失敗しました
この関数は、データベーススーパーユーザーが所有し、 sysスキーマに存在する必要があります。
例:
次の例では、プロファイルとカスタム関数を作成します。その関数はプロファイルに関連付けられます。次の CREATE PROFILEコマンドは、 acctg _ pwd _ profileという名前のプロファイルを作成します
CREATE PROFILE acctg_pwd_profile;
次のコマンドは、 verify_password という名前の(スキーマ修飾された)関数を作成します
CREATE OR REPLACE FUNCTION sys.verify_password(user_name varchar2, new_password varchar2, old_password varchar2)
RETURN boolean IMMUTABLE
IS
BEGIN
IF (length(new_password) < 5)
THEN
raise_application_error(-20001, 'too short');
END IF;


IF substring(new_password FROM old_password) IS NOT NULL
THEN
raise_application_error(-20002, 'includes old password');
END IF;


RETURN true;
END;
この関数は、最初にパスワードの長さが5文字以上であることを確認してから、新しいパスワードと古いパスワードを比較します。新しいパスワードが5文字未満または古いパスワードを含む場合、関数はエラーを発生させます。
次の文は、 verify _ password関数の所有権を enterprisedbデータベースのスーパーユーザーに設定します。
ALTER FUNCTION verify_password(varchar2, varchar2, varchar2) OWNER TO enterprisedb;
その後、 検証 _ パスワード機能は、プロファイルに関連付けられています。
ALTER PROFILE acctg_pwd_profile LIMIT PASSWORD_VERIFY_FUNCTION verify_password;
次のステートメントは、最初にテストユーザー( alice )を作成し、無効で有効なパスワードを自分の役割に関連付けることによって、この機能が動作していることを確認します。
CREATE ROLE alice WITH LOGIN PASSWORD 'temp_password' PROFILE acctg_pwd_profile;
次に、 アリスがデータベースに接続してパスワードを変更しようとすると、彼女はプロファイル関数によって確立された規則に従わなければなりません。 CREATEROLEのないスーパーユーザー以外のユーザーは、パスワードを変更するときにREPLACE句を含める必要があります。
edb=> ALTER ROLE alice PASSWORD 'hey';
ERROR: missing REPLACE clause
新しいパスワードは5文字以上でなければなりません:
edb=> ALTER USER alice PASSWORD 'hey' REPLACE 'temp_password';
ERROR: EDB-20001: too short
CONTEXT: edb-spl function verify_password(character varying,character varying,character varying) line 5 at procedure/function invocation statement
 
新しいパスワードが受け入れ可能な場合、コマンドはエラーなしで完了します。
edb=> ALTER USER alice PASSWORD 'hello' REPLACE 'temp_password';
ALTER ROLE
アリス が自分のパスワードを変更することにした 場合 、新しいパスワードに古いパスワードが含まれていてはなりません。
edb=> ALTER USER alice PASSWORD 'helloworld' REPLACE 'hello';
ERROR: EDB-20002: includes old password
CONTEXT: edb-spl function verify_password(character varying,character varying,character varying) line 10 at procedure/function invocation statement
verify関数を削除するには、 password _ verify _ functionNULL に設定ます
ALTER PROFILE acctg_pwd_profile LIMIT password_verify_function NULL;
次に、すべてのパスワード制約が解除されます。
edb=# ALTER ROLE alice PASSWORD 'hey';
ALTER ROLE
 
2.3.2 プロファイルの変更
ユーザー定義プロファイルを変更するには、 ALTER PROFILEコマンドを使用します。 Advanced Serverは、次の2つの形式のコマンドをサポートしています。
PROFILE ALTER new_name PROFILE_NAMEの RENAMEを
 
ALTER PROFILE profile_name
LIMIT {
パラメータ値 } [...];
Advanced Serverによって実行されるルールを指定するには LIMIT 句と1つ以上のスペース区切り パラメータ / 値の ペアを 含める か、 ALTER PROFILE ... RENAME TOを使用してプロファイルの名前を変更します。
パラメーター:
profile_nameは、プロファイルの名前を指定します。
new_nameは、プロファイルの新しい名前を指定します。
パラメータ は、プロファイルによって制限される属性を指定します。
value はパラメータの制限を指定します。
受け入れられたパラメータと値のペアの完全なリストについては、 2.3.1 項の表を参照してください
次の例では、 acctg_profile という名前のプロファイルを変更します
ALTER PROFILE acctg_profile
LIMIT FAILED_LOGIN_ATTEMPTS 3 PASSWORD_LOCK_TIME 1;
 
ログインロールがサーバへの接続を試みると、 acctg_profileは失敗した接続試行回数をカウントします。このプロファイルでは、ユーザーが3回の試行で正しいパスワードで認証されなかった場合、そのアカウントは1日ロックされるように指定されています。
次の例では、名前の変更 payables_profileacctg_profileを
ALTER PROFILE acctg_profile RENAME TO payables_profile;
 
2.3.3 プロファイルの削除
DROPを 使用する PROFILE コマンドを使用してプロファイルを削除します。構文は次のとおりです。
プロフィールを削除する[存在する場合] profile_name [CASCADE | RESTRICT];
IFを 含める 指定されたプロファイルが存在しない場合、サーバーにエラーをスローしないように指示する EXISTS 句。プロファイルが存在しない場合、サーバーは通知を出します。
オプションの CASCADE 句を 含めて 、プロファイルに現在関連付けられているユーザーをすべて デフォルトの プロファイル に再割り当てし、プロファイルを 削除しますオプションの RESTRICT 句を 含めて 、ロールに関連付けられたプロファイルを削除しないようにサーバーに指示します。これがデフォルト動作です。
パラメーター
プロファイル名
削除されるプロファイルの名前。
次の例では、 acctg_profile という名前のプロファイルを削除します
DROP PROFILE acctg_profile CASCADE;
 
コマンドに関連付けられた最初の再関連付けどんな役割デフォルトのプロファイルを使用してacctg_profileプロファイル 、およびacctg_profileプロファイルを削除します。
次の例では、 acctg_profile という名前のプロファイルを削除します
DROP PROFILE acctg_profile RESTRICT;
 
このコマンド RESTRICT句は、プロファイルに関連付けられているロールがある場合、 acctg_profileを削除しないようにサーバーに指示します。
 
2.3.4 プロファイルを既存のロールに関連付ける
プロファイルを作成した後、 ALTER USER ... PROFILEまたはALTER ROLE ... PROFILEコマンドを使用して、プロファイルをロールに関連付けることができます 。プロファイル管理機能に関連するコマンド構文は次のとおりです。
ALTER USER | ROLE name [[WITH]オプション[...]
どこ オプションは、 次の互換性の句を指定できます。
PROFILE profile_name
|アカウント{LOCK | UNLOCK}
| PASSWORD EXPIRE [AT ' タイムスタンプ ]
または オプション は、次の互換性のない節に する ことができます。
| 「 タイムスタンプ 」に設定された パスワード
|ロックタイム ' タイムスタンプ '
|ストア前 のパスワード { 'パスワード' 'タイムスタンプ } [、...]
Advanced ServerでサポートされているALTER USERコマンドまたはALTER ROLEコマンドの管理句については 、次のURLにあるPostgreSQLのコアドキュメントを参照してください。
https://www.postgresql.org/docs/11/static/sql-commands.html
データベースのスーパーユーザーだけが ALTER を使用できます ユーザー | プロファイル管理を実施する ROLE この条項は、次のような行動を強制します。
事前定義されたプロファイルを役割に関連付ける、または事前定義されたプロファイルがユーザーに関連付けられていることを変更するには、 PROFILE句とprofile_name含めます。
ACCOUNT句とLOCKまたはUNLOCKキーワードを含めて、ユーザー・アカウントをロック状態またはロック解除状態にする必要があることを指定します。
インクルードこのロールに割り当てられたプロファイルのTIMEパラメータ _ _ LOCK指定した時刻に役割をロックするLOCK TIME「 タイムスタンプ 句と日付/時刻値を、およびPASSWORDで示される時点で役割のロックを解除します。 LOCK TIMEを ACCOUNT LOCK句とともに使用すると、ロールはACCOUNT UNLOCK句を使用してデータベースのスーパーユーザーのみがロックを解除できます
パスワードを 含める ATの EXPIRE ' timestamp ' キーワードを使用して、ロールに関連付けられたパスワードの有効期限が切れる日時を指定します。 AT を省略すると ' timestamp ' キーワードを入力すると、パスワードはすぐに期限切れになります。
パスワードを 含める セット AT ' timestamp ' キーワードを使用して、パスワード修正日を指定された時間に設定します。
ストアを 含める 先行 パスワード { 'パスワード' 'タイムスタンプ } [、...] 新しいパスワードとパスワードが設定された時刻を追加します。
各ログインロールは1つのプロファイルのみを持つことができます。現在ログイン・ロールに関連付けられているプロファイルを検出するには、 DBA_USERSビューのプロファイル列を問い合せます。
パラメーター
指定されたプロファイルが関連付けられるロールの名前。
パスワード
ロールに関連付けられたパスワード。
プロファイル名
ロールに関連付けられるプロファイルの名前。
タイムスタンプ
条項が適用される日時。 タイムスタンプの 値を指定する場合は 、値を一重引用符で囲みます。
次のコマンドは、 ALTER USER ... PROFILEコマンドを使用して、 acctgという名前のプロファイルをjohnという名前のユーザーに関連付けます。
ALTER USER john PROFILE acctg_profile;
次のコマンドは、 ALTER ROLE ... PROFILEコマンドを使用して、 acctgという名前のプロファイルをjohnという名前のユーザーに関連付けます。
ALTER ROLE john PROFILE acctg_profile;
 
2.3.5 ロックされたアカウントのロック解除
データベース・スーパーユーザーは 、ロールをロックまたはロック解除するために、 ALTER USER | ROLE ...コマンドの句を使用できます 。構文は次のとおりです。
ALTER ユーザー|役割
アカウント
{LOCK | UNLOCK}
ロックタイム '
タイムスタンプ '
アカウントを 含める 直ちに役割をロックする LOCK 節。ロックされると、ロールの LOGIN 機能は無効になります。 アカウント を指定すると LOCK TIME句が指定されていないLOCK句では、スーパーユーザが ACCOUNTを 使用するまでロールの状態は変更されません UNLOCK 句を使用してロールを解除します。
アカウントを 使用する UNLOCK 句を使用してロールを解除します。
ロックを 使用する 時間 ' timestamp ' は、このロールに関連付けられたプロファイルの PASSWORD_LOCK_TIME パラメータで 指定された時間だけ、指定されたタイムスタンプで指定された時刻にアカウントをロックするようにサーバーに指示します
ロックを 組み合わせる TIME ' timestamp ' 句と ACCOUNT ACCOUNT を呼び出すスーパーユーザーによってアカウントがロック解除されるまで、指定された時間にアカウントをロックする LOCK UNLOCK 句。
パラメーター
ロックまたはロック解除されているロールの名前。
タイムスタンプ
ロールがロックされる日付と時刻。 タイムスタンプの 値を指定する場合は 、値を一重引用符で囲みます。
注意
このコマンド(Advanced Serverでのみ使用可能)は、Oracleスタイルのプロファイル管理をサポートするために実装されています。
 
 
次の例では、 ACCOUNT LOCK句を使用して johnという名前のロールをロックします。 ACCOUNT UNLOCK句を使用してアカウントがロック解除されるまで、アカウントはロックされたままです。
ALTER ROLE john ACCOUNT LOCK;
次の例では、 ACCOUNT UNLOCK 句を 使用して john という名前のロールをロック解除し ます。
ALTER USER john ACCOUNT UNLOCK;
次の例では、 LOCK 時間 2015年9月4日にjohnという名前のロールをロックするための' timestamp '
ALTER ROLE john LOCK TIME ‘September 4 12:00:00 2015’;
ロールは、 PASSWORD _ LOCK _ TIME パラメーターで 指定された時間だけロックされたまま です。
次の例では、 LOCK 時間 ' timestamp ' 句と ACCOUNT LOCK句を使用して、2015年9月4日にjohnという名前のロールをロックします。
ALTER ROLE john LOCK TIME ‘September 4 12:00:00 2015’ ACCOUNT LOCK;
ロールは、データベーススーパーユーザーが アカウントを 使用するまでロックされたままです UNLOCK コマンドを使用して役割のロックを解除します。
 
2.3.6 プロファイルに関連付けられた新しいロールの作成
データベース・スーパー・ユーザーは、 CREATE USER | CREATE USER 節の句を使用できますROLEコマンドを使用して、ロールの作成時に名前付きプロファイルをロールに割り当てたり、ロールのプロファイル管理の詳細を指定することができます。プロファイル管理機能に関連するコマンド構文は次のとおりです。
CREATE USER | ROLE name [[WITH] オプション [...]]
どこ オプションは、次の互換性の句を指定できます。
PROFILE profile_name
|アカウント{LOCK | UNLOCK}
| PASSWORD EXPIRE [AT ' タイムスタンプ ]
または オプションは、次の互換性のない節にすることができます。
|ロックタイム ' タイムスタンプ '
Advanced ServerでサポートされているCREATE USERまたはCREATE ROLEコマンドの管理句の詳細については、次のURLにあるPostgreSQLのコアドキュメントを参照してください。
https://www.postgresql.org/docs/11/static/sql-commands.html
CREATE ROLE | USER ... PROFILEは、関連するプロファイルとともに新しい役割をAdvanced Serverデータベースクラスタに追加します。
CREATEで 作成されたロール USER コマンドはログインロールです(デフォルト)。 CREATEで 作成されたロール ROLE コマンドは(デフォルトでは)ログインロールではありません。 CREATE を使用してログインアカウントを作成するには ROLE コマンドを使用するには、 LOGIN キーワードを 含める必要があります
データベーススーパーユーザーだけが CREATE を使用できます。 ユーザー | プロファイル管理を実施する ROLE これらの条項は次のような行動を強制します:
事前定義されたプロファイルを役割に関連付ける、または事前定義されたプロファイルがユーザーに関連付けられていることを変更するには、 PROFILE句とprofile_name含めます。
ACCOUNT句とLOCKまたはUNLOCKキーワードを含めて、ユーザー・アカウントをロック状態またはロック解除状態にする必要があることを指定します。
インクルードこのロールに割り当てられたプロファイルのTIMEパラメータ _ _ LOCK指定した時刻に役割をロックするLOCK TIME「 タイムスタンプ 句と日付/時刻値を、およびPASSWORDで示される時点で役割のロックを解除します。 LOCK TIMEを ACCOUNT LOCK句とともに使用すると、ロールはACCOUNT UNLOCK句を使用してデータベースのスーパーユーザーのみがロックを解除できます
パスワードを 含める オプションの ATを 持つ EXPIRE ' timestamp ' キーワードを使用して、ロールに関連付けられたパスワードの有効期限が切れる日時を指定します。 AT を省略すると ' timestamp ' キーワードを入力すると、パスワードはすぐに期限切れになります。
各ログインロールは1つのプロファイルのみを持つことができます。現在ログイン・ロールに関連付けられているプロファイルを検出するには、 DBA_USERSビューのプロファイル列を問い合せます。
パラメーター
ロールの名前。
プロファイル名
ロールに関連付けられたプロファイルの名前。
タイムスタンプ
条項が適用される日時。 タイムスタンプの 指定する場合 、値を一重引用符で囲みます。
次の例では、 CREATE USERを使用して、 acctg_profileプロファイルに関連付けられたjohnというログイン・ロールを作成します。
CREATE USER john PROFILE acctg_profile IDENTIFIED BY “1safepwd”;
johnはパスワード1safepwdを使用してサーバーにログインできます。
次の例では、 CREATE ROLEを使用して、 acctg_profileプロファイルに関連付けられたjohnというログイン・ロールを作成します。
CREATE ROLE john PROFILE acctg_profile LOGIN PASSWORD “1safepwd”;
johnはパスワード1safepwdを使用してサーバーにログインできます。
 
2.3.7 プロファイル管理機能のバックアップ
プロファイルには、 Advanced Serverによって強制される動作を指定するユーザー定義関数を参照する PASSWORD _ VERIFY _ FUNCTIONが含まれます。 プロファイルはグローバルオブジェクトです。それらはクラスタ内のすべてのデータベースによって共有されます。プロファイルはグローバルオブジェクトですが、ユーザー定義関数はデータベースオブジェクトです。
-gまたは-rオプションを指定して pg_dumpall呼び出すと、既存のプロファイルの定義を再作成するスクリプトが作成されますが、 PASSWORD _ VERIFY _ FUNCTION 句で 参照されるユーザー定義関数は再作成されません これらの関数が存在するデータベースを明示的にダンプ(および後で復元)するには、 pg_dumpユーティリティを使用する必要があります。
pg_dump によって作成されたスクリプトは、句と関数名を含むコマンドを含みます:
ALTER PROFILE ... LIMIT PASSWORD_VERIFY_FUNCTION function_name
復元された機能を以前に関連付けられたプロファイルに関連付けることができる。
PASSWORD_VERIFY_FUNCTION句がDEFAULTまたはNULLに設定されている場合、動作はpg_dumpall -gまたはpg_dumpall -r コマンドによって生成されたスクリプトによって複製されます。
 
2.4 オプティマイザのヒント
DELETE INSERT SELECT または UPDATE コマンド を呼び出す と、サーバーは一連の実行計画を生成します。それらの実行計画を分析した後、サーバーは、(最も)最も時間のかかる結果セットを返すプランを選択します。サーバーの計画の選択は、いくつかの要素に依存します。
postgresql.conf ファイルの Query Tuning セクションの パラメータに割り当てられたパラメータ値
原則として、クエリプランナは最もコストの安いプランを選択します。 オプティマイザ を使用することができます クエリプランを選択するときにサーバーに影響を与える ヒント 。オプティマイザ・ヒントは、 DELETE INSERT SELECT または UPDATE コマンドの 直後にあるコメントのような構文に埋め込まれたディレクティブ(または複数のディレクティブ) です。コメント内のキーワードは、結果セットを作成するときに特定のプランを採用または回避するようサーバーに指示します。
シノプシス
{DELETE | INSERT | SELECT | UPDATE} / * + { ヒント [ コメント ]} [...] * /
ステートメント_ボディー
 
{DELETE | INSERT | SELECT | UPDATE} - + { ヒント [ コメント ]} [...]
ステートメント_ボディー
オプティマイザヒントは、上記のいずれかのフォームに含めることができます。どちらの形式でも、スペースが挿入されていない/ *または-開始コメントシンボルの直後にプラス記号( + )を付ける必要があります。そうしないと、サーバーは次のトークンをヒントとして解釈しません。
最初のフォームを使用している場合は、ヒントとオプションのコメントが複数の行にまたがることがあります。 2番目の形式では、すべてのヒントとコメントが1行に収まる必要があります。ステートメントの残りの部分は新しい行から開始する必要があります。
説明
ご注意ください:
ヒントはコメント内に埋め込まれています。結果として、ヒントのスペルが間違っている場合や、ビュー、表、列名などのヒントのパラメータのスペルが間違っている場合や、 SQLコマンドに存在しない場合は、何らかのエラーが発生したことが示されません。構文エラーはなく、ヒント全体が単に無視されます。
SQLコマンドでテーブル名またはビュー名にエイリアスを使用する場合は、ヒントで元のオブジェクト名ではなくエイリアス名を使用する必要があります。たとえば、コマンドのSELECT / * + FULL(acct)* / * FROM accounts acct ...、 acctアカウントのエイリアスは、テーブル名ではなく、 FULLヒントで指定する必要があります
ヒントが正しく形成され、プランナーがヒントを使用していることを確認するには、 EXPLAINコマンドを使用します。 Advanced Serverを参照してください。 EXPLAINコマンドについては、ドキュメンテーション・セットを参照してください
一般に、オプティマイザ・ヒントは、本番アプリケーション(テーブル・データがアプリケーションの存続期間を通して変化する)で使用するべきではありません。動的列が頻繁に分析さ れることを保証することによって 、列統計は値の変更を反映するように更新され、プランナはそのような情報を使用して、任意のコマンド実行のための最小コスト計画を作成します。オプティマイザ・ヒントを使用すると、このプロセスの目的が無効になり、テーブル・データの変更方法にかかわらず、同じ計画になります。
パラメーター
ヒント
オプティマイザ・ヒント・ディレクティブ。
コメント
追加情報を含む文字列。注釈にはどのような文字が含まれるかについての制限があることに注意してください。一般的に、 コメントはアルファベット、数字、アンダースコア、ドル記号、数字記号、および空白文字のみで構成されます。これらはまた、識別子の構文に準拠しなければならない。コメントがこのフォームにない場合、後続のヒントはすべて無視されます。
ステートメント_ボディー
DELETEINSERTSELECT 、またはUPDATEコマンドの残りの部分
以降のセクションでは、オプティマイザのヒント・ディレクティブについて詳しく説明します。
 
2.4.1 デフォルトの最適化モード
Advanced Serverデータベースクラスタのデフォルト設定として選択できるいくつかの最適化モードがあります。この設定は、オプティマイザ・ヒント内の個々のDELETESELECTおよびUPDATEコマンドと同様に、 ALTER SESSIONコマンドを使用して、セッションごとに変更することもできます。これらのデフォルト・モードを制御する構成パラメーターの名前はOPTIMIZER_MODEです。次の表に、使用可能な値を示します。
表2-1デフォルトの最適化モード
結果セットの 最初の n 行の 検索用に最適化し ます。このフォームは、 ALTER SESSION SET OPTIMIZER_MODE コマンドの オブジェクトとして使用できません 。これは、 SQL コマンド 内のヒントの形式でのみ使用でき ます
これらの最適化モードは、 SQLコマンドを送信するクライアントが結果セットの最初の "n"行だけを表示することに関心があり、結果セットの残りを放棄するという仮定に基づいています 。クエリに割り当てられたリソースは、そのように調整されます。
現在のセッションを変更して、結果セットの最初の10行の取得を最適化します。
ALTER SESSION SET OPTIMIZER_MODE = FIRST_ROWS_10;
OPTIMIZER_MODEパラメータの現在の値はSHOWコマンドを使用して表示できます。このコマンドは、ユーティリティに依存するコマンドであることに注意してください。 PSQLでは、 SHOWコマンドは次のように使用されます。
SHOW OPTIMIZER_MODE;
 
optimizer_mode
----------------
first_rows_10
(1 row)
Oracleデータベースと互換性のある SHOWコマンドの構文は次のとおりです。
SHOW PARAMETER OPTIMIZER_MODE;
 
NAME
--------------------------------------------------
VALUE
--------------------------------------------------
optimizer_mode
first_rows_10
次の例は、 SELECTコマンドでヒントとして使用される最適化モードを示しています
SELECT /*+ FIRST_ROWS(7) */ * FROM emp;
 
empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+--------+-----------+------+--------------------+---------+---------+--------
7369 | SMITH | CLERK | 7902 | 17-DEC-80 00:00:00 | 800.00 | | 20
7499 | ALLEN | SALESMAN | 7698 | 20-FEB-81 00:00:00 | 1600.00 | 300.00 | 30
7521 | WARD | SALESMAN | 7698 | 22-FEB-81 00:00:00 | 1250.00 | 500.00 | 30
7566 | JONES | MANAGER | 7839 | 02-APR-81 00:00:00 | 2975.00 | | 20
7654 | MARTIN | SALESMAN | 7698 | 28-SEP-81 00:00:00 | 1250.00 | 1400.00 | 30
7698 | BLAKE | MANAGER | 7839 | 01-MAY-81 00:00:00 | 2850.00 | | 30
7782 | CLARK | MANAGER | 7839 | 09-JUN-81 00:00:00 | 2450.00 | | 10
7788 | SCOTT | ANALYST | 7566 | 19-APR-87 00:00:00 | 3000.00 | | 20
7839 | KING | PRESIDENT | | 17-NOV-81 00:00:00 | 5000.00 | | 10
7844 | TURNER | SALESMAN | 7698 | 08-SEP-81 00:00:00 | 1500.00 | 0.00 | 30
7876 | ADAMS | CLERK | 7788 | 23-MAY-87 00:00:00 | 1100.00 | | 20
7900 | JAMES | CLERK | 7698 | 03-DEC-81 00:00:00 | 950.00 | | 30
7902 | FORD | ANALYST | 7566 | 03-DEC-81 00:00:00 | 3000.00 | | 20
7934 | MILLER | CLERK | 7782 | 23-JAN-82 00:00:00 | 1300.00 | | 10
(14 rows)
 
2.4.2 アクセス方法のヒント
次のヒントは、オプティマイザがリレーションにアクセスして結果セットを作成する方法に影響します。
表2-2アクセス方法のヒント
FULL( table
INDEX( table [ index ] [...])
リレーションにアクセスするには、 table index 使用 table
NO_INDEX( table [ index ] [...])
リレーションにアクセスするため table 上の index 使用しないでください
さらに、 表2-1 ALL_ROWSFIRST_ROWS 、およびFIRST_ROWS( n )のヒントを使用できます。
サンプル・アプリケーションにはオプティマイザ・ヒントの効果を示すための十分なデータがないため、この節の残りの例では、Advanced Server binサブディレクトリにあるpgbenchアプリケーションによって作成された銀行データベースが使用されます。
次の手順では、 bank という名前のデータベースを作成し、テーブル、 pgbench_accountspgbench_branchespgbench_tellers 、およびpgbench_historyで作成します。 -s 20オプションはpgbench_accountsテーブル内2,000,000行とpgbench_branchesテーブルの20行の合計をもたらす100,000アカウントで20の分岐、それぞれの生成をもたらす20のスケーリング係数を指定します。 10人のTellerが各ブランチに割り当てられ、合計200行がpgbench_tellersテーブルに格納されます。
以下は、 銀行データベースのpgbenchアプリケーションを初期化します。
createdb -U enterprisedb bank
CREATE DATABASE
 
pgbench -i -s 20 -U enterprisedb bank
 
NOTICE: table "pgbench_history" does not exist, skipping
NOTICE: table "pgbench_tellers" does not exist, skipping
NOTICE: table "pgbench_accounts" does not exist, skipping
NOTICE: table "pgbench_branches" does not exist, skipping
creating tables...
100000 of 2000000 tuples (5%) done (elapsed 0.11 s, remaining 2.10 s)
200000 of 2000000 tuples (10%) done (elapsed 0.22 s, remaining 1.98 s)
300000 of 2000000 tuples (15%) done (elapsed 0.33 s, remaining 1.84 s)
400000 of 2000000 tuples (20%) done (elapsed 0.42 s, remaining 1.67 s)
500000 of 2000000 tuples (25%) done (elapsed 0.52 s, remaining 1.57 s)
600000 of 2000000 tuples (30%) done (elapsed 0.62 s, remaining 1.45 s)
700000 of 2000000 tuples (35%) done (elapsed 0.73 s, remaining 1.35 s)
800000 of 2000000 tuples (40%) done (elapsed 0.87 s, remaining 1.31 s)
900000 of 2000000 tuples (45%) done (elapsed 0.98 s, remaining 1.19 s)
1000000 of 2000000 tuples (50%) done (elapsed 1.09 s, remaining 1.09 s)
1100000 of 2000000 tuples (55%) done (elapsed 1.22 s, remaining 1.00 s)
1200000 of 2000000 tuples (60%) done (elapsed 1.36 s, remaining 0.91 s)
1300000 of 2000000 tuples (65%) done (elapsed 1.51 s, remaining 0.82 s)
1400000 of 2000000 tuples (70%) done (elapsed 1.65 s, remaining 0.71 s)
1500000 of 2000000 tuples (75%) done (elapsed 1.78 s, remaining 0.59 s)
1600000 of 2000000 tuples (80%) done (elapsed 1.93 s, remaining 0.48 s)
1700000 of 2000000 tuples (85%) done (elapsed 2.10 s, remaining 0.37 s)
1800000 of 2000000 tuples (90%) done (elapsed 2.23 s, remaining 0.25 s)
1900000 of 2000000 tuples (95%) done (elapsed 2.37 s, remaining 0.12 s)
2000000 of 2000000 tuples (100%) done (elapsed 2.48 s, remaining 0.00 s)
vacuum...
set primary keys...
done.
トータル500,00件のトランザクションが処理されます。これにより、 pgbench_historyテーブルに500,000行が移入されます。
pgbench -U enterprisedb -t 500000 bank
 
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 20
query mode: simple
number of clients: 1
number of threads: 1
number of transactions per client: 500000
number of transactions actually processed: 500000/500000
latency average: 0.000 ms
tps = 1464.338375 (including connections establishing)
tps = 1464.350357 (excluding connections establishing)
表の定義を以下に示します。
\d pgbench_accounts
 
Table "public.pgbench_accounts"
Column | Type | Modifiers
----------+---------------+-----------
aid | integer | not null
bid | integer |
abalance | integer |
filler | character(84) |
Indexes:
"pgbench_accounts_pkey" PRIMARY KEY, btree (aid)
 
\d pgbench_branches
 
Table "public.pgbench_branches"
Column | Type | Modifiers
----------+---------------+-----------
bid | integer | not null
bbalance | integer |
filler | character(88) |
Indexes:
"pgbench_branches_pkey" PRIMARY KEY, btree (bid)
 
\d pgbench_tellers
 
Table "public.pgbench_tellers"
Column | Type | Modifiers
----------+---------------+-----------
tid | integer | not null
bid | integer |
tbalance | integer |
filler | character(84) |
Indexes:
"pgbench_tellers_pkey" PRIMARY KEY, btree (tid)
 
\d pgbench_history
 
Table "public.pgbench_history"
Column | Type | Modifiers
--------+-----------------------------+-----------
tid | integer |
bid | integer |
aid | integer |
delta | integer |
mtime | timestamp without time zone |
filler | character(22) |
EXPLAINコマンドは問い合わせプランナによって選択されたプランを示しています。次の例では、 aidが主キー列であるため、索引検索はpgbench_accounts_pkey索引で使用されます。
EXPLAIN SELECT * FROM pgbench_accounts WHERE aid = 100;
 
QUERY PLAN
-----------------------------------------------------------------------------------------------
Index Scan using pgbench_accounts_pkey on pgbench_accounts (cost=0.43..8.45 rows=1 width=97)
Index Cond: (aid = 100)
(2 rows)
以下に示すようにFULLヒントは、インデックスを使用するのではなく、完全なシーケンシャルスキャンを強制するために使用されます。
EXPLAIN SELECT /*+ FULL(pgbench_accounts) */ * FROM pgbench_accounts WHERE aid = 100;
 
QUERY PLAN
---------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..58781.69 rows=1 width=97)
Filter: (aid = 100)
(2 rows)
以下に示すようにNO_INDEXヒントではなく、インデックスの使用の並列順次走査を強制します。
EXPLAIN SELECT /*+ NO_INDEX(pgbench_accounts pgbench_accounts_pkey) */ * FROM pgbench_accounts WHERE aid = 100;
 
QUERY PLAN
------------------------------------------------------------------------------------
Gather (cost=1000.00..45094.80 rows=1 width=97)
Workers Planned: 2
-> Parallel Seq Scan on pgbench_accounts (cost=0.00..44094.70 rows=1 width=97)
Filter: (aid = 100)
(4 rows)
前の例に示すようにEXPLAINコマンドを使用することに加えて 、plannerによってヒントが使用されたかどうかに関するより詳細な情報は、 trace_hints構成パラメーターを次のように設定することによって取得できます。
SET trace_hints TO on;
NO_INDEXヒントSELECTコマンドはtrace_hints設定パラメータが設定されているときに生じる付加的な情報を説明するために以下繰り返されます。
EXPLAIN SELECT /*+ NO_INDEX(pgbench_accounts pgbench_accounts_pkey) */ * FROM pgbench_accounts WHERE aid = 100;
 
INFO: [HINTS] Index Scan of [pgbench_accounts].[pgbench_accounts_pkey] rejected due to NO_INDEX hint.
QUERY PLAN
------------------------------------------------------------------------------------
Gather (cost=1000.00..45094.80 rows=1 width=97)
Workers Planned: 2
-> Parallel Seq Scan on pgbench_accounts (cost=0.00..44094.70 rows=1 width=97)
Filter: (aid = 100)
(4 rows)
ヒントが無視されると、 INFO:[HINTS]行は表示されません。これは、索引名のスペルが誤っている次の例に示すように、ヒントに構文エラーまたはその他のスペルミスがあったことを示している可能性があります。
EXPLAIN SELECT /*+ NO_INDEX(pgbench_accounts pgbench_accounts_xxx) */ * FROM pgbench_accounts WHERE aid = 100;
 
QUERY PLAN
-----------------------------------------------------------------------------------------------
Index Scan using pgbench_accounts_pkey on pgbench_accounts (cost=0.43..8.45 rows=1 width=97)
Index Cond: (aid = 100)
(2 rows)
 
2.4.3 結合順序の指定
含める彼らはFROM句にリストされている順序でテーブルを結合するクエリオプティマイザに指示するよう命じディレクティブを。 ORDEREDキーワードを指定しないと、照会オプティマイザーは表を結合する順序を選択します。
たとえば、次のコマンドを使用すると、オプティマイザは FROM句にリストされている表を結合する順序を選択できます
SELECT e.ename、d.dname、h.startdate
FROM emp e、dept d、jobhist h
WHERE d.deptno = e.deptno
そして、h.empno = e.empno;
次のコマンドは、オプティマイザに、指定された順序でテーブルを結合するように指示します。
SELECT / * + ORDERED * / e.ename、d.dname、h.startdate
FROM emp e、dept d、jobhist h
WHERE d.deptno = e.deptno
そして、h.empno = e.empno;
では 、コマンドの順序付きバージョン、Advanced Serverは最初JOBHIST時間で結果を結合する前にDEPT dEMP eを参加します。 ORDEREDディレクティブがなければ、ジョイン順はクエリオプティマイザによって選択されます。
注意: Oracleスタイルの外部結合( '+'記号を含む結合)では ORDERED指令は機能しません。
 
2.4.4 関係のヒントへの参加
2つの表を結合する場合、結合を実行するために使用できる3つの計画があります。
ネストされたループ結合 - テーブルは、 結合された他のテーブルのすべての行に対して1回スキャンされます。
マージソート結合 - 各テーブルは、ジョインが開始する前にジョイン属性でソートされます。次に、2つのテーブルが並列にスキャンされ、一致する行が結合されて結合行が形成されます。
ハッシュ結合 - テーブルがスキャンされ、その結合属性がその結合属性をハッシュ・キーとして使用してハッシュ表にロードされます。次に、他の結合された表がスキャンされ、その結合属性がハッシュ・キーとして使用されて、一致する行が最初の表から検索されます。
次の表に、プランナがあるタイプの結合プランを別のプランに使用するために使用できるオプティマイザ・ヒントを示します。
表2-3結合のヒント
USE_HASH( table [...])
NO_USE_HASH( table [...])
USE_MERGE( table [...])
NO_USE_MERGE( table [...])
USE_NL( table [...])
NO_USE_NL( table [...])
次の例ではpgbench_branchesおよびpgbench_accountsテーブルの結合にUSE_HASHヒントが使用されています。クエリ・プランは、 pgbench_branches表の結合属性からハッシュ表を作成することによってハッシュ結合が使用されることを示しています。
EXPLAIN SELECT /*+ USE_HASH(b) */ b.bid, a.aid, abalance FROM pgbench_branches b, pgbench_accounts a WHERE b.bid = a.bid;
 
QUERY PLAN
-----------------------------------------------------------------------------------
Hash Join (cost=21.45..81463.06 rows=2014215 width=12)
Hash Cond: (a.bid = b.bid)
-> Seq Scan on pgbench_accounts a (cost=0.00..53746.15 rows=2014215 width=12)
-> Hash (cost=21.20..21.20 rows=20 width=4)
-> Seq Scan on pgbench_branches b (cost=0.00..21.20 rows=20 width=4)
(5 rows)
次に、 NO_USE_HASH(ab)ヒントは、プランナにハッシュテーブル以外のアプローチを使用させるように強制します。結果はマージ結合です。
EXPLAIN SELECT /*+ NO_USE_HASH(a b) */ b.bid, a.aid, abalance FROM pgbench_branches b, pgbench_accounts a WHERE b.bid = a.bid;
 
QUERY PLAN
-----------------------------------------------------------------------------------------------
Merge Join (cost=333526.08..368774.94 rows=2014215 width=12)
Merge Cond: (b.bid = a.bid)
-> Sort (cost=21.63..21.68 rows=20 width=4)
Sort Key: b.bid
-> Seq Scan on pgbench_branches b (cost=0.00..21.20 rows=20 width=4)
-> Materialize (cost=333504.45..343575.53 rows=2014215 width=12)
-> Sort (cost=333504.45..338539.99 rows=2014215 width=12)
Sort Key: a.bid
-> Seq Scan on pgbench_accounts a (cost=0.00..53746.15 rows=2014215 width=12)
(9 rows)
最後に、 USE_MERGEヒントは、プランナーにマージ結合を使用させるように強制します。
EXPLAIN SELECT /*+ USE_MERGE(a) */ b.bid, a.aid, abalance FROM pgbench_branches b, pgbench_accounts a WHERE b.bid = a.bid;
 
QUERY PLAN
-----------------------------------------------------------------------------------------------
Merge Join (cost=333526.08..368774.94 rows=2014215 width=12)
Merge Cond: (b.bid = a.bid)
-> Sort (cost=21.63..21.68 rows=20 width=4)
Sort Key: b.bid
-> Seq Scan on pgbench_branches b (cost=0.00..21.20 rows=20 width=4)
-> Materialize (cost=333504.45..343575.53 rows=2014215 width=12)
-> Sort (cost=333504.45..338539.99 rows=2014215 width=12)
Sort Key: a.bid
-> Seq Scan on pgbench_accounts a (cost=0.00..53746.15 rows=2014215 width=12)
(9 rows)
この3台の例に参加する、プランナが最初のハッシュに結合を実行 pgbench_branchespgbench_historyテーブル、最後にハッシュpgbench_accountsテーブルと結果の結合行います。
EXPLAIN SELECT h.mtime, h.delta, b.bid, a.aid FROM pgbench_history h, pgbench_branches b, pgbench_accounts a WHERE h.bid = b.bid AND h.aid = a.aid;
 
QUERY PLAN
----------------------------------------------------------------------------------------
Hash Join (cost=86814.29..123103.29 rows=500000 width=20)
Hash Cond: (h.aid = a.aid)
-> Hash Join (cost=21.45..15081.45 rows=500000 width=20)
Hash Cond: (h.bid = b.bid)
-> Seq Scan on pgbench_history h (cost=0.00..8185.00 rows=500000 width=20)
-> Hash (cost=21.20..21.20 rows=20 width=4)
-> Seq Scan on pgbench_branches b (cost=0.00..21.20 rows=20 width=4)
-> Hash (cost=53746.15..53746.15 rows=2014215 width=4)
-> Seq Scan on pgbench_accounts a (cost=0.00..53746.15 rows=2014215 width=4)
(9 rows)
この計画は、ヒントを使用してマージソート結合とハッシュ結合の組み合わせを強制することによって変更されます。
EXPLAIN SELECT /*+ USE_MERGE(h b) USE_HASH(a) */ h.mtime, h.delta, b.bid, a.aid FROM pgbench_history h, pgbench_branches b, pgbench_accounts a WHERE h.bid = b.bid AND h.aid = a.aid;
 
QUERY PLAN
--------------------------------------------------------------------------------------------------
Hash Join (cost=152583.39..182562.49 rows=500000 width=20)
Hash Cond: (h.aid = a.aid)
-> Merge Join (cost=65790.55..74540.65 rows=500000 width=20)
Merge Cond: (b.bid = h.bid)
-> Sort (cost=21.63..21.68 rows=20 width=4)
Sort Key: b.bid
-> Seq Scan on pgbench_branches b (cost=0.00..21.20 rows=20 width=4)
-> Materialize (cost=65768.92..68268.92 rows=500000 width=20)
-> Sort (cost=65768.92..67018.92 rows=500000 width=20)
Sort Key: h.bid
-> Seq Scan on pgbench_history h (cost=0.00..8185.00 rows=500000 width=20)
-> Hash (cost=53746.15..53746.15 rows=2014215 width=4)
-> Seq Scan on pgbench_accounts a (cost=0.00..53746.15 rows=2014215 width=4)
(13 rows)
 
2.4.5 グローバルヒント
ここまでのヒントは、 SQLコマンドで参照されるテーブルに直接適用されてい ます 。ビューがSQLコマンドで参照されるときに、ビューに表示されるテーブルにヒントを適用することもできます 。ヒントは、ビュー自体に表示されるのではなく、ビューを参照するSQLコマンドに表示されます。
ビュー内のテーブルに適用するヒントを指定するときは、ビューとテーブルの名前はヒント引数リスト内のドット表記で与えられます。
シノプシス
ヒントビューテーブル
パラメーター
ヒント
表2-2または表2-3 のヒントのいずれか。
見る
テーブル を含むビューの名前
ヒントが適用されるテーブル。
ビュー txは、セクション2.4.4の最後の例に示すpgbench_historypgbench_branches 、およびpgbench_accountsの3つのテーブルの結合から作成されます。
CREATE VIEW tx AS SELECT h.mtime, h.delta, b.bid, a.aid FROM pgbench_history h, pgbench_branches b, pgbench_accounts a WHERE h.bid = b.bid AND h.aid = a.aid;
このビューから選択して作成したクエリプランを以下に示します。
EXPLAIN SELECT * FROM tx;
 
QUERY PLAN
----------------------------------------------------------------------------------------
Hash Join (cost=86814.29..123103.29 rows=500000 width=20)
Hash Cond: (h.aid = a.aid)
-> Hash Join (cost=21.45..15081.45 rows=500000 width=20)
Hash Cond: (h.bid = b.bid)
-> Seq Scan on pgbench_history h (cost=0.00..8185.00 rows=500000 width=20)
-> Hash (cost=21.20..21.20 rows=20 width=4)
-> Seq Scan on pgbench_branches b (cost=0.00..21.20 rows=20 width=4)
-> Hash (cost=53746.15..53746.15 rows=2014215 width=4)
-> Seq Scan on pgbench_accounts a (cost=0.00..53746.15 rows=2014215 width=4)
(9 rows)
セクション 2.4.4 の最後にこの結合に適用されたのと同じヒントを次のようにビューに適用できます。
EXPLAIN SELECT /*+ USE_MERGE(tx.h tx.b) USE_HASH(tx.a) */ * FROM tx;
 
QUERY PLAN
--------------------------------------------------------------------------------------------------
Hash Join (cost=152583.39..182562.49 rows=500000 width=20)
Hash Cond: (h.aid = a.aid)
-> Merge Join (cost=65790.55..74540.65 rows=500000 width=20)
Merge Cond: (b.bid = h.bid)
-> Sort (cost=21.63..21.68 rows=20 width=4)
Sort Key: b.bid
-> Seq Scan on pgbench_branches b (cost=0.00..21.20 rows=20 width=4)
-> Materialize (cost=65768.92..68268.92 rows=500000 width=20)
-> Sort (cost=65768.92..67018.92 rows=500000 width=20)
Sort Key: h.bid
-> Seq Scan on pgbench_history h (cost=0.00..8185.00 rows=500000 width=20)
-> Hash (cost=53746.15..53746.15 rows=2014215 width=4)
-> Seq Scan on pgbench_accounts a (cost=0.00..53746.15 rows=2014215 width=4)
(13 rows)
格納されたビュー内のテーブルにヒントを適用することに加えて、ヒントは、次の例に示すようにサブクエリ内のテーブルに適用できます。サンプル・アプリケーションの emp表のこの問合せではemp表を別名bで識別されるemp表のサブクエリに結合することによって、従業員とそのマネージャがリストされます。
SELECT a.empno, a.ename, b.empno "mgr empno", b.ename "mgr ename" FROM emp a, (SELECT * FROM emp) b WHERE a.mgr = b.empno;
 
empno | ename | mgr empno | mgr ename
-------+--------+-----------+-----------
7369 | SMITH | 7902 | FORD
7499 | ALLEN | 7698 | BLAKE
7521 | WARD | 7698 | BLAKE
7566 | JONES | 7839 | KING
7654 | MARTIN | 7698 | BLAKE
7698 | BLAKE | 7839 | KING
7782 | CLARK | 7839 | KING
7788 | SCOTT | 7566 | JONES
7844 | TURNER | 7698 | BLAKE
7876 | ADAMS | 7788 | SCOTT
7900 | JAMES | 7698 | BLAKE
7902 | FORD | 7566 | JONES
7934 | MILLER | 7782 | CLARK
(13 rows)
クエリプランナによって選択された計画を以下に示します。
EXPLAIN SELECT a.empno, a.ename, b.empno "mgr empno", b.ename "mgr ename" FROM emp a, (SELECT * FROM emp) b WHERE a.mgr = b.empno;
 
QUERY PLAN
-----------------------------------------------------------------
Hash Join (cost=1.32..2.64 rows=13 width=22)
Hash Cond: (a.mgr = emp.empno)
-> Seq Scan on emp a (cost=0.00..1.14 rows=14 width=16)
-> Hash (cost=1.14..1.14 rows=14 width=11)
-> Seq Scan on emp (cost=0.00..1.14 rows=14 width=11)
(5 rows)
サブクエリ内 emp表にヒントを適用して 、表スキャンではなく索引emp_pkで索引スキャンを実行できます。クエリプランの違いに注意してください。
EXPLAIN SELECT /*+ INDEX(b.emp emp_pk) */ a.empno, a.ename, b.empno "mgr empno", b.ename "mgr ename" FROM emp a, (SELECT * FROM emp) b WHERE a.mgr = b.empno;
 
QUERY PLAN
---------------------------------------------------------------------------
Merge Join (cost=4.17..13.11 rows=13 width=22)
Merge Cond: (a.mgr = emp.empno)
-> Sort (cost=1.41..1.44 rows=14 width=16)
Sort Key: a.mgr
-> Seq Scan on emp a (cost=0.00..1.14 rows=14 width=16)
-> Index Scan using emp_pk on emp (cost=0.14..12.35 rows=14 width=11)
(6 rows)
 
2.4.6 APPENDオプティマイザ・ヒントの使用
デフォルトでは、Advanced Serverは新しいデータをテーブルの最初に利用可能な空き領域に追加します(空白のレコードによって削除されます)。含める半ばテーブルの空き領域を迂回して、テーブルの末尾に新しい行を固定するために、サーバーに指示するINSERTまたはSELECTコマンドの後APPENDディレクティブを。このオプティマイザ・ヒントは、データをバルク・ロードする場合に特に役立ちます。
構文は次のとおりです。
/ * + APPEND * /
たとえば、Oracleデータベースと互換性のある次のコマンドは、 INSERT 文の データを sales 表の 末尾 に追加するようにサーバーに指示します
INSERT / * + APPEND * / INTO売上値
(10,10、'01-Mar-2011 '、10、' OR ');
Advanced Serverは、 単一の INSERT 文に 複数の行を追加する場合に APPEND ヒントを サポートしています
INSERT / * + APPEND * / INTO売上値
(20,20、'01-Aug-2011 '、20、' NY ')、
(30,30、'01-Feb-2011 '、30、' FL ')、
(40,40、'01-Nov-2011 '、40、' TX ');
APPEND ヒント はまた、INSERT SELECT に含めることができます INTO ステートメント:
INSERT INTO sales_history SELECT / * + APPEND * / FROM sales;
 
2.4.7 並列化のヒント
PARALLELオプティマイザヒントは、並列スキャンを強制するために使用されます。
NO_PARALLELオプティマイザヒントは、並列スキャンの使用を防止します。
シノプシス
PARALLEL( テーブル [ parallel_degree | DEFAULT])
 
NO_PARALLEL(
説明
パラレルスキャンとは、複数のバックグラウンドワーカーを使用して、特定のクエリに対して同時にテーブルをスキャンする(つまりパラレルに実行する)ことです。このプロセスは、順次スキャンなどの他の方法よりもパフォーマンスの向上をもたらします。
パラメーター
並列ヒントが適用されるテーブル。
parallel_degree |デフォルト
parallel_degreeは、並列スキャンに使用するワーカーの希望する数を指定する正の整数です。これを指定すると、 parallel_degreeと構成パラメータmax_parallel_workers_per_gatherのうち小さい方が計画された作業者数として使用されます。 max_parallel_workers_per_gatherパラメータの詳細については、 19.4.6節「 非同期 動作」を参照してください。ここでは、PostgreSQLのコアドキュメントのリソース 消費量を示します。
https://www.postgresql.org/docs/11/static/runtime-config-resource.html
DEFAULTが指定されている場合 、可能な最大並列度が使用されます。
parallel_degreeDEFAULTの 両方を省略すると、問合せオプティマイザは並列度を決定します。この場合、 parallel_workers記憶域パラメーターを使用してが設定されている場合は、この値が並列度として使用されます。そうでない場合、 DEFAULTが指定されたかのように、オプティマイザーは可能な最大並列度を使用します。 parallel_workersストレージパラメータの詳細については、PostgreSQLのコアドキュメントのCREATE TABLEの Storage Parametersサブセクションを参照してください。
https://www.postgresql.org/docs/11/static/sql-createtable.html
状況にかかわらず、並列度は構成パラメータ max_parallel_workers_per_gatherの 設定を決して超えません
次の構成パラメータ設定が有効です。
SHOW max_worker_processes;
 
max_worker_processes
----------------------
8
(1 row)
 
SHOW max_parallel_workers_per_gather;
 
max_parallel_workers_per_gather
---------------------------------
2
(1 row)
次の例は、 pgbench_accounts テーブルのデフォルトスキャンを示しています 。シーケンシャルスキャンがクエリプランに表示されることに注意してください。
SET trace_hints TO on;
 
EXPLAIN SELECT * FROM pgbench_accounts;
 
QUERY PLAN
---------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..53746.15 rows=2014215 width=97)
(1 row)
次の例では、 PARALLELヒントを使用しています。クエリプランでは、バックグラウンドワーカーを起動するGatherノードは、2人のワーカーを使用する予定であることを示します。
注: trace_hintsonに設定されている場合、 INFO:[HINTS]行に、 pgbench_accountsおよびその他のヒント情報でPARALLELが受け入れられたことが示されます。残りの例では、これらの行は、一般的に同じ出力を示すので表示されません(つまり、 trace_hintsoffにリセットされています )。
EXPLAIN SELECT /*+ PARALLEL(pgbench_accounts) */ * FROM pgbench_accounts;
 
INFO: [HINTS] SeqScan of [pgbench_accounts] rejected due to PARALLEL hint.
INFO: [HINTS] PARALLEL on [pgbench_accounts] accepted.
INFO: [HINTS] Index Scan of [pgbench_accounts].[pgbench_accounts_pkey] rejected due to PARALLEL hint.
QUERY PLAN
-----------------------------------------------------------------------------------------
Gather (cost=1000.00..244418.06 rows=2014215 width=97)
Workers Planned: 2
-> Parallel Seq Scan on pgbench_accounts (cost=0.00..41996.56 rows=839256 width=97)
(3 rows)
今、 max_parallel_workers_per_gather設定が増加しました:
SET max_parallel_workers_per_gather TO 6;
 
SHOW max_parallel_workers_per_gather;
 
max_parallel_workers_per_gather
---------------------------------
6
(1 row)
pgbench_accounts の同じ照会PARALLELヒントに並列度指定を指定せずに再度発行されます 。計画されている作業者の数は、オプティマイザによって決定されるように4に増加しました。
EXPLAIN SELECT /*+ PARALLEL(pgbench_accounts) */ * FROM pgbench_accounts;
 
QUERY PLAN
-----------------------------------------------------------------------------------------
Gather (cost=1000.00..241061.04 rows=2014215 width=97)
Workers Planned: 4
-> Parallel Seq Scan on pgbench_accounts (cost=0.00..38639.54 rows=503554 width=97)
(3 rows)
これで、 PARALLELヒントの並列度パラメータに値6が指定されました 。計画された作業者数がこの指定値として返されます。
EXPLAIN SELECT /*+ PARALLEL(pgbench_accounts 6) */ * FROM pgbench_accounts;
 
QUERY PLAN
-----------------------------------------------------------------------------------------
Gather (cost=1000.00..239382.52 rows=2014215 width=97)
Workers Planned: 6
-> Parallel Seq Scan on pgbench_accounts (cost=0.00..36961.03 rows=335702 width=97)
(3 rows)
平行度のDEFAULT設定で同じクエリが発行されるようになりました。結果は、最大許容労働者数が計画されていることを示している。
EXPLAIN SELECT /*+ PARALLEL(pgbench_accounts DEFAULT) */ * FROM pgbench_accounts;
 
QUERY PLAN
-----------------------------------------------------------------------------------------
Gather (cost=1000.00..239382.52 rows=2014215 width=97)
Workers Planned: 6
-> Parallel Seq Scan on pgbench_accounts (cost=0.00..36961.03 rows=335702 width=97)
(3 rows)
テーブル pgbench_accountsが変更され、 parallel_workersストレージパラメータが3に設定されました。
注意: parallel_workersパラメータを設定するALTER TABLEコマンドのこの形式は、Oracleデータベースと互換性がありません。
parallel_workers設定はPSQLの\ dの+コマンドによって示されています。
ALTER TABLE pgbench_accounts SET (parallel_workers=3);
 
\d+ pgbench_accounts
Table "public.pgbench_accounts"
Column | Type | Modifiers | Storage | Stats target | Description
----------+---------------+-----------+----------+--------------+-------------
aid | integer | not null | plain | |
bid | integer | | plain | |
abalance | integer | | plain | |
filler | character(84) | | extended | |
Indexes:
"pgbench_accounts_pkey" PRIMARY KEY, btree (aid)
Options: fillfactor=100, parallel_workers=3
場合今、 PARALLELヒントがない平行度が付与され、計画された労働者の得られた数はparallel_workersパラメータの値です。
EXPLAIN SELECT /*+ PARALLEL(pgbench_accounts) */ * FROM pgbench_accounts;
 
QUERY PLAN
-----------------------------------------------------------------------------------------
Gather (cost=1000.00..242522.97 rows=2014215 width=97)
Workers Planned: 3
-> Parallel Seq Scan on pgbench_accounts (cost=0.00..40101.47 rows=649747 width=97)
(3 rows)
PARALLELヒントに並列度値または DEFAULT指定するとparallel_workers設定がオーバーライドされます。
次の例は、 NO_PARALLELヒントを示しています。 trace_hintsonに設定するINFO:[HINTS]メッセージは、 NO_PARALLELヒントのためにパラレルスキャンが拒否されたことを示します。
EXPLAIN SELECT /*+ NO_PARALLEL(pgbench_accounts) */ * FROM pgbench_accounts;
INFO: [HINTS] Parallel SeqScan of [pgbench_accounts] rejected due to NO_PARALLEL hint.
QUERY PLAN
---------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..53746.15 rows=2014215 width=97)
(1 row)
 
2.4.8 競合するヒント
コマンドに2つ以上の衝突するヒントが含まれている場合、サーバーは矛盾したヒントを無視します。次の表に、互いに矛盾するヒントを示します。
表2-4矛盾するヒント
FIRST_ROWS - すべての形式
FULL( table
INDEX( table [ index ])
PARALLEL( table [ degree ])
INDEX( table
FULL( table
NO_INDEX( table
PARALLEL( table [ degree ])
INDEX( table index
FULL( table
NO_INDEX( table index
PARALLEL( table [ degree ])
PARALLEL( table [ degree ])
FULL( table
INDEX( table
NO_PARALLEL( table
USE_HASH( table
NO_USE_HASH( table
USE_MERGE( table
NO_USE_MERGE( table
USE_NL( table
NO_USE_NL( table
3 ストアドプロシージャ言語
この章では、 ストアドプロシージャ言語 SPL) について説明し ます SPL 高度なサーバー 用のカスタムプロシージャ、関数、トリガ、およびパッケージを作成するための高度に生産的な手続き型プログラミング言語です
この章では、基本的な要素について説明し SPLプログラムの組織の概要を提供する前に、SPLプログラムを、プロシージャまたは関数を作成するために使用される方法。トリガーは、まだSPLを利用しているが、別の議論を正当化するためには十分に異なっている トリガーについての 詳細はセクション 4 参照 )。パッケージは、次の URLにあるOracle Developerの組み込みパッケージ・ガイド データベース互換性 について説明してい ます。
https://www.enterprisedb.com/resources/product-documentation
この章の残りのセクションでは、 SPL言語の詳細を掘り下げ 、アプリケーションの例を示します。
3.1 基本的なSPL要素
このセクションでは、 SPL プログラムの 基本的なプログラミング要素について説明し ます。
3.1.1 文字セット
SPLプログラムは、次の文字セットを使用して記述されます。
大文字 Zと小文字スルースルーZ
数字 0 から9まで
シンボル + - * / < > = ^ ; ' @ " $ _ | { } [ ]
これらの文字を使用して SPL言語を構成する識別子、式、文、制御構造などが記述されます。
注意: SPL プログラムで 操作できるデータ は、データベースエンコーディングでサポートされている文字セットによって決まります。
3.1.2 大文字小文字の区別
SPL プログラムで 使用されるキーワードおよびユーザー定義の識別子 は、大文字と小文字を区別しません。したがって、たとえば、文 DBMS_OUTPUT.PUT_LINE( 'Hello World')。 dbms_output.put_line( 'Hello World') と同じ意味を持つと解釈され ます。 または Dbms_Output.Put_Line( 'Hello World'); または DBMS_output.Put_line( 'Hello World')。
ただし、文字および文字列定数では、大文字と小文字が区別されます。また、 Advanced Serverデータベースから取得されたデータまたは他の外部ソースから取得されたデータもあります。文DBMS_OUTPUT.PUT_LINE( 'Hello World!')。次の出力が生成されます。
Hello World!
しかし、文の DBMS_OUTPUT.PUT_LINE( 'HELLO WORLD!'); 出力が生成されます。
HELLO WORLD!
3.1.3 識別子
識別子 、変数、カーソル、ラベル、プログラム、およびパラメータを含むSPLプログラムのさまざまな要素を識別するために使用されるユーザー定義の名前です 。有効な識別子の構文ルールは、 SQL言語の識別子と同じです。
識別子は、 SPLキーワードまたはSQL言語のキーワードと同じであってはなりません 。有効な識別子の例を次に示します。
x
last___name
a_$_Sign
Many$$$$$$$$signs_____
THIS_IS_AN_EXTREMELY_LONG_NAME
A1
3.1.4 修飾子
修飾子は、 資格の対象となるエンティティの所有者またはコンテキストを指定する名前です。 修飾されたオブジェクトが修飾子の名前として指定され、続いて空白が挿入されないドットが続き、修飾されるオブジェクトの名前の後に空白が挿入されません。この構文を ドット表記法 といいます
以下は、修飾されたオブジェクトの構文です。
qualifier . [ qualifier . ]... object
修飾子 は、オブジェクトの所有者の名前です。 object 修飾子に 属するエンティティの名前です 。前の修飾子が後続の修飾子とオブジェクトによって識別されるエンティティを所有する場合、一連の修飾を持つことが可能です。
ほぼすべての識別子を修飾することができます。どの識別子が修飾されるかは、その識別子が表すものとその使用のコンテキストに依存する。
資格の例は次のとおりです。
原則として、 SPL文の構文に名前が表示されている場合でも 、その修飾名も使用できます。通常、修飾された名前は、名前にあいまいさがある場合にのみ使用されます。たとえば、2つの異なるスキーマに属する同じ名前を持つ2つのプロシージャがプログラム内から呼び出された場合、または同じプログラム内の表の列およびSPL変数に同じ名前が使用された場合。
可能な場合は、修飾名を使用しないでください。この章では、名前の競合を避けるために次の規則を採用しています。
SPLプログラムの宣言セクションで宣言されたすべての変数の先頭にはv_が付きます。例えば、 v_empno
3.1.5 定数
定数 または リテラル 、数値、文字列、日付などのさまざまな型の値を表すために SPLプログラムで使用できる固定値です 。定数の型は次のとおりです。
 
3.1.6 ユーザー定義のPL / SQLサブタイプ
Advanced Serverは、ユーザー定義のPL / SQLサブタイプおよび(サブタイプ)別名をサポートします。サブタイプは、そのタイプの列に保管できる値を制限するオプションの制約セットを持つデータ・タイプです。サブタイプの基になるタイプに適用されるルールは引き続き適用されますが、追加の制約を使用して、そのタイプに格納されている値の精度または位取りを制限できます。
PL関数、プロシージャ、匿名ブロックまたはパッケージの宣言にサブタイプを定義できます。構文は次のとおりです。
SUBTYPE サブタイプ _ 名前 IS タイプ _ 名前 [( 制約 )] [NOT NULL]
どこに 制約があります。
{ precision [、 scale ]} | 長さ
場所:
サブタイプ _
subtype _ nameは、 サブタイプの 名前を指定します。
タイプ _ 名前
type _ nameは、サブタイプの基となる元のタイプの名前を指定します。 type_nameは次のようになります。
%TYPE演算子で固定された列
精度または位取りをサポートする型 制約を定義するには、 constraint句を含めます
精度
precisionは、サブタイプの値に許される桁数の合計を指定します。
規模
scaleは、サブタイプの値に許容される小数の桁数を指定します。
長さ
lengthは、 CHARACTERVARCHAR 、またはTEXTの基本タイプの値に許可れている合計長を指定します。
指定されたサブタイプの列にNULL値が格納されないように指定するには、 NOT NULL句を含めます
列に基づくサブタイプは列サイズ制約を継承しますが、サブタイプは NOT NULLまたはCHECK制約を継承し ません
制約のないサブタイプ
拘束されていないサブタイプを作成するには、 SUBTYPEコマンドを使用して 、新しいサブタイプ名とサブタイプの基になるタイプの名前を指定します。たとえば、次のコマンドは、タイプがCHARのすべての属性を持つaddressという名前のサブタイプを作成します。
SUBTYPEアドレスはIS CHARです。
別のサブタイプのサブタイプであるサブタイプ(制約付きまたは制約なし)を作成することもできます。
SUBTYPE cust_address ISアドレスはNULLではありません。
このコマンドはアドレスサブタイプのすべての属性を共有するcust _ address という名前のサブタイプを作成ますCUSTの値が_ アドレスが NULLではないかもしれないことを指定するには、NOT NULL句が含まれます。
制約付きサブタイプ
サブタイプの最大長を定義する文字タイプに基づくサブタイプを作成するときに 長さの値を含めます 。例えば:
SUBTYPE acct_nameはVARCHAR(15)です。
この例では、 VARCHARデータ・タイプに基づいた長さが15文字に制限されているacct _ nameというサブタイプを作成します
数値型の基本型を制約するときは、 精度の (サブタイプの値の最大桁数を指定する)とオプションでscale (小数点の右側の桁数を指定する)を指定します。例えば:
SUBTYPE acct_balance IS NUMBER(5、2)です。
この例では、 NUMBER型のすべての属性を共有するacct_balanceというサブタイプを作成しますが、小数点の左側に3桁、小数点の右側に2桁を超えることはできません。
引数宣言(関数またはプロシージャヘッダー内)は 引数です。関数またはプロシージャに渡される値は、 実際の 引数です。関数またはプロシージャを呼び出すとき、呼び出し側は実際の引数を(0以上)提供します。実際の各引数は、関数またはプロシージャの本体内の値を保持する仮引数に割り当てられます。
正式な引数が制約付きのサブタイプとして宣言されている場合:
%TYPE演算子の使用
%TYPE表記を使用して、列にアンカーされたサブタイプを宣言することができます。例えば:
SUBTYPE emp_typeはemp.empno%TYPEです。
このコマンドは、基本タイプがempテーブルのempnoカラムのタイプと一致するemp _ type というサブタイプを作成します。列に基づいたサブタイプは列サイズの制約を共有します。 NOT NULLおよびCHECK制約は継承されません。
サブタイプ変換
制約のないサブタイプは、それが基にしているタイプの別名です。サブタイプ(制約なし)の変数は、変換を行わずに基本タイプの変数と入れ替えることができます。逆もあります。
制約付きサブタイプの変数は、変換なしで基本タイプの変数と入れ替えることができるが、基本タイプの変数は、それがサブタイプの制約に準拠する場合にのみ、制約付きサブタイプと交換することができる。制約付きサブタイプの変数は、同じサブタイプに基づいており、制約値が変換されるサブタイプの値内にある場合、暗黙的に別のサブタイプに変換される可能性があります。
3.2 SPLプログラム
SPL は手続き型のブロック構造言語です。 SPL を使用して作成できるプログラムには プロシージャ 関数 トリガ 、および パッケージの 4種類が あり ます
さらに、SPLを使用してサブプログラムを作成します。 サブプログラムは、プロシージャおよび関数に外観がほぼ同じであるが、プロシージャおよび関数は、個別にデータベースに格納され、他のSPLプログラムによって、またはPSQLから呼び出すことができ、スタンドアロンのプログラム 、であるという点で異なるサブプロシージャまたはサブファンクションを指し。サブプログラムは、作成されたスタンドアロン・プログラム内からのみ呼び出すことができます。
 
3.2.1 SPLのブロック構造
プログラムがプロシージャ、ファンクション、サブプログラム、トリガのいずれであるかにかかわらず、 SPL プログラムは同じ ブロック 構造を 持ち ます。ブロックは、オプションの宣言セクション、必須の実行可能セクション、およびオプションの例外セクションの3つのセクションで構成されます。最低限、ブロックには 、キーワード BEGIN END 内の 1つ以上の SPL 文で 構成される実行可能セクションがあります
オプションの宣言セクションは、実行可能セクションおよび例外セクション内のステートメントによって使用される変数、カーソル、タイプ、およびサブプログラムを宣言するために使用されます。宣言は、実行可能セクションのBEGINキーワードの直前に現れます。ブロックが使用されるコンテキストに応じて、宣言セクションはキーワードDECLAREで始まることがあります。
BEGIN - ENDブロック内に例外セクションを含めることができます 。例外セクションはキーワードEXCEPTIONで始まり、それが現れるブロックの終わりまで続きます。ブロック内のステートメントによって例外がスローされた場合、プログラム制御は、例外セクションおよび例外セクションの内容に応じて、スローされた例外が処理される場合とされない場合があります。
ブロックの一般的な構造は次のとおりです。
[ [ DECLARE ]
pragmas
declarations ]
BEGIN
statements
[ EXCEPTION
WHEN exception_condition THEN
statements [, ...] ]
END;
プラグマがディレクティブです( AUTONOMOUS_TRANSACTIONは現在サポートされているプラ​​グマです)。 宣言 は、ブロックに対してローカルな1つ以上の変数、カーソル、タイプ、またはサブプログラムの宣言です。サブプログラム宣言が含まれている場合は、他のすべての変数宣言、カーソル宣言、および型宣言の後に宣言する必要があります。各宣言はセミコロンで終わらなければなりません。キーワード DECLARE の使用は 、ブロックが表示されるコンテキストによって異なります。
ステートメント は、1つ以上の SPL ステートメントです。各ステートメントは、セミコロンで終了する必要があります。 END キーワードで示されるブロックの終わりもセミコロンで終わらなければなりません。
存在する場合、キーワード EXCEPTIONは例外セクションの先頭を示します。 exception_conditionは、1つまたは複数のタイプの例外をテストする条件式です。例外がexception_condition内の例外の 1つと一致する場合、 WHEN exception_condition節の後のステートメントが実行されます。 1つ以上のWHEN exception_condition句があり、それぞれにはステートメントが続きます。 注: BEGIN / ENDブロック自体はステートメントとみなされます。従って、ブロックは入れ子にされてもよい。例外セクションには、ネストされたブロックも含まれます。
以下は 、実行可能セクション内のNULLからなる最も単純なブロックです。 NULL文は、何も実行しない実行文です。
BEGIN
NULL;
END;
次のブロックには、宣言セクションと実行可能セクションが含まれています。
DECLARE
v_numerator NUMBER(2);
v_denominator NUMBER(2);
v_result NUMBER(5,2);
BEGIN
v_numerator := 75;
v_denominator := 14;
v_result := v_numerator / v_denominator;
DBMS_OUTPUT.PUT_LINE(v_numerator || ' divided by ' || v_denominator ||
' is ' || v_result);
END;
この例では、データ型 NUMBERの 3つの数値変数が宣言されています 。値は2つの変数に割り当てられ、1つの数値は別の数値で割り算され、結果が第3の変数に格納されて表示されます。実行されると、出力は次のようになります。
75 divided by 14 is 5.36
次のブロックは、宣言、実行可能ファイル、および例外から構成されます。
DECLARE
v_numerator NUMBER(2);
v_denominator NUMBER(2);
v_result NUMBER(5,2);
BEGIN
v_numerator := 75;
v_denominator := 0;
v_result := v_numerator / v_denominator;
DBMS_OUTPUT.PUT_LINE(v_numerator || ' divided by ' || v_denominator ||
' is ' || v_result);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('An exception occurred');
END;
次の出力は、例外セクション内のステートメントがゼロ除算の結果として実行されることを示しています。
An exception occurred
 
3.2.2 匿名ブロック
ブロックは、通常、プロシージャ、ファンクション、サブプログラム、またはトリガの一部として記述されます。プロシージャー、関数、およびトリガー・プログラムは、再使用のために名前が付けられ、データベースに保管されます。クイック(ワンタイム)実行(テストなど)の場合は、名前を入力せずにブロックを入力するか、データベースに格納するだけです。
このタイプのブロックは 匿名ブロック と呼ば れます 。無名ブロックは名前が付けられておらず、データベースに格納されません。ブロックが実行され、アプリケーションバッファから消去されると、ブロックコードがアプリケーションに再入力されない限り、ブロックは再実行できません。
通常、同じコードブロックが何度も再実行されます。毎回コードを再入力せずにコードブロックを繰り返し実行するには、いくつかの簡単な変更を加えて、無名ブロックを手続きまたは関数に変換することができます。以下のセクションでは、データベースに格納し、別のプロシージャー、関数、またはアプリケーション・プログラムによって繰り返し呼び出されるプロシージャーまたは関数を作成する方法について説明します。
 
3.2.3 プロシージャの概要
プロシージャは 、個々のSPLプログラム文として呼び出される、または呼び出されるスタンドアロンの SPLプログラムです。呼び出されると、プロシージャはオプションで入力パラメータの形式で呼び出し元から値を受け取り、オプションで出力パラメータの形式で呼び出し元に値を返します。
3.2.3.1 プロシージャの作成
PROCEDUREコマンド定義と名称データベースに格納されるスタンドアロン・プロシージャを作成します
スキーマ名が含まれている場合、プロシージャーは指定されたスキーマに作成されます。それ以外の場合は、現在のスキーマに作成されます。新しいプロシージャの名前は、同じスキーマ内の同じ入力引数型を持つ既存のプロシージャと一致していてはなりません。しかし、異なる入力引数型のプロシージャは名前を共有することがあります(これは オーバーロード と呼ばれます )。 (プロシージャのオーバーロードはAdvanced Serverの機能であり、ストアド・スタンドアロン・プロシージャのオーバーロードはOracleデータベースと互換性がありません)。
既存のプロシージャーの定義を更新するには、 CREATE OR REPLACE PROCEDUREを 使用します 。このようにプロシージャの名前または引数の型を変更することはできません(試した場合は、実際には新しいプロシージャを作成することになります)。 OUTパラメーターを使用する場合は、プロシージャーをドロップすることを除いて、 OUTパラメーターのタイプを変更することはできません。
CREATE [ OR REPLACE ] PROCEDURE name [ ( parameters ) ]
[
不変
|安定
|揮発性
|決定的
| [NOT] LEAKPROOF
| NULL入力で呼び出される
|ヌル入力でNULLを返す
| STRICT
| [外部]セキュリティ・インボーカ
| [外部]セキュリティディフェンダー
| AUTHID DEFINER
| AUTHID CURRENT_USER
|パラレル{UNSAFE |制限された|安全 }
| COSTの 実行 _ コスト
| ROWSは _ 行の 結果
| SET
構成 _ パラメーター
{TO
| = | FROM CURRENT}
...]
{IS | AS}
[PRAGMA AUTONOMOUS_TRANSACTION; ]
[ declarations ]
BEGIN
statements
END [ name ];
場所:
name はプロシージャの識別子です。
パラメーター
parameters は仮パラメータのリストです。
宣言
宣言 は、変数、カーソル、型、または副プログラムの宣言です。サブプログラム宣言が含まれている場合は、他のすべての変数宣言、カーソル宣言、および型宣言の後に宣言する必要があります。
ステートメント
ステートメント SPL プログラムステートメントです( BEGIN - END ブロックには EXCEPTIONセクションが含まれる場合があります )。
不変
安定
揮発性
これらの属性は、問合せオプティマイザにプロシージャの動作を通知します。 1つの選択肢しか指定できません。 VOLATILE はデフォルトの動作です。
IMMUTABLE は、プロシージャーがデータベースを変更できず、同じ引き数値が与えられたときに常に同じ結果に達することを示します。データベース参照を行わず、引数リストに直接存在しない情報を使用しません。この句をインクルードすると、すべて定数の引数を持つプロシージャの呼び出しをすぐにプロシージャの値に置き換えることができます。
STABLE は、プロシージャーがデータベースを変更できず、単一の表スキャン内で、同じ引き数値に対して同じ結果を一貫して戻しますが、結果がSQLステートメントで変更される可能性があることを示します。これは、データベースルックアップ、パラメータ変数(現在のタイムゾーンなど)に依存するプロシージャの適切な選択です。
VOLATILE は、単一の表スキャン内でもプロシージャ値が変更可能であるため、最適化を実行できないことを示します。副作用のある関数は、呼び出しが最適化されないように、結果がかなり予測可能であっても、揮発性に分類されなければならないことに注意してください。
決定的
DETERMINISTICIMMUTABLEの同義語です DETERMINISTIC プロシージャーはデータベースを変更することはできず、同じ引き数値が与えられたときに常に同じ結果になります。データベース参照を行わず、引数リストに直接存在しない情報を使用しません。この句をインクルードすると、すべて定数の引数を持つプロシージャの呼び出しをすぐにプロシージャの値に置き換えることができます。
[NOT] LEAKPROOF
漏れ防止の 手順は、副作用がなく、プロシージャを呼び出すために使用される値に関する情報を明らかにしません。
NULL入力で呼び出される
ヌル入力でNULLを返す
STRICT
呼び出される ヌル INPUT (デフォルト)は、引数の一部が NULLの 場合にプロシージャが正常に呼び出されることを示し ます 必要に応じ NULL をチェックし、 適切に応答するの は作者の責任 です。
戻り値 ヌル ヌル INPUT または STRICT 、その引数のいずれか NULL の場合は必ずプロシージャが NULL を返すことを示し ます 。これらの句が指定されている場合、 NULL 引数 がある場合はプロシージャは実行されません 。代わりに NULL という結果が自動的想定されます。
[外部]セキュリティディフェンダー
セキュリティ DEFINER は、プロシージャを作成したユーザーの権限でプロシージャを実行するように指定します。これがデフォルトです。キーワード EXTERNAL はSQL準拠には使用できますが、オプションです。
[外部]セキュリティ・インボーカ
SECURITY INVOKER 句は、プロシージャがそれを呼び出すユーザの権限で実行されることを示します。キーワード EXTERNAL はSQL準拠には使用できますが、オプションです。
AUTHID DEFINER
AUTHID CURRENT_USER
AUTHID DEFINER 句は、 [EXTERNAL]の 同義語です セキュリティ DEFINER AUTHID が省略された 場合 、または AUTHID 場合 DEFINER が指定されている場合は、プロシージャ所有者の権限を使用してデータベース・オブジェクトへのアクセス権限が決定されます。
AUTHID CURRENT_USER 句は、 [EXTERNAL]の 同義語です セキュリティ INVOKER AUTHIDの 場合 CURRENT_USER が指定されている場合、プロシージャを実行している現行ユーザーの権限を使用してアクセス権限が決定されます。
パラレル{UNSAFE |制限された|安全 }
PARALLEL 句は、並列逐次走査(パラレルモード)の使用を可能にします。 並列逐次スキャンは、逐次逐次スキャンとは対照的に、クエリ中に複数のワーカーを使用してリレーションを並行してスキャンします。
UNSAFE 設定すると 、パラレルモードでは実行できません。このようなプロシージャが存在すると、シリアル実行プランが強制されます。これは、 PARALLEL 句が省略された 場合のデフォルト設定です
RESTRICTED 設定する と、プロシージャはパラレルモードで実行できますが、実行はパラレルグループリーダーに制限されます。特定の関係の資格に並行制限があるものがあれば、その関係は並列性のために選択されません。
SAFE 設定されている場合 、プロシージャは制限なしでパラレルモードで実行できます。
COSTの 実行 _ コスト
実行 _ コストは、CPU _ オペレータ _ コスト の単位で手順の推定実行コストを与える正の数です 。プロシージャーがセットを戻す場合、これは戻された行あたりのコストです。値を大きくすると、プランナは必要以上に機能を評価しないようにします。
ROWSは _ 行の 結果
result _ rows は、プランナがプロシージャが返すと予想する行の推定数を示す正の数です。これは、プロシージャがセットを返すと宣言されている場合にのみ許可されます。デフォルトの仮定は1000行です。
SET 設定 _ パラメータ {TO | = | FROM CURRENT}
SET は、指定された設定パラメータは、手順が入力されると、指定された値に設定され、その前の値場合の処理手順が終了に復帰させます。 セット から CURRENT は、プロシージャーに入ったときに適用される値として、セッションの現行のパラメーター値を 保管 します。
場合 SET SET は、プロシージャに装着され、その後、効果 同じ変数のプロシージャー内で実行される LOCAL コマンドは、プロシージャーに限定されています。プロシージャ出口で構成パラメータの事前値がリストアされます。 (LOCALなし 通常の SET コマンド 、前の SET のために行うだろう限り、SET句 上書きします 現在のトランザクションがロールバックされない限り、プロシージャの終了後にそのようなコマンドの効果が持続する LOCAL コマンド。
PRAGMA AUTONOMOUS_TRANSACTION
PRAGMA AUTONOMOUS_TRANSACTIONは、プロシージャを自律型トランザクションとして設定するディレクティブです。
注: STRICTLEAKPROOFPARALLELCOSTROWSおよびSETキーワードはAdvanced Serverの拡張機能を提供し、Oracleではサポートされていません。
注意:デフォルトでは、ストアド・プロシージャはSECURITY DEFINERSとして作成されますが、plpgsqlで書かれたストアド・プロシージャはSECURITY INVOKERSとして作成されます。
以下は、パラメータを取らない単純なプロシージャの例です。
CREATE OR REPLACE PROCEDURE simple_procedure
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('That''s all folks!');
END simple_procedure;
プロシージャは、 Advanced Serverに プロシージャコードを入力してデータベースに格納され ます。
次の例は、プロシージャ宣言でAUTHID DEFINERおよびSETを使用する方法を示しています。 更新 _ 給与の 手順は(手順の実行中)プロシージャを呼び出している役割に手順を定義したロールの権限を伝えます
CREATE OR REPLACE PROCEDURE update_salary(id INT, new_salary NUMBER)
SET SEARCH_PATH = 'public' SET WORK_MEM = '1MB'
AUTHID DEFINER IS
BEGIN
UPDATE emp SET salary = new_salary WHERE emp_id = id;
END;
プロシージャの検索パスを public に、ワークメモリを 1MB に設定するに は、 SET 句を 含めます 。他のプロシージャ、関数、およびオブジェクトは、これらの設定の影響を受けません。
この例では、 AUTHID DEFINER 句は、プロシージャ内の文の実行を許可されないロールに一時的に権限を付与します。プロシージャを呼び出すロールに関連付けられた権限を使用するようにサーバーに指示するには、 AUTHID AUTHIDを 持つ DEFINER CURRENT _ USER 節。
3.2.3.2 プロシージャのコール
プロシージャーは 、プロシージャー名の後にそのパラメーターがある場合はそれを指定し、その後にセミコロンを付けることによって 、別の SPL プログラム から呼び出すことができます
name [ ([ parameters ]) ];
場所:
name はプロシージャの識別子です。
parameters は実際のパラメータのリストです。
注意:渡される実際のパラメータがない場合は、空のパラメータリストを使用してプロシージャを呼び出すことができます。または、開閉括弧を完全に省略することもできます。
注:プロシージャを呼び出す構文は、PSQLまたはEDB * PlusのEXECコマンドを使用して実行する場合の構文図と同じです。 EXECコマンドの詳細は、 「Oracle Developer Tools and Utilities Guide」データベースの互換性を参照してください。
次は、無名ブロックからプロシージャを呼び出す例です。
BEGIN
simple_procedure;
END;
 
That's all folks!
:各アプリケーションには、プロシージャーを呼び出す独自の方法があります。たとえば、 Javaアプリケーションでは、アプリケーションプログラミングインターフェイスであるJDBCが使用されます。
3.2.3.3 プロシージャの削除
プロシージャーは、 DROP PROCEDURE コマンド を使用してデータベースから削除することができます
DROP PROCEDURE [ IF EXISTS ] name [ ( parameters ) ]
[ CASCADE | RESTRICT ];
ここで、 nameは削除するプロシージャの名前です。
注意:パラメータリストの指定は、オーバーロードされたプロシージャなど、特定の状況下でAdvanced Serverに必要です。 Oracleでは、パラメータ・リストを常に省略する必要があります。
注: IF EXISTSCASCADE 、またはRESTRICTの使用法は、Oracleデータベースとの互換性がありません。これらのオプションの詳細は、 「Oracle Database開発者リファレンスガイド」のデータベース互換性DROP PROCEDUREコマンドを参照してください。
この例では、以前に作成されたプロシージャは削除されます。
DROP PROCEDURE simple_procedure;
 
3.2.4 関数の概要
関数は 、式として呼び出される スタンドアロンの SPL プログラムです。評価されると、関数は、関数が組み込まれている式で代入された値を返します。関数はオプションで、呼び出しプログラムから入力パラメータの形で値を取ることができます。ファンクション自体が値を返すという事実に加えて、関数は出力パラメータの形式で呼び出し側にオプションで追加の値を返すことがあります。しかし、関数内での出力パラメータの使用は、プログラミングの奨励策ではありません。
3.2.4.1 関数の作成
機能 コマンド定義と名称データベースに格納されるスタンドアロン関数を 作成 します
スキーマ名が含まれる場合、関数は指定されたスキーマに作成されます。それ以外の場合は、現在のスキーマに作成されます。新しい関数の名前は、同じスキーマ内の同じ入力引数型を持つ既存の関数と一致していてはなりません。しかし、異なる入力引数型の関数は名前を共有することがあります(これは オーバーロード と呼ばれます )。 (関数のオーバーロードはAdvanced Serverの機能です。格納されたスタンドアロン関数のオーバーロードはOracleデータベースと互換性がありません。
既存の関数の定義を更新するには、 CREATE OR REPLACE FUNCTIONを 使用します 。この方法で関数の名前や引数の型を変更することはできません(試した場合は、実際には別個の関数を作成することになります)。また、 CREATE OR REPLACE FUNCTIONでは、既存の関数の戻り値の型を変更することはできません。これを行うには、関数を削除して再作成する必要があります。また、 OUTパラメーターを使用する場合は、その関数をドロップすることを除いて、 OUTパラメーターのタイプを変更することはできません。
CREATE [ OR REPLACE ] FUNCTION name [ ( parameters ) ]
RETURN data_type
[
不変
|安定
|揮発性
|決定的
| [NOT] LEAKPROOF
| NULL入力で呼び出される
|ヌル入力でNULLを返す
| STRICT
| [外部]セキュリティ・インボーカ
| [外部]セキュリティディフェンダー
| AUTHID DEFINER
| AUTHID CURRENT_USER
|パラレル{UNSAFE |制限された|安全 }
| COSTの 実行 _ コスト
| ROWSは _ 行の 結果
| SET
構成 _ パラメーター
{TO
| = | FROM CURRENT}
...]
{IS | AS}
[PRAGMA AUTONOMOUS_TRANSACTION; ]
[ declarations ]
BEGIN
statements
END [ name ];
場所:
name 関数の識別子です
パラメーター
parameters は仮パラメータのリストです。
データ・タイプ
data_typeは、関数のRETURNステートメントによって返された値のデータ型です。
宣言
宣言 は、変数、カーソル、型、または副プログラムの宣言です。サブプログラム宣言が含まれている場合は、他のすべての変数宣言、カーソル宣言、および型宣言の後に宣言する必要があります。
ステートメント
ステートメント SPL プログラムステートメントです( BEGIN - END ブロックには EXCEPTIONセクションが含まれる場合があります )。
不変
安定
揮発性
これらの属性は、クエリオプティマイザに関数の動作を通知します 。 1つの選択肢しか指定できません。 VOLATILE はデフォルトの動作です。
IMMUTABLE は、関数がデータベースを変更できず、同じ引数値が与えられたときに常に同じ結果に達することを示します。データベース参照を行わず、引数リストに直接存在しない情報を使用しません。この句を含める と、すべて定数の引数を持つ関数の呼び出しを すぐに関数の に置き換えることができ ます。
STABLE は、関数がデータベースを変更できない ことを示し 、単一の表スキャン内では、同じ引き数値に対して同じ結果を一貫して戻しますが、結果はSQLステートメント全体で変更される可能性があることを示します。これは、 データベースルックアップ、パラメータ変数(現在のタイムゾーンなど)に依存する関数の適切な選択です
VOLATILE 、単一のテーブル・スキャン内でも関数値が変更できることを 示している ため、最適化は行えません。副作用のある関数は、呼び出しが最適化されないように、結果がかなり予測可能であっても、揮発性に分類されなければならないことに注意してください。
決定的
DETERMINISTICIMMUTABLEの同義語です。 DETERMINISTIC関数はデータベースを変更することはできず、同じ引き数を指定すると常に同じ結果になります。データベース参照を行わず、引数リストに直接存在しない情報を使用しません。この句を含めると、すべて定数の引数を持つ関数の呼び出しをすぐに関数の値に置き換えることができます。
[NOT] LEAKPROOF
漏れ止め 関数には副作用がなく、関数の呼び出しに使用された値に関する情報は表示されません
NULL入力で呼び出される
ヌル入力でNULLを返す
STRICT
呼び出される ヌル INPUT (デフォルト)は、引数の一部が NULLの 場合にプロシージャが正常に呼び出されることを示し ます 必要に応じ NULL をチェックし、 適切に応答するの は作者の責任 です。
戻り値 ヌル ヌル INPUT または STRICT 、その引数のいずれか NULL の場合は必ずプロシージャが NULL を返すことを示し ます 。これらの句が指定されている場合、 NULL 引数 がある場合はプロシージャは実行されません 。代わりに NULL という結果が自動的想定されます。
[外部]セキュリティディフェンダー
セキュリティ DEFINER は、関数を作成したユーザーの権限で関数が実行されることを指定します。これがデフォルトです。キーワード EXTERNAL はSQL準拠には使用できますが、オプションです。
[外部]セキュリティ・インボーカ
SECURITY INVOKER 句は、関数を呼び出すユーザーの権限で関数が実行されることを示します。キーワード EXTERNAL はSQL準拠には使用できますが、オプションです。
AUTHID DEFINER
AUTHID CURRENT_USER
AUTHID DEFINER 句は、 [EXTERNAL]の 同義語です セキュリティ DEFINER AUTHID が省略された 場合 、または AUTHID 場合 DEFINER が指定されている場合、関数所有者の権限を使用してデータベース・オブジェクトへのアクセス権限が決定されます。
AUTHID CURRENT_USER 句は、 [EXTERNAL]の 同義語です セキュリティ INVOKER AUTHIDの 場合 CURRENT_USER が指定されている場合、その関数を実行している現行ユーザーの権限を使用してアクセス特権が判別されます。
パラレル{UNSAFE |制限された|安全 }
PARALLEL 句は、並列逐次走査(パラレルモード)の使用を可能にします。 並列逐次スキャンは、逐次逐次スキャンとは対照的に、クエリ中に複数のワーカーを使用してリレーションを並行してスキャンします。
UNSAFE 設定すると 、パラレルモードでは実行できません。このような関数がSQL文に存在すると、実行計画が強制的に実行されます。これは、 PARALLEL 句が省略された 場合のデフォルト設定です
RESTRICTED 設定すると 、この関数はパラレルモードで実行できますが、実行はパラレルグループリーダーに制限されます。特定の関係の資格に並行制限があるものがあれば、その関係は並列性のために選択されません。
SAFE 設定すると 、パラレルモードで機能を制限なく実行できます。
COSTの 実行 _ コスト
実行 _ コスト は、 CPUの _ 演算子 _ コストの 単位で 関数の推定実行コストを示す正の数 です。機能の場合 セットを返します。返される行あたりのコストです。値を大きくすると、プランナは関数の評価を回避しようとします 必要以上に頻繁に。
ROWSは _ 行の 結果
result _ rows は、プランナが関数を予想する行の推定数を示す正の数です。 復帰する。これは、関数 セットを返すように宣言されています。デフォルトの仮定は1000行です。
SET 設定 _ パラメータ {TO | = | FROM CURRENT}
SET は、場合関数指定された構成パラメータが指定された値に設定させます 関数が入力されると、その値に戻されます 終了します。 セット から CURRENT は、セッションの現在のパラメータ値を、関数の実行時に適用される値として保存します 入力されます。
場合は SET は、関数、SETの後、効果 に取り付けられています。 関数内で実行される LOCAL コマンド 同じ変数に対しては関数に制限されています。構成パラメータの以前の値が関数で復元される 出口。 (LOCALなし 通常の SET コマンド 、前の SET のために行うだろう限り、SET句 上書きします 現在のトランザクションがロールバックされない限り、プロシージャの終了後にそのようなコマンドの効果が持続する LOCAL コマンド。
PRAGMA AUTONOMOUS_TRANSACTION
PRAGMA AUTONOMOUS_TRANSACTION は、この関数を自律型トランザクションとして設定するディレクティブです。
注: STRICTLEAKPROOFPARALLELCOSTROWSおよびSETキーワードはAdvanced Serverの拡張機能を提供し、Oracleではサポートされていません。
以下は、パラメータを取らない単純な関数の例です。
CREATE OR REPLACE FUNCTION simple_function
RETURN VARCHAR2
IS
BEGIN
RETURN 'That''s All Folks!';
END simple_function;
次の関数は、2つの入力パラメータを取ります。パラメータについては、以降のセクションで詳しく説明します。
CREATE OR REPLACE FUNCTION emp_comp (
p_sal NUMBER,
p_comm NUMBER
) RETURN NUMBER
IS
BEGIN
RETURN (p_sal + NVL(p_comm, 0)) * 24;
END emp_comp;
次の例は、関数宣言でAUTHID CURRENT_USER句とSTRICTキーワードを使用する方法を示しています。
CREATE OR REPLACE FUNCTION dept_salaries(dept_id int) RETURN NUMBER
STRICT
AUTHID CURRENT_USER
BEGIN
RETURN QUERY (SELECT sum(salary) FROM emp WHERE deptno = id);
END;
渡された入力パラメーターが NULLの 場合 、サーバーに NULL を戻すように指示 する STRICT キーワードを 組み込み ます NULL が渡された 場合 、この関数は実行されません。
DEPT _ 給与の 関数は、関数を呼び出している役割の権限で実行されます。 現在のユーザーに (従業員の給与を表示 するために) emp 表を 照会する SELECT ステートメント を実行するための十分な特権がない場合、 関数はエラーを報告します。関数を定義したロールに関連付けられた権限を使用するようにサーバーに指示するには、 AUTHID AUTHIDを 持つ CURRENT _ USER DEFINER 句。
3.2.4.2 関数の呼び出し
関数は、式が SPL ステートメント 内に現れる場所であれば、どこでも使用できます 。ファンクションは、その名前の後に括弧で囲まれたパラメータがあればそれを指定することによって呼び出されます。
name [ ([ parameters ]) ]
name は関数の名前です。 parameters は実際のパラメータのリストです。
注意:渡される実際のパラメータがない場合は、空のパラメータリストを使用して関数を呼び出すことも、開かれたかっこを完全に省略することもできます。
以下は、別の SPLプログラムから関数を呼び出す方法を示しています
BEGIN
DBMS_OUTPUT.PUT_LINE(simple_function);
END;
 
That's All Folks!
関数は、通常 、次のように SQL 文内で 使用され ます。
SELECT empno "EMPNO", ename "ENAME", sal "SAL", comm "COMM",
emp_comp(sal, comm) "YEARLY COMPENSATION" FROM emp;
 
EMPNO | ENAME | SAL | COMM | YEARLY COMPENSATION
-------+--------+---------+---------+---------------------
7369 | SMITH | 800.00 | | 19200.00
7499 | ALLEN | 1600.00 | 300.00 | 45600.00
7521 | WARD | 1250.00 | 500.00 | 42000.00
7566 | JONES | 2975.00 | | 71400.00
7654 | MARTIN | 1250.00 | 1400.00 | 63600.00
7698 | BLAKE | 2850.00 | | 68400.00
7782 | CLARK | 2450.00 | | 58800.00
7788 | SCOTT | 3000.00 | | 72000.00
7839 | KING | 5000.00 | | 120000.00
7844 | TURNER | 1500.00 | 0.00 | 36000.00
7876 | ADAMS | 1100.00 | | 26400.00
7900 | JAMES | 950.00 | | 22800.00
7902 | FORD | 3000.00 | | 72000.00
7934 | MILLER | 1300.00 | | 31200.00
(14 rows)
3.2.4.3 関数の削除
機能は、 DROP FUNCTION コマンド を使用してデータベースから削除することができます
DROP FUNCTION [ IF EXISTS ] name [ ( parameters ) ]
[ CASCADE | RESTRICT ];
ここで、 nameは削除する関数の名前です。
注意:パラメータリストの指定は、オーバーロードされた関数など、特定の状況下でAdvanced Serverで必要です。 Oracleでは、パラメータ・リストを常に省略する必要があります。
注: IF EXISTSCASCADE 、またはRESTRICTの使用法は、Oracleデータベースとの互換性がありません。これらのオプションの詳細は、 「Oracle Database開発者リファレンスガイド」のデータベース互換性DROP FUNCTIONコマンドを参照してください。
この例では、以前に作成された関数が削除されます。
DROP FUNCTION simple_function;
 
3.2.5 プロシージャと関数のパラメータ
プロシージャと関数を使用する重要な側面は、呼び出し元プログラムからプロシージャまたはファンクションにデータを渡し、プロシージャまたはファンクションからデータを戻す機能です。これは パラメータ を使用して実行され ます
パラメーターは、プロシージャーまたは関数の名前の後にかっこで囲まれたプロシージャーまたは関数の定義で宣言されます。プロシージャまたは関数定義で宣言されたパラメータは、 仮パラメータ として知られてい ます 。プロシージャまたは関数が呼び出されると、呼び出し側プログラムは、呼び出されたプログラムの処理で使用される実際のデータと、呼び出されたプログラムの処理の結果を受け取る変数を提供します。プロシージャまたは関数が呼び出されたときに呼び出しプログラムによって供給されるデータおよび変数は、 実際のパラメータと呼ばれます
以下は、仮パラメータ宣言の一般的な形式です。
( name [ IN | OUT | IN OUT ] data_type [ DEFAULT value ])
name は、仮パラメータに割り当てられた識別子です。 INを 指定すると、 IN はプロシージャーまたは関数への入力データを受け取るためのパラメーターを定義します。 IN パラメータは、デフォルト値に初期化することができます。指定すると、 OUT はプロシージャまたは関数からデータを戻すためのパラメータを定義します。 IN OUTを 指定すると、 入力と出力の両方にパラメーターを使用できます。 IN のすべて 、OUT、および OUTを 省略している 場合 、パラメータ は、それが デフォルトで よう定義されていたかのように機能し ます。パラメータが IN OUT 、または IN OUTの いずれであるか は、パラメータの モード と呼ばれ ます data_typeは、パラメータのデータ型を定義します。 valueは、コールで実際のパラメータが指定されていない場合、呼び出されたプログラムのINパラメータに割り当てられたデフォルト値です。
次に、パラメータを取るプロシージャの例を示します。
CREATE OR REPLACE PROCEDURE emp_query (
p_deptno IN NUMBER,
p_empno IN OUT NUMBER,
p_ename IN OUT VARCHAR2,
p_job OUT VARCHAR2,
p_hiredate OUT DATE,
p_sal OUT NUMBER
)
IS
BEGIN
SELECT empno, ename, job, hiredate, sal
INTO p_empno, p_ename, p_job, p_hiredate, p_sal
FROM emp
WHERE deptno = p_deptno
AND (empno = p_empno
OR ename = UPPER(p_ename));
END;
この例では、 p_deptno IN 仮パラメータであり、 p_empno および p_ename IN OUT 仮パラメータであり、 p_job p_hiredate および p_sal OUT 仮パラメータです。
注: 前の例では、 VARCHAR2 パラメーター に最大長が指定されて おらず、 NUMBERパラメーターに精度と位取りが指定されていませんでした 。パラメータの宣言に長さ、精度、スケールなどの制約を指定することはできません。これらの制約は、プロシージャまたは関数の呼び出し時に使用される実際のパラメータから自動的に継承されます。
emp_query手順は、それを実際のパラメータを渡し、他のプログラムから呼び出すことができます。以下は、 emp_queryを呼び出す別のSPLプログラムの例です。
DECLARE
v_deptno NUMBER(2);
v_empno NUMBER(4);
v_ename VARCHAR2(10);
v_job VARCHAR2(9);
v_hiredate DATE;
v_sal NUMBER;
BEGIN
v_deptno := 30;
v_empno := 7900;
v_ename := '';
emp_query(v_deptno, v_empno, v_ename, v_job, v_hiredate, v_sal);
DBMS_OUTPUT.PUT_LINE('Department : ' || v_deptno);
DBMS_OUTPUT.PUT_LINE('Employee No: ' || v_empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || v_ename);
DBMS_OUTPUT.PUT_LINE('Job : ' || v_job);
DBMS_OUTPUT.PUT_LINE('Hire Date : ' || v_hiredate);
DBMS_OUTPUT.PUT_LINE('Salary : ' || v_sal);
END;
この例では、 v_deptno v_empno v_ename v_job v_hiredate 、および v_salが実際のパラメータです。
前の例の出力は次のように表示されます。
Department : 30
Employee No: 7900
Name : JAMES
Job : CLERK
Hire Date : 03-DEC-81
Salary : 950
3.2.5.1 位置指定と名前付きパラメータの表記
関数またはプロシージャーにパラメーターを渡すときは、 定位置または名前付きのパラメーター表記を使用できます。位置指定表記を使用してパラメータを指定する場合、宣言されている順序でパラメータをリストする必要があります。名前付き表記でパラメータを指定すると、パラメータの順序は重要ではありません。
名前付き表記法を使用してパラメーターを指定するには、各パラメーターの名前と、矢印( => )およびパラメーター値をリストします。名前付き表記はより冗長ですが、コードを読みやすく保守しやすくなります。
位置指定された名前付きの表記法を使用した簡単な例を次に示します。
プロシージャの作成または置換emp_info(
p_deptno IN NUMBER、
p_empno IN OUT NUMBER、
p_ename IN OUT VARCHAR2、
IS
ベギン
dbms_output.put_line( 'Department Number =' || p_deptno);
dbms_output.put_line( '従業員番号=' || p_empno);
dbms_output.put_line( 'Employee Name =' || p_ename;
終わり;
位置指定表記を使用してプロシージャを呼び出すには、次のように渡します。
emp_info(30、7455、 'Clark');
名前付き表記を使用してプロシージャを呼び出すには、次のように渡します。
emp_info(p_ename => 'クラーク'、p_empno => 7455、p_deptno => 30);
名前付き表記を使用すると、パラメータリストが変更された場合、パラメータの順序が変更された場合、または新しいオプションのパラメータが追加された場合に、プロシージャのパラメータリストを再配置する必要性が軽減されます。
引数のデフォルト値があり、引数が後続の引数ではない場合は、名前付き表記を使用してプロシージャまたは関数を呼び出す必要があります。以下のケースでは、2つの主要なデフォルト引数を持つプロシージャーを示しています。
check_balanceを作成または置換する(check_balance
p_customerID IN NUMBER DEFAULT NULL、
p_balance IN NUMBER DEFAULT NULL、
p_amount IN NUMBER
IS
宣言
バランスNUMBER;
ベギン
IF(p_バランスがNULLで、p_customerIDがNULLの場合)THEN
RAISE_APPLICATION_ERROR
(-20010、 'バランスまたは顧客を提供しなければならない');
ELSEIF(p_balanceはNULLではなく、p_customerIDはNULLではない)
RAISE_APPLICATION_ERROR
(-20020、 '両方を提供する必要はありません。
ELSEIF(p_バランスがNULL)THEN
残高:= getCustomerBalance(p_customerID);
ELSE
バランス:= p_バランス。
END IF;
IF(金額>残高)THEN
RAISE_APPLICATION_ERROR
(-20030、 '残高不足');
END IF;
終わり;
名前付き表記を使用して、末尾にない引数値(このプロシージャを呼び出すとき)を省略することができます。位置表記法を使用する場合、後続の引数だけがデフォルトになります。このプロシージャは、次の引数で呼び出すことができます。
check_balance(p_customerID => 10、p_amount = 500.00)
 
check_balance(p_balance => 1000.00、p_amount = 500.00)
位置指定と名前付き表記(混合表記)の組み合わせを使用して、パラメーターを指定することができます。混合パラメータの表記法を使用した簡単な例を次に示します。
プロシージャの作成または置換emp_info(
p_deptno IN NUMBER、
p_empno IN OUT NUMBER、
p_ename IN OUT VARCHAR2、
IS
ベギン
dbms_output.put_line( 'Department Number =' || p_deptno);
dbms_output.put_line( '従業員番号=' || p_empno);
dbms_output.put_line( 'Employee Name =' || p_ename;
終わり;
混合表記を使用してプロシージャを呼び出すことができます。
emp_info(30、p_ename => 'Clark'、p_empno => 7455);
混合表記を使用する場合は、名前付き引数は位置引数の前に指定できないことに注意してください。
3.2.5.2 パラメータモード
前に説明したように、パラメータは3つの可能なモードの1つ、 IN OUT 、または IN OUTの いずれかを 持ちます 。仮パラメータの次の特性は、そのモードに依存します。
次の表は、モードに応じたパラメータの動作をまとめたものです。
表3-1パラメータモード
表に示すように、 IN 仮パラメータは、デフォルト値で明示的に初期化されない限り、呼び出される実際のパラメータに初期化されます。 IN パラメータが呼ばれるプログラム内で参照することができる、しかし、と呼ばれるプログラムは、IN パラメータ に新しい値を割り当てることはできません 。制御が呼び出し元のプログラムに戻った後、実際のパラメータには、呼び出し前に設定されたのと同じ値が常に含まれます。
OUT仮パラメータは、それが呼び出されると、実際のパラメータに初期化されます。呼び出されるプログラムは、仮パラメータに新しい値を参照して割り当てることができます。呼び出されたプログラムが例外なく終了した場合、実際のパラメーターは仮パラメーターで最後に設定された値をとります。処理された例外が発生した場合、実パラメータの値は仮パラメータに割り当てられた最後の値をとります。未処理の例外が発生した場合、実際のパラメータの値は呼び出し前の状態のままです。
INパラメータと同様に、 IN OUT仮パラメータは、呼び出された実際のパラメータに初期化されます。 OUTパラメータと同様に、 IN OUT仮パラメータは被呼び出しプログラムによって変更可能であり、呼び出されたプログラムが例外なく終了する場合、仮パラメータの最後の値が呼び出しプログラムの実際のパラメータに渡されます。処理された例外が発生した場合、実パラメータの値は仮パラメータに割り当てられた最後の値をとります。未処理の例外が発生した場合、実際のパラメータの値は呼び出し前の状態のままです。
3.2.5.3 パラメータのデフォルト値の使用
DEFAULTを含めるか、 CREATE PROCEDUREまたはCREATE FUNCTIONステートメントで代入演算子( := )を使用することによって、仮パラメーターのデフォルト値を設定できます
仮パラメータ宣言の一般的な形式は次のとおりです。
( name [ IN | OUT | IN OUT ] data_type [{DEFAULT | := } expr ])
name は、パラメータに割り当てられた識別子です。
IN | OUT | IN OUT は、パラメータモードを指定します。
data_type は、変数に割り当てられたデータ型です。
expr は、パラメータに割り当てられたデフォルト値です。 DEFAULT を指定しない場合 、呼び出し元はパラメータの値を指定する必要があります。
デフォルト値は、関数またはプロシージャーが呼び出されるたびに評価されます。たとえば、 DATE型のパラメータにSYSDATE代入すると、プロシージャまたはファンクションが作成された時刻ではなく、現在の呼び出しの時刻がパラメータに設定されます。
次の簡単な手順は、代入演算子を使用して、 SYSDATEの デフォルト値を hiredateパラメータに設定する方法を示しています
CREATE OR REPLACE PROCEDURE hire_emp (
p_empno NUMBER,
p_ename VARCHAR2,
p_hiredate DATE := SYSDATE
)
IS
BEGIN
INSERT INTO emp(empno, ename, hiredate)
VALUES(p_empno, p_ename, p_hiredate);
 
DBMS_OUTPUT.PUT_LINE('Hired!');
END hire_emp;
パラメータ宣言にデフォルト値が含まれている場合は、プロシージャを呼び出すときに実際のパラメータリストからパラメータを省略できます。 サンプル手続き( hire_emp )の 呼び出しには 、従業員番号( p_empno )と従業員名( p_empno )の 2つの引数が含まれていなければなりません 。 3番目のパラメータ( p_hiredate )のデフォルトは SYSDATE の値です
hire_emp (7575, Clark)
プロシージャを呼び出すときに実際のパラメータの値を含めると、その値がデフォルト値よりも優先されます。
hire_emp (7575, Clark, 15-FEB-2010)
SYSDATEの 現在の値に関係なく 、2010年2月15日の 雇用者を持つ新しい従業員を追加し ます。
代入演算子に DEFAULT キーワードを 代入すると、同じプロシージャを記述できます
CREATE OR REPLACE PROCEDURE hire_emp (
p_empno NUMBER,
p_ename VARCHAR2,
p_hiredate DATE DEFAULT SYSDATE
)
IS
BEGIN
INSERT INTO emp(empno, ename, hiredate)
VALUES(p_empno, p_ename, p_hiredate);
 
DBMS_OUTPUT.PUT_LINE('Hired!');
END hire_emp;
3.2.6 サブプログラム - サブプロシージャとサブ関数
SPLプロシージャおよび機能プログラムの能力および機能は、SPLコードをサブプロシージャおよびサブファンクションに編成することによって、適切に構成され維持可能なプログラムを構築するのに有利な方法で使用することができる。
同じSPLコードは、SPLプログラム内のサブプロシージャとサブファンクションを宣言することによって、比較的大きなSPLプログラム内の異なる場所から複数回呼び出すことができます。
サブプロシージャおよびサブファンクションには、次の特性があります。
サブプロシージャおよびサブファンクションの構文、構造および機能は、スタンドアロンのプロシージャおよびファンクションと実質的に同じです。主な違いは 、サブプログラムを宣言するためにCREATE PROCEDUREまたはCREATE FUNCTIONの代わりにキーワード PROCEDUREまたはFUNCTIONを 使用することです。
サブプロシージャおよびサブファンクションは、次のタイプのSPLプログラムのいずれかから宣言して呼び出すことができます。
サブプロシージャとサブ関数の構造とアクセスに関する規則については、次のセクションで詳しく説明します。
3.2.6.1 サブプロシージャの作成
宣言部で指定されたプロシージャの句は、そのブロックにローカルサブプロシージャを定義し、名前。
ブロック という用語は、オプションの宣言セクション、必須の実行可能セクション、およびオプションの例外セクションで構成されるSPLブロック構造を指します。ブロックは、スタンドアロンのプロシージャおよびファンクション、匿名ブロック、サブプログラム、トリガ、パッケージおよびオブジェクト型メソッドの構造です。
識別子がブロックに対してローカルである という句 、識別子(つまり、変数、カーソル、タイプ、またはサブプログラム)がそのブロックの宣言セクション内で宣言されていることを示します。したがって、実行可能セクション内のSPLコードとオプションそのブロックの例外セクション。
サブプロシージャは 、宣言セクションに含まれる 他のすべての 変数、カーソル、およびタイプ宣言の 後にのみ宣言でき ます。 (つまり、サブプログラムは最後の宣言のセットでなければなりません)。
PROCEDURE name [ ( parameters ) ]
{ IS | AS }
[ PRAGMA AUTONOMOUS_TRANSACTION; ]
[ declarations ]
BEGIN
statements
END [ name ];
場所:
name はサブプロシージャの識別子です。
パラメーター
parameters は仮パラメータのリストです。
PRAGMA AUTONOMOUS_TRANSACTION
PRAGMA AUTONOMOUS_TRANSACTION は、サブプロシージャを自律型トランザクションとして設定するディレクティブです。
宣言
宣言 は、変数、カーソル、型、または副プログラムの宣言です。サブプログラム宣言が含まれている場合は、他のすべての変数宣言、カーソル宣言、および型宣言の後に宣言する必要があります。
ステートメント
ステートメント SPL プログラムステートメントです( BEGIN - END ブロックには EXCEPTIONセクションが含まれる場合があります )。
次の例は、無名ブロック内のサブプロシージャです。
DECLARE
PROCEDURE list_emp
IS
v_empno NUMBER(4);
v_ename VARCHAR2(10);
CURSOR emp_cur IS
SELECT empno, ename FROM emp ORDER BY empno;
BEGIN
OPEN emp_cur;
DBMS_OUTPUT.PUT_LINE('Subprocedure list_emp:');
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH emp_cur INTO v_empno, v_ename;
EXIT WHEN emp_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_ename);
END LOOP;
CLOSE emp_cur;
END;
BEGIN
list_emp;
END;
この無名ブロックを呼び出すと、次の出力が生成されます。
Subprocedure list_emp:
EMPNO ENAME
----- -------
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER
次の例は、トリガー内のサブプロシージャです。
CREATE OR REPLACE TRIGGER dept_audit_trig
AFTER INSERT OR UPDATE OR DELETE ON dept
DECLARE
v_action VARCHAR2(24);
PROCEDURE display_action (
p_action IN VARCHAR2
)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('User ' || USER || ' ' || p_action ||
' dept on ' || TO_CHAR(SYSDATE,'YYYY-MM-DD'));
END display_action;
BEGIN
IF INSERTING THEN
v_action := 'added';
ELSIF UPDATING THEN
v_action := 'updated';
ELSIF DELETING THEN
v_action := 'deleted';
END IF;
display_action(v_action);
END;
このトリガーを呼び出すと、次の出力が生成されます。
INSERT INTO dept VALUES (50,'HR','DENVER');
 
User enterprisedb added dept on 2016-07-26
3.2.6.2サブ関数の作成
宣言部で指定された機能の句は、そのブロックにローカルサブファンクションを定義し、名前。
ブロック という用語は、オプションの宣言セクション、必須の実行可能セクション、およびオプションの例外セクションで構成されるSPLブロック構造を指します。ブロックは、スタンドアロンのプロシージャおよびファンクション、匿名ブロック、サブプログラム、トリガ、パッケージおよびオブジェクト型メソッドの構造です。
識別子がブロックに対してローカルである という句 、識別子(つまり、変数、カーソル、タイプ、またはサブプログラム)がそのブロックの宣言セクション内で宣言されていることを示します。したがって、実行可能セクション内のSPLコードとオプションそのブロックの例外セクション。
FUNCTION name [ ( parameters ) ]
RETURN data_type
{ IS | AS }
[ PRAGMA AUTONOMOUS_TRANSACTION; ]
[ declarations ]
BEGIN
statements
END [ name ];
場所:
name はサブ関数の識別子です。
パラメーター
parameters は仮パラメータのリストです。
データ・タイプ
data_typeは、関数のRETURNステートメントによって返された値のデータ型です。
PRAGMA AUTONOMOUS_TRANSACTION
PRAGMA AUTONOMOUS_TRANSACTION は、サブ機能を自律型トランザクションとして設定するディレクティブです。
宣言
宣言 は、変数、カーソル、型、または副プログラムの宣言です。サブプログラム宣言が含まれている場合は、他のすべての変数宣言、カーソル宣言、および型宣言の後に宣言する必要があります。
ステートメント
ステートメント SPL プログラムステートメントです( BEGIN - END ブロックには EXCEPTIONセクションが含まれる場合があります )。
次の例は、再帰的サブ関数の使用方法を示しています。
DECLARE
FUNCTION factorial (
n BINARY_INTEGER
) RETURN BINARY_INTEGER
IS
BEGIN
IF n = 1 THEN
RETURN n;
ELSE
RETURN n * factorial(n-1);
END IF;
END factorial;
BEGIN
FOR i IN 1..5 LOOP
DBMS_OUTPUT.PUT_LINE(i || '! = ' || factorial(i));
END LOOP;
END;
この例の出力は次のとおりです。
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
3.2.6.3 ブロック関係
このセクションでは、SPLプログラムで宣言できるブロック間の関係の用語について説明します。ブロック内で宣言されたサブプログラムおよびアクセス識別子を呼び出す機能は、この関係によって異なります。
基本的な用語は次のとおりです。
ブロックは、オプションの宣言セクション、必須の実行部、およびオプションの例外部からなる基本的なSPL構造です。ブロックは、スタンドアロンのプロシージャおよび関数プログラム、匿名ブロック、トリガ、パッケージ、サブプロシージャおよびサブファンクションを実装します。
ブロックにローカル な識別子(変数、カーソル、タイプ、またはサブプログラム)は、そのブロックの宣言セクション内で宣言されていることを意味します。そのようなローカル識別子はブロックの実行可能セクションとオプションの例外セクションからアクセスできます。
親ブロックは別のブロック( 子ブロック )の宣言が含まれています。
降順ブロックは、特定の親ブロックから開始して子関係を形成するブロックの集合です。
祖先ブロックは、与えられた子ブロックから始まる親の関係を形成するブロックの集合である。
レベルが最も高い、先祖ブロックから所定ブロックの序数です。たとえば、スタンドアロン・プロシージャでは、このプロシージャの宣言セクション内で宣言されたサブプログラムはすべて同じレベルにあります(たとえば、レベル1と呼びます)。スタンドアロン・プロシージャで宣言されたサブプログラムの宣言セクション内の追加サブプログラムは、レベルはレベル2です。
兄弟ブロックは (つまり、それらはすべてローカルに同じブロック内で宣言されている)同じ親ブロックを持つブロックのセットです。兄弟ブロックも常に同じレベルにあります。
一連のプロシージャ宣言セクションの次の図は、ブロックのセットの例とその周囲のブロックとの関係を示しています。
ブロックの左側の2本の垂直線は、2対の兄弟ブロックがあることを示している。 block_1ablock_1bは1つのペアであり、 block_2ablock_2bは第2のペアです。
各ブロックとその祖先との関係は、ブロックの右側に示されています。最下位レベルの子ブロックから階層を進めるときに形成される3つの階層パスがあります。最初の構成要素は block_0、block_1a、block_2a、およびblock_3。 2番目はblock_0block_1ablock_2bです。 3番目はblock_0block_1bblock_2bです。

CREATE PROCEDURE block_0
IS
.
+---- PROCEDURE block_1a ------- Local to block_0
| IS
| . |
| . |
| . |
| +-- PROCEDURE block_2a ---- Local to block_1a and descendant
| | IS of block_0
| | . |
| | . |
| | . |
| | PROCEDURE block_3 -- Local to block_2a and descendant
| | IS of block_1a, and block_0
| Siblings . |
| | . |
| | . |
| | END block_3; |
| | END block_2a; |
| +-- PROCEDURE block_2b ---- Local to block_1a and descendant
| | IS of block_0
Siblings | , |
| | . |
| | . |
| +-- END block_2b; |
| |
| END block_1a; ---------+
+---- PROCEDURE block_1b; ------- Local to block_0
| IS
| . |
| . |
| . |
| PROCEDURE block_2b ---- Local to block_1b and descendant
| IS of block_0
| . |
| . |
| . |
| END block_2b; |
| |
+---- END block_1b; ---------+
BEGIN
.
.
.
END block_0;
ブロック位置に基づいてサブプログラムを呼び出す規則については、 3.2.6.4 項で 説明します。ブロックの位置に基づいて変数にアクセスするためのルールは、セクション3.2.6.7で説明されています。
3.2.6.4 サブプログラムの起動
サブプログラムは、名前と実際のパラメータを指定することによって、スタンドアロンのプロシージャまたはファンクションと同じ方法で呼び出されます。
サブプログラムは、サブプログラムが宣言されている先祖階層を形成する親サブプログラムまたはラベル付き無名ブロックの名前であるなし、1つ、または複数の修飾子を指定して呼び出すことができます。
呼び出しは、サブプログラム名とその引き数で終わる修飾子のドット区切りリストとして指定され、次のようになります。
[[ qualifier_1 .][...] qualifier_n .] subprog [( arguments )]
指定された場合は、 qualifier_nは subprogはその宣言セクションで宣言されたサブプログラムです。修飾子の前のリストには、最大連続した経路qualifier_1するqualifier_nから階層内に存在しなければなりません。 qualifier_1は、パス内の任意の祖先サブプログラムでも、次のいずれかです。
宣言セクションが存在する場合 DECLARE キーワードの前に、 宣言セクションがない場合 BEGIN キーワードの 前に 含まれる無名ブロックラベル
注意: qualifier_1はスキーマ名ではない可能性があります。それ以外の場合は、サブプログラムの起動時にエラーがスローされます。このAdvanced Serverの制限は、スキーマ名を修飾子として使用できるOracleデータベースとは互換性がありません。
arguments は、サブ手続きまたはサブ関数に渡される実際のパラメータのリストです。
起動時に、サブプログラムの検索は次のように行われます。
注意:サブプログラム起動のためのAdvanced Server検索アルゴリズムは、Oracleデータベースとあまり互換性がありません。 Oracleの場合、最初の修飾子( qualifier_1 )の最初の一致が検索されます。このような一致が見つかると、残りのすべての修飾子、サブプログラム名、サブプログラムのタイプ、および呼び出しの引数が、一致する第1修飾子が見つかる階層コンテンツと一致しなければなりません。そうでない場合はエラーがスローされます。 Advanced Serverの場合、呼び出しのすべての修飾子、サブプログラム名、およびサブプログラムの型が階層の内容と一致しない限り、一致が見つかりません。このような完全一致が最初に見つからない場合、Advanced Serverは検索を続けて階層を上に進めます。
呼び出し元のブロックに対する相対的なサブプログラムの位置は、次のようにしてアクセスできます。
ただし、サブプログラムの次の場所は、呼び出し元のブロックからはアクセスできません。
以下の例は、前述の様々な条件を説明する。
ローカル宣言されたサブプログラムの呼び出し
次の例には、スタンドアロン・プロシージャ level_0に 含まれるブロックの単一の階層が含まれています 。プロシージャーlevel_1aの実行可能セクション内には、修飾子の有無にかかわらず、ローカル・プロシージャーlevel_2aを呼び出す手段が示されています。
また、ローカルプロシージャの子孫へのアクセス注意手順level_3aあるlevel_2aを 、または修飾子なしに、許可されません。これらの呼び出しは、この例ではコメントアウトされています。
CREATE OR REPLACE PROCEDURE level_0
IS
PROCEDURE level_1a
IS
PROCEDURE level_2a
IS
PROCEDURE level_3a
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('........ BLOCK level_3a');
DBMS_OUTPUT.PUT_LINE('........ END BLOCK level_3a');
END level_3a;
BEGIN
DBMS_OUTPUT.PUT_LINE('...... BLOCK level_2a');
DBMS_OUTPUT.PUT_LINE('...... END BLOCK level_2a');
END level_2a;
BEGIN
DBMS_OUTPUT.PUT_LINE('.. BLOCK level_1a');
level_2a; -- Local block called
level_1a.level_2a; -- Qualified local block called
level_0.level_1a.level_2a; -- Double qualified local block called
-- level_3a; -- Error - Descendant of local block
-- level_2a.level_3a; -- Error - Descendant of local block
DBMS_OUTPUT.PUT_LINE('.. END BLOCK level_1a');
END level_1a;
BEGIN
DBMS_OUTPUT.PUT_LINE('BLOCK level_0');
level_1a;
DBMS_OUTPUT.PUT_LINE('END BLOCK level_0');
END level_0;
スタンドアロン・プロシージャが呼び出される場合、出力は、プロシージャことを示し、以下の通りである level_2aが正常手順level_1aの実行可能セクションのコールから呼び出されます。
BEGIN
level_0;
END;
 
BLOCK level_0
.. BLOCK level_1a
...... BLOCK level_2a
...... END BLOCK level_2a
...... BLOCK level_2a
...... END BLOCK level_2a
...... BLOCK level_2a
...... END BLOCK level_2a
.. END BLOCK level_1a
END BLOCK level_0
子孫ブロックへの呼び出しのいずれかを非コメント化してlevel_0 プロシージャを実行しようとすると、エラーが発生します。
祖先ブロックで宣言されたサブプログラムの呼び出し
次の例は、呼び出しが行われたブロックを基準にして、親ブロックおよび他の祖先ブロックで宣言されているサブプログラムを呼び出す方法を示しています。
この例では、プロシージャの実行可能セクション level_3a親ブロックである手順level_2aを呼び出します。 (無限ループを避けるためにv_cntが使用されることに注意してください)。
CREATE OR REPLACE PROCEDURE level_0
IS
v_cnt NUMBER(2) := 0;
PROCEDURE level_1a
IS
PROCEDURE level_2a
IS
PROCEDURE level_3a
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('........ BLOCK level_3a');
v_cnt := v_cnt + 1;
IF v_cnt < 2 THEN
level_2a; -- Parent block called
END IF;
DBMS_OUTPUT.PUT_LINE('........ END BLOCK level_3a');
END level_3a;
BEGIN
DBMS_OUTPUT.PUT_LINE('...... BLOCK level_2a');
level_3a; -- Local block called
DBMS_OUTPUT.PUT_LINE('...... END BLOCK level_2a');
END level_2a;
BEGIN
DBMS_OUTPUT.PUT_LINE('.. BLOCK level_1a');
level_2a; -- Local block called
DBMS_OUTPUT.PUT_LINE('.. END BLOCK level_1a');
END level_1a;
BEGIN
DBMS_OUTPUT.PUT_LINE('BLOCK level_0');
level_1a;
DBMS_OUTPUT.PUT_LINE('END BLOCK level_0');
END level_0;
結果は次のようになります。
BEGIN
level_0;
END;
 
BLOCK level_0
.. BLOCK level_1a
...... BLOCK level_2a
........ BLOCK level_3a
...... BLOCK level_2a
........ BLOCK level_3a
........ END BLOCK level_3a
...... END BLOCK level_2a
........ END BLOCK level_3a
...... END BLOCK level_2a
.. END BLOCK level_1a
END BLOCK level_0
同様の例では、手続き level_3aの 実行可能セクションは手続き level_1aを呼び出す。手続きlevel_1aは上位階層の上にある。 (無限ループを避けるためにv_cntが使用されることに注意してください)。
CREATE OR REPLACE PROCEDURE level_0
IS
v_cnt NUMBER(2) := 0;
PROCEDURE level_1a
IS
PROCEDURE level_2a
IS
PROCEDURE level_3a
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('........ BLOCK level_3a');
v_cnt := v_cnt + 1;
IF v_cnt < 2 THEN
level_1a; -- Ancestor block called
END IF;
DBMS_OUTPUT.PUT_LINE('........ END BLOCK level_3a');
END level_3a;
BEGIN
DBMS_OUTPUT.PUT_LINE('...... BLOCK level_2a');
level_3a; -- Local block called
DBMS_OUTPUT.PUT_LINE('...... END BLOCK level_2a');
END level_2a;
BEGIN
DBMS_OUTPUT.PUT_LINE('.. BLOCK level_1a');
level_2a; -- Local block called
DBMS_OUTPUT.PUT_LINE('.. END BLOCK level_1a');
END level_1a;
BEGIN
DBMS_OUTPUT.PUT_LINE('BLOCK level_0');
level_1a;
DBMS_OUTPUT.PUT_LINE('END BLOCK level_0');
END level_0;
結果は次のようになります。
BEGIN
level_0;
END;
 
BLOCK level_0
.. BLOCK level_1a
...... BLOCK level_2a
........ BLOCK level_3a
.. BLOCK level_1a
...... BLOCK level_2a
........ BLOCK level_3a
........ END BLOCK level_3a
...... END BLOCK level_2a
.. END BLOCK level_1a
........ END BLOCK level_3a
...... END BLOCK level_2a
.. END BLOCK level_1a
END BLOCK level_0
兄弟ブロックで宣言されたサブプログラムの呼び出し
次の例は、サブプログラムの呼び出しが行われたローカル、親、または他の祖先ブロックに対して、兄弟ブロックで宣言されたサブプログラムを呼び出す方法を示しています。
この例では、プロシージャの実行可能セクション level_1bは、その兄弟ブロックである手順level_1aを呼び出します。両方ともスタンドアロンのプロシージャlevel_0に対してローカルです
呼び出し注意 level_2aのまたは等価的手順level_1b内からlevel_1a.level_2aは、このコールがエラーをもたらすようにコメントアウトされています。兄弟ブロック( level_1a )の子孫サブプログラム( level_2a )を呼び出すことはできません。
CREATE OR REPLACE PROCEDURE level_0
IS
v_cnt NUMBER(2) := 0;
PROCEDURE level_1a
IS
PROCEDURE level_2a
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('...... BLOCK level_2a');
DBMS_OUTPUT.PUT_LINE('...... END BLOCK level_2a');
END level_2a;
BEGIN
DBMS_OUTPUT.PUT_LINE('.. BLOCK level_1a');
DBMS_OUTPUT.PUT_LINE('.. END BLOCK level_1a');
END level_1a;
PROCEDURE level_1b
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('.. BLOCK level_1b');
level_1a; -- Sibling block called
-- level_2a; -- Error – Descendant of sibling block
-- level_1a.level_2a; -- Error - Descendant of sibling block
DBMS_OUTPUT.PUT_LINE('.. END BLOCK level_1b');
END level_1b;
BEGIN
DBMS_OUTPUT.PUT_LINE('BLOCK level_0');
level_1b;
DBMS_OUTPUT.PUT_LINE('END BLOCK level_0');
END level_0;
結果は次のようになります。
BEGIN
level_0;
END;
 
BLOCK level_0
.. BLOCK level_1b
.. BLOCK level_1a
.. END BLOCK level_1a
.. END BLOCK level_1b
END BLOCK level_0
次の例では、プロシージャプロシージャlevel_3bの祖先が正常に起動されている手順level_1bの兄弟であるlevel_1a、。
CREATE OR REPLACE PROCEDURE level_0
IS
PROCEDURE level_1a
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('.. BLOCK level_1a');
DBMS_OUTPUT.PUT_LINE('.. END BLOCK level_1a');
END level_1a;
PROCEDURE level_1b
IS
PROCEDURE level_2b
IS
PROCEDURE level_3b
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('........ BLOCK level_3b');
level_1a; -- Ancestor's sibling block called
level_0.level_1a; -- Qualified ancestor's sibling block
DBMS_OUTPUT.PUT_LINE('........ END BLOCK level_3b');
END level_3b;
BEGIN
DBMS_OUTPUT.PUT_LINE('...... BLOCK level_2b');
level_3b; -- Local block called
DBMS_OUTPUT.PUT_LINE('...... END BLOCK level_2b');
END level_2b;
BEGIN
DBMS_OUTPUT.PUT_LINE('.. BLOCK level_1b');
level_2b; -- Local block called
DBMS_OUTPUT.PUT_LINE('.. END BLOCK level_1b');
END level_1b;
BEGIN
DBMS_OUTPUT.PUT_LINE('BLOCK level_0');
level_1b;
DBMS_OUTPUT.PUT_LINE('END BLOCK level_0');
END level_0;
結果は次のようになります。
BEGIN
level_0;
END;
 
BLOCK level_0
.. BLOCK level_1b
...... BLOCK level_2b
........ BLOCK level_3b
.. BLOCK level_1a
.. END BLOCK level_1a
.. BLOCK level_1a
.. END BLOCK level_1a
........ END BLOCK level_3b
...... END BLOCK level_2b
.. END BLOCK level_1b
END BLOCK level_0
3.2.6.5 前方宣言の使用
これまでに説明したように、サブプログラムを呼び出すときは、スタンドアロンプ​​ログラム内のブロックの階層のどこかで、呼び出される前に宣言されていなければなりません。言い換えれば、SPLコードを最初から最後までスキャンするときは、サブプログラムの宣言をその呼び出しの前に見つける必要があります。
ただし、コード内のポイントの後にSPLコードにサブプログラムの完全な宣言(つまり、オプションの宣言セクション、必須実行可能セクション、およびオプションの例外セクション)が表示されるように、SPLコードを作成する方法があります。呼び出されます。
これは 、呼び出しの前にSPLコードに前方宣言挿入することによって実現されます。前方宣言は、サブプロシージャーまたはサブ関数名、仮パラメーター、およびそれがサブ関数の場合の戻りタイプの指定です。
オプションの宣言セクション、実行可能セクション、およびオプションの例外セクションで構成される完全なサブプログラム仕様は、前方宣言と同じ宣言セクションで指定する必要がありますが、前方宣言でこのサブプログラムを呼び出す他のサブプログラム宣言の後に表示することもできます。
フォワード宣言の一般的な使用法は、次のように2つのサブプログラムが互いに呼び出す場合です。
DECLARE
FUNCTION add_one (
p_add IN NUMBER
) RETURN NUMBER;
FUNCTION test_max (
p_test IN NUMBER)
RETURN NUMBER
IS
BEGIN
IF p_test < 5 THEN
RETURN add_one(p_test);
END IF;
DBMS_OUTPUT.PUT('Final value is ');
RETURN p_test;
END;
FUNCTION add_one (
p_add IN NUMBER)
RETURN NUMBER
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Increase by 1');
RETURN test_max(p_add + 1);
END;
BEGIN
DBMS_OUTPUT.PUT_LINE(test_max(3));
END;
サブファンクション test_maxは前方宣言が匿名ブロック宣言セクションの冒頭にadd_oneために実装されているサブプログラム、のいずれかのために必要とされるように、また、サブ関数test_max呼び出すサブファンクションadd_oneを呼び出します。
匿名ブロックからの結果出力は次のとおりです。
Increase by 1
Increase by 1
Final value is 5
3.2.6.6 サブプログラムのオーバーロード
一般的に、同じ名前の同じタイプのサブプログラム(サブプロシージャまたはサブファンクション)と同じ仮パラメータ仕様は、同じスタンドアロンプ​​ログラム内では兄弟ブロックでない限り複数回現れます(つまり、サブプログラムは同じローカルブロック)。
各サブプログラムは、前のセクションで説明したように、サブプログラムの呼び出しが行われる場所と修飾子の使用に応じて個別に呼び出すことができます。
ただし、仮パラメータの特定の側面が異なる限り、同じサブプログラム型および名前のサブプログラム(兄弟としても)を宣言することは可能です。これらの特性(サブプログラムタイプ、名前、および仮パラメータ仕様)は、一般にプログラムの シグネチャ として知られてい ます
仮パラメータ仕様の特定の側面を除いて、シグネチャが同一である複数の副プログラムの宣言は、副プログラムの オーバーロード と呼ばれます。
したがって、どの特定の過負荷サブプログラムが呼び出されるべきかの決定は、サブプログラム呼び出しによって指定される実際のパラメータと、過負荷サブプログラムの仮パラメータリストの一致によって決定される。
オーバーロードされたサブプログラムは、次の違いのいずれかによって許可されます。
次の相違点だけでは、多重定義されたサブプログラムを使用できないことに注意してください。
対応する仮パラメータの異なるパラメータモード( ININ OUTOUT
前述のように、オーバーロードされたサブプログラムを許可する違いの1つは、異なるデータ型です。
ただし、特定のデータ型には、 エイリアス と呼ばれる代替名があり、これをテーブル定義に使用できます。
たとえば、 CHARまたはCHARACTER として指定できる固定長文字データ型がありますCHAR VARYINGCHARACTER VARYINGVARCHAR 、またはVARCHAR2として指定できる可変長文字データ型があります。整数の場合BINARY_INTEGERPLS_INTEGER 、およびINTEGERデータ型があります。数値の場合は、 NUMBERNUMERICDEC 、およびDECIMALのデータ型があります。
Advanced Serverでサポートされているデータ型の詳細については、次のURLのEnterpriseDBから入手可能なOracle Developer Reference GuideのDatabase Compatibilityを参照してください。
https://www.enterprisedb.com/resources/product-documentation
したがって、オーバーロードされたサブプログラムを作成しようとすると、指定されたデータ型が互いに別名である場合、仮パラメータ・データ型は異なるとみなされません。
問題のデータ型を含むテーブル定義を表示することによって、特定のデータ型が他の型のエイリアスであるかどうかを判断できます。
たとえば、次の表定義には、いくつかのデータ型とそのエイリアスが含まれています。
CREATE TABLE data_type_aliases (
dt_BLOB BLOB,
dt_LONG_RAW LONG RAW,
dt_RAW RAW(4),
dt_BYTEA BYTEA,
dt_INTEGER INTEGER,
dt_BINARY_INTEGER BINARY_INTEGER,
dt_PLS_INTEGER PLS_INTEGER,
dt_REAL REAL,
dt_DOUBLE_PRECISION DOUBLE PRECISION,
dt_FLOAT FLOAT,
dt_NUMBER NUMBER,
dt_DECIMAL DECIMAL,
dt_NUMERIC NUMERIC,
dt_CHAR CHAR,
dt_CHARACTER CHARACTER,
dt_VARCHAR2 VARCHAR2(4),
dt_CHAR_VARYING CHAR VARYING(4),
dt_VARCHAR VARCHAR(4)
);
PSQL \ dコマンドを使用してテーブル定義を表示すると、[Type]列には、テーブル定義のデータ型に基づいて各列に内部的に割り当てられたデータ型が表示されます。
\d data_type_aliases
Column | Type | Modifiers
---------------------+----------------------+-----------
dt_blob | bytea |
dt_long_raw | bytea |
dt_raw | bytea(4) |
dt_bytea | bytea |
dt_integer | integer |
dt_binary_integer | integer |
dt_pls_integer | integer |
dt_real | real |
dt_double_precision | double precision |
dt_float | double precision |
dt_number | numeric |
dt_decimal | numeric |
dt_numeric | numeric |
dt_char | character(1) |
dt_character | character(1) |
dt_varchar2 | character varying(4) |
dt_char_varying | character varying(4) |
dt_varchar | character varying(4) |
この例では、データ型の基本セットはbytea整数実数倍精度数値文字 、および文字可変です。
オーバーロードされたサブプログラムを宣言しようとすると、エイリアスである仮パラメータ・データ型のペアでは、サブプログラムのオーバーロードを許可するには不十分です。したがって、データ型が INTEGERおよびPLS_INTEGERの パラメータは 、1組のサブプログラムをオーバーロードできませんが、データ型INTEGERおよびREAL 、またはINTEGERおよびFLOAT 、またはINTEGERおよびNUMBERは、サブプログラムをオーバーロードできます。
注意:仮パラメータ・データ型に基づくオーバーロード・ルールは、Oracleデータベースと互換性がありません。通常、Advanced Serverルールは柔軟性があり、Advanced ServerではOracleデータベースでプロシージャまたはファンクションを作成しようとするとエラーが発生する特定の組み合わせが許可されます。
オーバーロードに使用される特定のデータ型のペアについては、サブプログラムの実行時に発生したエラーを回避するために、サブプログラム呼び出しで指定された引数のキャストが必要な場合があります。サブプログラムの呼び出しには、データ型を具体的に識別できる実際のパラメーター・リストが含まれていなければなりません。オーバーロードされたデータ型の特定のペアでは、データ型を明示的に識別するためにCAST関数が必要な場合があります。たとえば、呼び出し時にキャストが必要なオーバーロードされたデータ型のペアは、 CHARおよびVARCHAR2 、またはNUMBERおよびREALです。
次の例は、無名ブロック内から呼び出されたオーバーロードされたサブ関数のグループを示しています。無名ブロックの実行可能セクションには、 CAST関数を使用して、特定のデータ型でオーバーロードされた関数を呼び出すことができます。
DECLARE
FUNCTION add_it (
p_add_1 IN BINARY_INTEGER,
p_add_2 IN BINARY_INTEGER
) RETURN VARCHAR2
IS
BEGIN
RETURN 'add_it BINARY_INTEGER: ' || TO_CHAR(p_add_1 + p_add_2,9999.9999);
END add_it;
FUNCTION add_it (
p_add_1 IN NUMBER,
p_add_2 IN NUMBER
) RETURN VARCHAR2
IS
BEGIN
RETURN 'add_it NUMBER: ' || TO_CHAR(p_add_1 + p_add_2,999.9999);
END add_it;
FUNCTION add_it (
p_add_1 IN REAL,
p_add_2 IN REAL
) RETURN VARCHAR2
IS
BEGIN
RETURN 'add_it REAL: ' || TO_CHAR(p_add_1 + p_add_2,9999.9999);
END add_it;
FUNCTION add_it (
p_add_1 IN DOUBLE PRECISION,
p_add_2 IN DOUBLE PRECISION
) RETURN VARCHAR2
IS
BEGIN
RETURN 'add_it DOUBLE PRECISION: ' || TO_CHAR(p_add_1 + p_add_2,9999.9999);
END add_it;
BEGIN
DBMS_OUTPUT.PUT_LINE(add_it (25, 50));
DBMS_OUTPUT.PUT_LINE(add_it (25.3333, 50.3333));
DBMS_OUTPUT.PUT_LINE(add_it (TO_NUMBER(25.3333), TO_NUMBER(50.3333)));
DBMS_OUTPUT.PUT_LINE(add_it (CAST('25.3333' AS REAL), CAST('50.3333' AS REAL)));
DBMS_OUTPUT.PUT_LINE(add_it (CAST('25.3333' AS DOUBLE PRECISION),
CAST('50.3333' AS DOUBLE PRECISION)));
END;
無名ブロックから表示される出力は次のとおりです。
add_it BINARY_INTEGER: 75.0000
add_it NUMBER: 75.6666
add_it NUMBER: 75.6666
add_it REAL: 75.6666
add_it DOUBLE PRECISION: 75.6666
3.2.6.7 サブプログラム変数へのアクセス
サブプログラムや匿名ブロックなどのブロックで宣言された変数は、相対位置に応じて実行可能セクションまたは他のブロックの例外セクションからアクセスできます。
変数へのアクセスとは、ローカル変数を使用する場合と同様に、SQLステートメントまたはSPLステートメント内で変数を参照できることを意味します。
注意:サブプログラムのシグネチャに仮パラメータが含まれている場合は、サブプログラムのローカル変数と同じ方法でアクセスできます。この項では、サブプログラムの変数に関するすべての説明が、サブプログラムの仮パラメータにも適用されます。
変数のアクセスには、データ型として定義された変数だけでなく、レコードタイプ、コレクションタイプ、カーソルなどの変数も含まれます。
変数は、変数がローカルに宣言されているサブプログラムまたはラベル付き無名ブロックの名前である多くても1つの修飾子によってアクセスできます。
変数を参照する構文は、次のとおりです。
[ qualifier .] variable
指定した場合、 修飾子変数が宣言セクションで宣言されているサブプログラムまたはラベル付き匿名ブロックです (つまり、ローカル変数です)。
注: Advanced Serverでは、2つの修飾子が許可される環境は1つだけです。このシナリオは、参照を次の形式で指定できるパッケージのパブリック変数にアクセスするためのものです。
schema_name . package_name . public_variable_name
サポートされているパッケージの構文の詳細は、「Oracle Developerの組み込みパッケージのデータベース互換性ガイド」を参照してください。
変数にアクセスする方法を以下に要約します。
次の変数の場所は、変数への参照が行われたブロックからの相対的なアクセスはできません。
注意:変数にアクセスするためのAdvanced Serverプロセスは、Oracleデータベースと互換性がありません。 Oracleでは、任意の数の修飾子を指定することができ、検索は、サブプログラムを呼び出すためのOracleの一致アルゴリズムと同様の方法で、最初の修飾子の最初の一致に基づいて行われます。
次の例では、修飾子の有無にかかわらず、さまざまなブロックの変数にアクセスする方法を示します。コメントアウトされている行は、エラーになる変数へのアクセスを示しています。
CREATE OR REPLACE PROCEDURE level_0
IS
v_level_0 VARCHAR2(20) := 'Value from level_0';
PROCEDURE level_1a
IS
v_level_1a VARCHAR2(20) := 'Value from level_1a';
PROCEDURE level_2a
IS
v_level_2a VARCHAR2(20) := 'Value from level_2a';
BEGIN
DBMS_OUTPUT.PUT_LINE('...... BLOCK level_2a');
DBMS_OUTPUT.PUT_LINE('........ v_level_2a: ' || v_level_2a);
DBMS_OUTPUT.PUT_LINE('........ v_level_1a: ' || v_level_1a);
DBMS_OUTPUT.PUT_LINE('........ level_1a.v_level_1a: ' ||
level_1a.v_level_1a);
DBMS_OUTPUT.PUT_LINE('........ v_level_0: ' || v_level_0);
DBMS_OUTPUT.PUT_LINE('........ level_0.v_level_0: ' || level_0.v_level_0);
DBMS_OUTPUT.PUT_LINE('...... END BLOCK level_2a');
END level_2a;
BEGIN
DBMS_OUTPUT.PUT_LINE('.. BLOCK level_1a');
level_2a;
-- DBMS_OUTPUT.PUT_LINE('.... v_level_2a: ' || v_level_2a);
-- Error - Descendent block ----^
-- DBMS_OUTPUT.PUT_LINE('.... level_2a.v_level_2a: ' || level_2a.v_level_2a);
-- Error - Descendent block ---------------^
DBMS_OUTPUT.PUT_LINE('.. END BLOCK level_1a');
END level_1a;
PROCEDURE level_1b
IS
v_level_1b VARCHAR2(20) := 'Value from level_1b';
BEGIN
DBMS_OUTPUT.PUT_LINE('.. BLOCK level_1b');
DBMS_OUTPUT.PUT_LINE('.... v_level_1b: ' || v_level_1b);
DBMS_OUTPUT.PUT_LINE('.... v_level_0 : ' || v_level_0);
-- DBMS_OUTPUT.PUT_LINE('.... level_1a.v_level_1a: ' || level_1a.v_level_1a);
-- Error - Sibling block -----------------^
-- DBMS_OUTPUT.PUT_LINE('.... level_2a.v_level_2a: ' || level_2a.v_level_2a);
-- Error - Sibling block descendant ------^
DBMS_OUTPUT.PUT_LINE('.. END BLOCK level_1b');
END level_1b;
BEGIN
DBMS_OUTPUT.PUT_LINE('BLOCK level_0');
DBMS_OUTPUT.PUT_LINE('.. v_level_0: ' || v_level_0);
level_1a;
level_1b;
DBMS_OUTPUT.PUT_LINE('END BLOCK level_0');
END level_0;
プロシージャが呼び出されたときの各変数の内容を示す出力は次のとおりです。
BEGIN
level_0;
END;
 
BLOCK level_0
.. v_level_0: Value from level_0
.. BLOCK level_1a
...... BLOCK level_2a
........ v_level_2a: Value from level_2a
........ v_level_1a: Value from level_1a
........ level_1a.v_level_1a: Value from level_1a
........ v_level_0: Value from level_0
........ level_0.v_level_0: Value from level_0
...... END BLOCK level_2a
.. END BLOCK level_1a
.. BLOCK level_1b
.... v_level_1b: Value from level_1b
.... v_level_0 : Value from level_0
.. END BLOCK level_1b
END BLOCK level_0
次の例は、すべてのブロックのすべての変数が同じ名前を持つ場合の同様のアクセス試行を示しています。
CREATE OR REPLACE PROCEDURE level_0
IS
v_common VARCHAR2(20) := 'Value from level_0';
PROCEDURE level_1a
IS
v_common VARCHAR2(20) := 'Value from level_1a';
PROCEDURE level_2a
IS
v_common VARCHAR2(20) := 'Value from level_2a';
BEGIN
DBMS_OUTPUT.PUT_LINE('...... BLOCK level_2a');
DBMS_OUTPUT.PUT_LINE('........ v_common: ' || v_common);
DBMS_OUTPUT.PUT_LINE('........ level_2a.v_common: ' || level_2a.v_common);
DBMS_OUTPUT.PUT_LINE('........ level_1a.v_common: ' || level_1a.v_common);
DBMS_OUTPUT.PUT_LINE('........ level_0.v_common: ' || level_0.v_common);
DBMS_OUTPUT.PUT_LINE('...... END BLOCK level_2a');
END level_2a;
BEGIN
DBMS_OUTPUT.PUT_LINE('.. BLOCK level_1a');
DBMS_OUTPUT.PUT_LINE('.... v_common: ' || v_common);
DBMS_OUTPUT.PUT_LINE('.... level_0.v_common: ' || level_0.v_common);
level_2a;
DBMS_OUTPUT.PUT_LINE('.. END BLOCK level_1a');
END level_1a;
PROCEDURE level_1b
IS
v_common VARCHAR2(20) := 'Value from level_1b';
BEGIN
DBMS_OUTPUT.PUT_LINE('.. BLOCK level_1b');
DBMS_OUTPUT.PUT_LINE('.... v_common: ' || v_common);
DBMS_OUTPUT.PUT_LINE('.... level_0.v_common : ' || level_0.v_common);
DBMS_OUTPUT.PUT_LINE('.. END BLOCK level_1b');
END level_1b;
BEGIN
DBMS_OUTPUT.PUT_LINE('BLOCK level_0');
DBMS_OUTPUT.PUT_LINE('.. v_common: ' || v_common);
level_1a;
level_1b;
DBMS_OUTPUT.PUT_LINE('END BLOCK level_0');
END level_0;
プロシージャが呼び出されたときの各変数の内容を示す出力は次のとおりです。
BEGIN
level_0;
END;
 
BLOCK level_0
.. v_common: Value from level_0
.. BLOCK level_1a
.... v_common: Value from level_1a
.... level_0.v_common: Value from level_0
...... BLOCK level_2a
........ v_common: Value from level_2a
........ level_2a.v_common: Value from level_2a
........ level_1a.v_common: Value from level_1a
........ level_0.v_common: Value from level_0
...... END BLOCK level_2a
.. END BLOCK level_1a
.. BLOCK level_1b
.... v_common: Value from level_1b
.... level_0.v_common : Value from level_0
.. END BLOCK level_1b
END BLOCK level_0
前述のように、無名ブロックのラベルを使用して変数へのアクセスを限定することもできます。次の例は、ネストされた匿名ブロックのセット内の変数アクセスを示しています。
DECLARE
v_common VARCHAR2(20) := 'Value from level_0';
BEGIN
DBMS_OUTPUT.PUT_LINE('BLOCK level_0');
DBMS_OUTPUT.PUT_LINE('.. v_common: ' || v_common);
<<level_1a>>
DECLARE
v_common VARCHAR2(20) := 'Value from level_1a';
BEGIN
DBMS_OUTPUT.PUT_LINE('.. BLOCK level_1a');
DBMS_OUTPUT.PUT_LINE('.... v_common: ' || v_common);
<<level_2a>>
DECLARE
v_common VARCHAR2(20) := 'Value from level_2a';
BEGIN
DBMS_OUTPUT.PUT_LINE('...... BLOCK level_2a');
DBMS_OUTPUT.PUT_LINE('........ v_common: ' || v_common);
DBMS_OUTPUT.PUT_LINE('........ level_1a.v_common: ' || level_1a.v_common);
DBMS_OUTPUT.PUT_LINE('...... END BLOCK level_2a');
END;
DBMS_OUTPUT.PUT_LINE('.. END BLOCK level_1a');
END;
<<level_1b>>
DECLARE
v_common VARCHAR2(20) := 'Value from level_1b';
BEGIN
DBMS_OUTPUT.PUT_LINE('.. BLOCK level_1b');
DBMS_OUTPUT.PUT_LINE('.... v_common: ' || v_common);
DBMS_OUTPUT.PUT_LINE('.... level_1b.v_common: ' || level_1b.v_common);
DBMS_OUTPUT.PUT_LINE('.. END BLOCK level_1b');
END;
DBMS_OUTPUT.PUT_LINE('END BLOCK level_0');
END;
以下は、無名ブロックが呼び出されたときの各変数の内容を示す出力です。
BLOCK level_0
.. v_common: Value from level_0
.. BLOCK level_1a
.... v_common: Value from level_1a
...... BLOCK level_2a
........ v_common: Value from level_2a
........ level_1a.v_common: Value from level_1a
...... END BLOCK level_2a
.. END BLOCK level_1a
.. BLOCK level_1b
.... v_common: Value from level_1b
.... level_1b.v_common: Value from level_1b
.. END BLOCK level_1b
END BLOCK level_0
次の例は、オブジェクト型メソッド display_empにレコード型emp_typとサブプロシージャ emp_sal_queryが含まれているオブジェクト型 ですemp_sal_queryにローカルに宣言されたレコード変数r_empは、親ブロックdisplay_empで宣言されたレコードタイプemp_typにアクセスすることが可能です。
CREATE OR REPLACE TYPE emp_pay_obj_typ AS OBJECT
(
empno NUMBER(4),
MEMBER PROCEDURE display_emp(SELF IN OUT emp_pay_obj_typ)
);
 
CREATE OR REPLACE TYPE BODY emp_pay_obj_typ AS
MEMBER PROCEDURE display_emp (SELF IN OUT emp_pay_obj_typ)
IS
TYPE emp_typ IS RECORD (
ename emp.ename%TYPE,
job emp.job%TYPE,
hiredate emp.hiredate%TYPE,
sal emp.sal%TYPE,
deptno emp.deptno%TYPE
);
PROCEDURE emp_sal_query (
p_empno IN emp.empno%TYPE
)
IS
r_emp emp_typ;
v_avgsal emp.sal%TYPE;
BEGIN
SELECT ename, job, hiredate, sal, deptno
INTO r_emp.ename, r_emp.job, r_emp.hiredate, r_emp.sal, r_emp.deptno
FROM emp WHERE empno = p_empno;
DBMS_OUTPUT.PUT_LINE('Employee # : ' || p_empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || r_emp.ename);
DBMS_OUTPUT.PUT_LINE('Job : ' || r_emp.job);
DBMS_OUTPUT.PUT_LINE('Hire Date : ' || r_emp.hiredate);
DBMS_OUTPUT.PUT_LINE('Salary : ' || r_emp.sal);
DBMS_OUTPUT.PUT_LINE('Dept # : ' || r_emp.deptno);
 
SELECT AVG(sal) INTO v_avgsal
FROM emp WHERE deptno = r_emp.deptno;
IF r_emp.sal > v_avgsal THEN
DBMS_OUTPUT.PUT_LINE('Employee''s salary is more than the '
|| 'department average of ' || v_avgsal);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee''s salary does not exceed the '
|| 'department average of ' || v_avgsal);
END IF;
END;
BEGIN
emp_sal_query(SELF.empno);
END;
END;
以下は、オブジェクト型のインスタンスが作成され、プロシージャ display_empが呼び出されたときに表示される出力です。
DECLARE
v_emp EMP_PAY_OBJ_TYP;
BEGIN
v_emp := emp_pay_obj_typ(7900);
v_emp.display_emp;
END;
 
Employee # : 7900
Name : JAMES
Job : CLERK
Hire Date : 03-DEC-81 00:00:00
Salary : 950.00
Dept # : 30
Employee's salary does not exceed the department average of 1566.67
次の例は、3つのレベルのサブプロシージャを含むパッケージです。上位レベルのプロシージャーで宣言されたレコード・タイプ、コレクション・タイプ、およびカーソル・タイプは、子孫プロシージャーによってアクセスできます。
CREATE OR REPLACE PACKAGE emp_dept_pkg
IS
PROCEDURE display_emp (
p_deptno NUMBER
);
END;
 
CREATE OR REPLACE PACKAGE BODY emp_dept_pkg
IS
PROCEDURE display_emp (
p_deptno NUMBER
)
IS
TYPE emp_rec_typ IS RECORD (
empno emp.empno%TYPE,
ename emp.ename%TYPE
);
TYPE emp_arr_typ IS TABLE OF emp_rec_typ INDEX BY BINARY_INTEGER;
TYPE emp_cur_type IS REF CURSOR RETURN emp_rec_typ;
PROCEDURE emp_by_dept (
p_deptno emp.deptno%TYPE
)
IS
emp_arr emp_arr_typ;
emp_refcur emp_cur_type;
i BINARY_INTEGER := 0;
PROCEDURE display_emp_arr
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
FOR j IN emp_arr.FIRST .. emp_arr.LAST LOOP
DBMS_OUTPUT.PUT_LINE(emp_arr(j).empno || ' ' ||
emp_arr(j).ename);
END LOOP;
END display_emp_arr;
BEGIN
OPEN emp_refcur FOR SELECT empno, ename FROM emp WHERE deptno = p_deptno;
LOOP
i := i + 1;
FETCH emp_refcur INTO emp_arr(i).empno, emp_arr(i).ename;
EXIT WHEN emp_refcur%NOTFOUND;
END LOOP;
CLOSE emp_refcur;
display_emp_arr;
END emp_by_dept;
BEGIN
emp_by_dept(p_deptno);
END;
END;
最上位パッケージプロシージャが呼び出されたときに表示される出力は次のとおりです。
BEGIN
emp_dept_pkg.display_emp(20);
END;
 
EMPNO ENAME
----- -------
7369 SMITH
7566 JONES
7788 SCOTT
7876 ADAMS
7902 FORD
 
3.2.7 プロシージャと関数のコンパイルエラー
Advanced Serverパーサーがプロシージャーまたは関数をコンパイルすると、 CREATEステートメントとプログラム本体( ASキーワードに続くプログラムの部分)がSPLおよびSQL構成の文法規則に準拠していることが確認されます。デフォルトでは、パーサーがエラーを検出した場合、サーバーはコンパイルプロセスを終了します。パーサーは、式内の構文エラーを検出しますが、意味エラー(つまり、存在しない列、表、関数を参照する式、または誤った型の値)を検出しないことに注意してください。
spl.max _ error _ countは、SPLコードで指定された数のエラーが発生した場合、またはSQLコードでエラーが発生した場合に、サーバーに解析を停止するように指示します。 spl.maxのデフォルト値は、_ _ エラー カウントは 10です。最大値は1000です。 spl.max_error_count1に設定すると、SPLコードまたはSQLコードの最初のエラーが発生したときに、サーバーは解析を停止するように指示されます。
あなたは使用することができ 、あなたの現在のセッションのspl.max _ _ エラー カウンタの値を指定するには、SETコマンドを使用します。構文は次のとおりです。
SET spl.max_error_count = number_of_errors
どこ NUMBER_OF_ERRORSは 、サーバがコンパイルプロセスを停止する前に発生することがありSPLエラーの数を指定します。例えば:
SET spl.max_error_count = 6
この例では、検出した最初の5つのSPLエラーを超えてサーバーに続行するよう指示しています。サーバーが6番目のエラーに遭遇すると、検証が中止され、6つの詳細なエラーメッセージと1つのエラーサマリーが出力されます。
新しいコードを作成するときや別のソースから既存のコードをインポートするときの時間を節約するために、 spl.max _ error _ count設定パラメータを比較的高い数のエラーに設定することができます。
プログラム本体のSPLコードのエラーにもかかわらずサーバーが解析を続行し、パーサーがSQLコードのセグメントでエラーを検出した場合は、それに続くSPLまたはSQLコードにもエラーが残っている可能性があります間違ったSQLコード。たとえば、次の関数は2つのエラーを発生させます。
CREATE FUNCTION computeBonus(baseSalary number)RETURN数値をASとして返します。
ベギン

ボーナス:= baseSalary * 1.10;
合計:=ボーナス+ 100;

リターンボーナス。
終わり;

エラー:「ボーナス」は既知の変数ではありません
LINE 4:ボーナス:= baseSalary * 1.10;
^
エラー:「合計」は既知の変数ではありません
LINE 5:合計:=ボーナス+ 100;
^
エラー:2つのエラーのためにSPL関数/プロシージャ "computebonus"のコンパイルが失敗しました
次の例では 、前の例にSELECT文が追加されています。 SELECT文のエラーは、次に続く他のエラーをマスクします。
CREATE FUNCTION computeBonus(employeeName number)戻り値番号AS
ベギン
SELECT salary INTO baseSalary FROM emp
where ename = employeeName;

ボーナス:= baseSalary * 1.10;
合計:=ボーナス+ 100;

リターンボーナス。

終わり;

エラー: "basesalary"は既知の変数ではありません
LINE 3:SELECT salary INTO baseSalary FROM emp where ename = emp ...
 
3.2.8 プログラムセキュリティ
どのユーザが SPLプログラムを実行するかに関するセキュリティと、 SPLプログラムがプログラムを実行している任意のユーザのためにアクセスできるデータベースオブジェクトは、以下によって制御されます。
プログラムがアクセスしようとするデータベースオブジェクト(他の SPLプログラムを含む )に付与される特権
これらの側面については、以降のセクションで説明します。
3.2.8.1 EXECUTE特権
SPLプログラム(ファンクション、プロシージャまたはパッケージ)は、次のいずれかに該当する場合にのみ実行を開始することができます:
現在のユーザーにはSPLプログラムに対するEXECUTE特権が与えられています。
現在のユーザは、そのような特権を持つグループのメンバであるため、 SPLプログラムに対するEXECUTE特権を継承します。
EXECUTE特権がPUBLICグループに付与されました。
Advanced ServerSPLプログラムが作成されるたびにEXECUTE特権がデフォルトでPUBLICグループに自動的に付与されるため、どのユーザーもすぐにプログラムを実行できます。
このデフォルトの権限は、 REVOKE EXECUTEコマンドを使用して削除できます 。次はその例です。
REVOKE EXECUTE ON PROCEDURE list_emp FROM PUBLIC;
プログラムに対する明示的な EXECUTE特権を個々のユーザーまたはグループに付与できます。
GRANT EXECUTE ON PROCEDURE list_emp TO john;
これで、ユーザー johnlist_empプログラムを実行できます。このセクションの冒頭に記載されている条件のいずれかを満たしていないユーザーは、他のユーザーにアクセスできません。
プログラムが実行を開始すると、セキュリティの次の側面は、プログラムがデータベースオブジェクトに対してアクションを実行しようとすると、どのような特権チェックが行われるかです。
このような各アクションは、ユーザーに対して許可または禁止されているデータベース・オブジェクトの権限によって保護できます。
データベースでは、同じ名前の同じタイプの複数のオブジェクトを持つことができますが、そのような各オブジェクトはデータベース内の異なるスキーマに属している可能性があります。この場合、どのオブジェクトが SPLプログラムによって参照されていますか?これは次のセクションのトピックです。
3.2.8.2 データベースオブジェクトの名前解決
SPLプログラム内のデータベースオブジェクトは 、修飾名または非修飾名で参照されることがあります。修飾名はスキーマの形式です nameここで、 schemaは、識別子、 名前のデータベースオブジェクトが存在するスキーマの名前です。修飾されていない名前には「 スキーマ 」はありません "部分。修飾された名前への参照が行われるとき、指定されたスキーマ内に存在するか存在しないかは、正確にどのデータベースオブジェクトが意図されているかについて全く曖昧さがありません。
ただし、修飾されていない名前のオブジェクトを見つけるには、現在のユーザーの検索パスを使用する必要があります。ユーザーがセッションの現在のユーザーになると、既定の検索パスは常にそのユーザーに関連付けられます。検索パスは、修飾されていないデータベース・オブジェクト参照を検索するために左から右の順序で検索されるスキーマのリストで構成されます。オブジェクトは、検索パスのいずれのスキーマにも見つからない場合は存在しないとみなされます。デフォルトの検索パスはSHOW search_pathコマンドを使用して PSQL に表示できます
edb=# SHOW search_path;
search_path
-----------------
"$user", public
(1 row)
$ユーザ次いで、第一、EnterpriseDBのを -上記検索パスでは、上記セッションの現在のユーザーがEnterpriseDBのであれば、非修飾データベース・オブジェクトがこの順に次のスキーマで検索されるように、現在のユーザを指す一般的なプレースホルダ公衆
未修飾の名前が検索パスで解決されると、現在のユーザーがその特定のオブジェクトに対して目的のアクションを実行するための適切な権限を持っているかどうかを判断できます。
注意:検索パスの概念は、 Oracleデータベースと互換性がありません。修飾されていない参照の場合、 Oracleは現在のユーザーのスキーマ内で、指定されたデータベース・オブジェクトを探します。 Oracleでは、 Advanced Serverではユーザーとスキーマは同じエンティティであり、ユーザーとスキーマは2つの異なるオブジェクトであることに注意してください。
3.2.8.3 データベース・オブジェクト権限
いったん SPLプログラムが実行を開始、現在のユーザーを確保するために、チェックのプログラムの結果の中からデータベースオブジェクトにアクセスしようとすると、参照されるオブジェクトに対する意図したアクションを実行する権限を持っています。 GRANTおよびREVOKEコマンドを使用して、データベース・オブジェクトに対する権限が付与され、削除されます。現在のユーザーがデータベースオブジェクトに対する不正アクセスを試みると、プログラムは例外をスローします。セクションを参照してください。 3.5.7例外処理の詳細については、
最後のトピックでは、現在のユーザーが誰であるかを正確に説明します。
3.2.8.4 Define の対Invokerの権利
場合 SPLプログラムが実行を開始しようとしている、決意は、このプロセスに関連するものをユーザが行われます。このユーザーは、 現在のユーザーと呼ばれます 。現在のユーザーのデータベース・オブジェクト権限は、プログラムで参照されるデータベース・オブジェクトへのアクセスを許可するかどうかを決定するために使用されます。プログラムが呼び出されたときに有効な現在の一般的な検索パスは、未修飾のオブジェクト参照を解決するために使用されます。
現在のユーザの選択は、 SPLプログラムが定義者の権利または実行者の権利で作成されたかどうかによって影響されます。 AUTHID節はその選択を決定します。 AUTHID DEFINER節の出現により、プログラム定義者の権利が与えられます。 AUTHID句が省略されている場合のこれもデフォルトです。 AUTHID CURRENT_USER句を使用すると、プログラムの呼び出し元の権限が与えられます。両者の違いは次のようにまとめられています。
プログラムに 定義者の権利がある場合、プログラムの実行開始時にプログラムの所有者が現在のユーザーになります。プログラム所有者のデータベースオブジェクト権限は、参照されたオブジェクトへのアクセスが許可されているかどうかを判断するために使用されます。定義者の権利プログラムでは、どのユーザーが実際にプログラムを呼び出したかは関係ありません。
プログラムに 呼び出し元の権限 がある場合、プログラムが呼び出された時点の現在のユーザーは、プログラムが実行されている間は現在のユーザーのままです(ただし、必ずしも呼び出されるサブプログラム内ではありません -起動者の権利プログラムが呼び出されると、セッションがSET ROLEコマンドを使用して開始された後に現在のユーザーを変更することは可能ですが、通常、現在のユーザーはセッションを開始したユーザー(データベース接続)です。呼び出し元の権利プログラムでは、どのユーザーがプログラムを実際に所有しているかは関係ありません。
前の定義から、以下の観察が可能である:
上記のケースでは、呼び出されたプログラムが別のプログラムを呼び出す場合も、同じ原則が適用されます。
セキュリティに関するこのセクションでは、サンプルアプリケーションを使用した例を示します。
3.2.8.5 セキュリティの例
次の例では、新しいデータベースには二人のユーザーと一緒に作成されます- hr_mgrスキーマ、hr_mgrで全体のサンプルアプリケーションのコピーを所有することになります。 sales_mgrというスキーマを所有するsales_mgrは、 salesで作業する従業員だけを含むempテーブルのみのコピーを持ちます。
この例では、 プロシージャ list_emp 、関数hire_clerk 、およびパッケージemp_adminが使用されます。サンプルアプリケーションのインストール時に付与されるすべてのデフォルト権限は削除され、この例ではより安全な環境を提供するために明示的に再付与されます。
プログラム list_emphire_clerkは、デフォルトの定義者権限から呼び出し元の権限に変更されます。 sales_mgrがこれらのプログラムを実行すると、 sales_mgrの検索パスと権限が名前解決と権限チェックに使用されるため、 sales_mgrのスキーマ内のempテーブルが処理されることが示されます。
emp_adminパッケージのget_dept_nameおよびhire_emp プログラムは、 sales_mgrによって実行されますhr_mgrが定義者権限を使用しているEMP_ADMINパッケージの所有者であり、この場合には、hr_mgrのスキーマ内のDEPTテーブルEMPテーブルがアクセスされます。デフォルトの検索パスは$ userプレースホルダで有効なので、 ユーザと一致するスキーマ(この場合はhr_mgr )を使用してテーブルを検索します。
ステップ1 - データベースとユーザを作成する
ユーザー enterprisedb としてhrデータベースを作成します。
CREATE DATABASE hr;
hrデータベースに切り替えて、ユーザーを作成します。
\c hr enterprisedb
CREATE USER hr_mgr IDENTIFIED BY password;
CREATE USER sales_mgr IDENTIFIED BY password;
ステップ2 - サンプルアプリケーションを作成する
が所有し、全サンプルアプリケーション、作成 hr_mgrのスキーマでhr_mgrを 、。
\c - hr_mgr
\i /usr/edb/as11/share/edb-sample.sql
 
BEGIN
CREATE TABLE
CREATE TABLE
CREATE TABLE
CREATE VIEW
CREATE SEQUENCE
.
.
.
CREATE PACKAGE
CREATE PACKAGE BODY
COMMIT
ステップ3 - スキーマsales_mgrにempテーブルを作成する
サブセットを作成 sales_mgrのスキーマにsales_mgrが所有するemp表を。
\c – hr_mgr
GRANT USAGE ON SCHEMA hr_mgr TO sales_mgr;
\c – sales_mgr
CREATE TABLE emp AS SELECT * FROM hr_mgr.emp WHERE job = 'SALESMAN';
上記の例では、 スキーマコマンドON GRANTの使用は S emp表 「hr_mgrのコピーを作成するためのスキーマ」hr_mgrsales_mgrアクセスを可能にするために与えられています。この手順はAdvanced Serverでは必須です.Oracleには、ユーザーとは異なるスキーマの概念がないため、Oracleデータベースとの互換性はありません。
ステップ4 - デフォルトの特権を削除する
すべての特権を削除して、必要な最小特権を後で説明します。
\c – hr_mgr
REVOKE USAGE ON SCHEMA hr_mgr FROM sales_mgr;
REVOKE ALL ON dept FROM PUBLIC;
REVOKE ALL ON emp FROM PUBLIC;
REVOKE ALL ON next_empno FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION new_empno() FROM PUBLIC;
REVOKE EXECUTE ON PROCEDURE list_emp FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION hire_clerk(VARCHAR2,NUMBER) FROM PUBLIC;
REVOKE EXECUTE ON PACKAGE emp_admin FROM PUBLIC;
ステップ5 - list_empを呼び出し側の権限に変更する
ユーザー hrhmgr として接続しているときに、 AUTHID CURRENT_USER句をlist_empプログラムに追加し、 Advanced Serverに再保存します 。この手順を実行するときは、 hr_mgrとしてログオンしていることを確認してください 。そうしないと、変更されたプログラムがhr_mgrのスキーマではなくパブリックスキーマに書き込まれることがあります。
CREATE OR REPLACE PROCEDURE list_emp
AUTHID CURRENT_USER
IS
v_empno NUMBER(4);
v_ename VARCHAR2(10);
CURSOR emp_cur IS
SELECT empno, ename FROM emp ORDER BY empno;
BEGIN
OPEN emp_cur;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH emp_cur INTO v_empno, v_ename;
EXIT WHEN emp_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_ename);
END LOOP;
CLOSE emp_cur;
END;
ステップ6 - hire_clerkを呼び出し側の権限に変更し、new_empnoへの呼び出しを修飾する
ユーザー hr_mgr として接続しているときに、 AUTHID CURRENT_USER句をhire_clerkプログラムに追加します。
また、後に BEGIN文で、完全にnew_empno機能hr_mgrスキーマに解決にhire_clerk関数呼び出しを確保するためにhr_mgr.new_empno、new_empno、参照を修飾。
プログラムを再保存するときは、必ず hr_mgr としてログオンして ください 。そうしないと、変更されたプログラムがhr_mgrのスキーマではなくパブリックスキーマに書き込まれることがあります。
CREATE OR REPLACE FUNCTION hire_clerk (
p_ename VARCHAR2,
p_deptno NUMBER
) RETURN NUMBER
AUTHID CURRENT_USER
IS
v_empno NUMBER(4);
v_ename VARCHAR2(10);
v_job VARCHAR2(9);
v_mgr NUMBER(4);
v_hiredate DATE;
v_sal NUMBER(7,2);
v_comm NUMBER(7,2);
v_deptno NUMBER(2);
BEGIN
v_empno := hr_mgr.new_empno;
INSERT INTO emp VALUES (v_empno, p_ename, 'CLERK', 7782,
TRUNC(SYSDATE), 950.00, NULL, p_deptno);
SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno INTO
v_empno, v_ename, v_job, v_mgr, v_hiredate, v_sal, v_comm, v_deptno
FROM emp WHERE empno = v_empno;
DBMS_OUTPUT.PUT_LINE('Department : ' || v_deptno);
DBMS_OUTPUT.PUT_LINE('Employee No: ' || v_empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || v_ename);
DBMS_OUTPUT.PUT_LINE('Job : ' || v_job);
DBMS_OUTPUT.PUT_LINE('Manager : ' || v_mgr);
DBMS_OUTPUT.PUT_LINE('Hire Date : ' || v_hiredate);
DBMS_OUTPUT.PUT_LINE('Salary : ' || v_sal);
DBMS_OUTPUT.PUT_LINE('Commission : ' || v_comm);
RETURN v_empno;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('The following is SQLERRM:');
DBMS_OUTPUT.PUT_LINE(SQLERRM);
DBMS_OUTPUT.PUT_LINE('The following is SQLCODE:');
DBMS_OUTPUT.PUT_LINE(SQLCODE);
RETURN -1;
END;
ステップ7 - 必要な特権を与える
ユーザーとして接続し、 hr_mgr、sales_mgr list_emp手順 、hire_clerk機能、およびEMP_ADMINパッケージを実行できるように、必要な権限を付与します。 sales_mgrがアクセスできるデータオブジェクトは、 sales_mgrスキーマのempテーブルだけです。 sales_mgrには、 hr_mgrスキーマ内の表に対する権限はありません。
GRANT USAGE ON SCHEMA hr_mgr TO sales_mgr;
GRANT EXECUTE ON PROCEDURE list_emp TO sales_mgr;
GRANT EXECUTE ON FUNCTION hire_clerk(VARCHAR2,NUMBER) TO sales_mgr;
GRANT EXECUTE ON FUNCTION new_empno() TO sales_mgr;
GRANT EXECUTE ON PACKAGE emp_admin TO sales_mgr;
ステップ8 - プログラムを実行するlist_empとhire_clerk
ユーザー sales_mgr として接続し 、次の匿名ブロックを実行します。
\c – sales_mgr
DECLARE
v_empno NUMBER(4);
BEGIN
hr_mgr.list_emp;
DBMS_OUTPUT.PUT_LINE('*** Adding new employee ***');
v_empno := hr_mgr.hire_clerk('JONES',40);
DBMS_OUTPUT.PUT_LINE('*** After new employee added ***');
hr_mgr.list_emp;
END;
 
EMPNO ENAME
----- -------
7499 ALLEN
7521 WARD
7654 MARTIN
7844 TURNER
*** Adding new employee ***
Department : 40
Employee No: 8000
Name : JONES
Job : CLERK
Manager : 7782
Hire Date : 08-NOV-07 00:00:00
Salary : 950.00
*** After new employee added ***
EMPNO ENAME
----- -------
7499 ALLEN
7521 WARD
7654 MARTIN
7844 TURNER
8000 JONES
匿名ブロックのプログラムによってアクセスされるテーブルとシーケンスを次の図に示します。灰色の楕円は sales_mgrhr_mgrの スキーマを表します。各プログラム実行中の現在のユーザーは、括弧内に太字の赤いフォントで示されています。
図3 - 呼び出し側の権利プログラム
sales_mgrempテーブルから選択すると 、このテーブルで更新が行われたことが示されます。
SELECT empno, ename, hiredate, sal, deptno, hr_mgr.emp_admin.get_dept_name(deptno) FROM sales_mgr.emp;
 
empno | ename | hiredate | sal | deptno | get_dept_name
-------+--------+--------------------+---------+--------+---------------
7499 | ALLEN | 20-FEB-81 00:00:00 | 1600.00 | 30 | SALES
7521 | WARD | 22-FEB-81 00:00:00 | 1250.00 | 30 | SALES
7654 | MARTIN | 28-SEP-81 00:00:00 | 1250.00 | 30 | SALES
7844 | TURNER | 08-SEP-81 00:00:00 | 1500.00 | 30 | SALES
8000 | JONES | 08-NOV-07 00:00:00 | 950.00 | 40 | OPERATIONS
(5 rows)
次の図は、ことを示して SELECTコマンドリファレンスsales_mgrスキーマEMP表を、しかしEMP_ADMINパッケージは、定義者権限を持ち、hr_mgrが所有しているので、EMP_ADMINパッケージGET_DEPT_NAME機能によって参照DEPT表hr_mgrスキーマからです。 $ userプレースホルダを使用するデフォルトの検索パス設定では、 hr_mgrスキーマのdeptテーブルに対するユーザーhr_mgrのアクセスが解決されます。
図4 Definer's Rights Package
ステップ9 - emp_adminパッケージでhire_empプログラムを実行する
ユーザー sales_mgr として接続している間は、 emp_adminパッケージでhire_empプロシージャを実行します。
EXEC hr_mgr.emp_admin.hire_emp(9001, 'ALICE','SALESMAN',8000,TRUNC(SYSDATE),1000,7369,40);
この図は、ことを示して EMP_ADMINの定義者権限パッケージのhire_emp手順hr_mgrのオブジェクト権限が使用されているので、hr_mgrに属するemp表を更新し、$ユーザーのプレースホルダーでの設定デフォルトの検索パスはhr_mgrのスキーマに解決されます。
図5 Definer's Rights Package
今すぐユーザー hr_mgr として接続します 。次のSELECTコマンドは、 emp_adminパッケージに定義者権限があり、 hr_mgremp_adminの所有者であるため、新しい従業員がhr_mgrempテーブルに追加されたことを確認します。
\c – hr_mgr
SELECT empno, ename, hiredate, sal, deptno, hr_mgr.emp_admin.get_dept_name(deptno) FROM hr_mgr.emp;
 
empno | ename | hiredate | sal | deptno | get_dept_name
-------+--------+--------------------+---------+--------+---------------
7369 | SMITH | 17-DEC-80 00:00:00 | 800.00 | 20 | RESEARCH
7499 | ALLEN | 20-FEB-81 00:00:00 | 1600.00 | 30 | SALES
7521 | WARD | 22-FEB-81 00:00:00 | 1250.00 | 30 | SALES
7566 | JONES | 02-APR-81 00:00:00 | 2975.00 | 20 | RESEARCH
7654 | MARTIN | 28-SEP-81 00:00:00 | 1250.00 | 30 | SALES
7698 | BLAKE | 01-MAY-81 00:00:00 | 2850.00 | 30 | SALES
7782 | CLARK | 09-JUN-81 00:00:00 | 2450.00 | 10 | ACCOUNTING
7788 | SCOTT | 19-APR-87 00:00:00 | 3000.00 | 20 | RESEARCH
7839 | KING | 17-NOV-81 00:00:00 | 5000.00 | 10 | ACCOUNTING
7844 | TURNER | 08-SEP-81 00:00:00 | 1500.00 | 30 | SALES
7876 | ADAMS | 23-MAY-87 00:00:00 | 1100.00 | 20 | RESEARCH
7900 | JAMES | 03-DEC-81 00:00:00 | 950.00 | 30 | SALES
7902 | FORD | 03-DEC-81 00:00:00 | 3000.00 | 20 | RESEARCH
7934 | MILLER | 23-JAN-82 00:00:00 | 1300.00 | 10 | ACCOUNTING
9001 | ALICE | 08-NOV-07 00:00:00 | 8000.00 | 40 | OPERATIONS
(15 rows)
 
 
3.3 可変宣言
SPL はブロック構造言語です。ブロックに表示される最初のセクションは宣言です。宣言には 、ブロックに含まれる SPL ステートメント で使用できる変数、カーソル、およびその他のタイプの定義が 含まれています。
 
3.3.1 変数の宣言
一般に、ブロックで使用されるすべての変数は、ブロックの宣言セクションで宣言する必要があります。変数宣言は、変数に割り当てられた名前とそのデータ型で構成されます。必要に応じて、変数は変数宣言のデフォルト値に初期化することができます。
変数宣言の一般的な構文は次のとおりです。
name type [ { := | DEFAULT } { expression | NULL } ];
name は変数に割り当てられた識別子です。
type は変数に割り当てられたデータ型です。
[ := ]を指定すると、ブロックが入力されたときに変数に割り当てられた初期値を指定します。この節が指定されていない場合、変数は SQL NULL値に初期化されます。
デフォルト値はブロックが入力されるたびに評価されます。たとえば、 DATE型の変数にSYSDATE代入すると、プロシージャーまたは関数がプリコンパイルされた時点ではなく、現在の呼び出しの時刻になります。
次の手順では、文字列と数値式で構成されるデフォルトを使用する変数宣言を示します。
CREATE OR REPLACE PROCEDURE dept_salary_rpt (
p_deptno NUMBER
)
IS
todays_date DATE := SYSDATE;
rpt_title VARCHAR2(60) := 'Report For Department # ' || p_deptno
|| ' on ' || todays_date;
base_sal INTEGER := 35525;
base_comm_rate NUMBER := 1.33333;
base_annual NUMBER := ROUND(base_sal * base_comm_rate, 2);
BEGIN
DBMS_OUTPUT.PUT_LINE(rpt_title);
DBMS_OUTPUT.PUT_LINE('Base Annual Salary: ' || base_annual);
END;
上記の手順の次の出力は、変数宣言のデフォルト値が実際に変数に割り当てられていることを示しています。
EXEC dept_salary_rpt(20);
 
Report For Department # 20 on 10-JUL-07 16:44:45
Base Annual Salary: 47366.55
 
3.3.2 変数宣言での%TYPEの使用
多くの場合、変数は データベース内のテーブルの値を保持するために使用される SPL プログラムで 宣言され ます。テーブル列と SPL変数との間の互換性を保証するためには、2つのデータ型が同じである必要があります。
ただし、非常に頻繁に起こるように、テーブル定義に変更が加えられる可能性があります。列のデータ型が変更された場合、対応する変更が SPLプログラムの変数に必要になることがあります
特定の列データ型を変数宣言にコーディングする代わりに、列属性 %TYPEを代わりに使用できます。ドット表記の修飾列名または事前に宣言された変数の名前を%TYPEの接頭辞として指定する必要があります。 %TYPEにプレフィックスされた列または変数のデータ型は、宣言されている変数に割り当てられます。指定された列または変数のデータ型が変更された場合、宣言コードを変更することなく、新しいデータ型が変数に関連付けられます。
注意: %TYPE 属性は、同様に仮パラメータの宣言で使用することができます。
name { { table | view }. column | variable }%TYPE;
name は、宣言されている変数または仮パラメータに割り当てられた識別子です。 column は、 または ビュー 内の列の名前です variable は、nameで指定された変数の前に宣言された変数の 名前です。
注:変数は、 NOT NULL句またはDEFAULT句の列に指定されているような列の他の属性を継承しません。
次の例では 、従業員番号を使用し empテーブルを照会し 、従業員のデータを表示し、従業員が属する部門の全従業員の平均給与を見つけ、選択した従業員の給与と部門平均を比較します。
CREATE OR REPLACE PROCEDURE emp_sal_query (
p_empno IN NUMBER
)
IS
v_ename VARCHAR2(10);
v_job VARCHAR2(9);
v_hiredate DATE;
v_sal NUMBER(7,2);
v_deptno NUMBER(2);
v_avgsal NUMBER(7,2);
BEGIN
SELECT ename, job, hiredate, sal, deptno
INTO v_ename, v_job, v_hiredate, v_sal, v_deptno
FROM emp WHERE empno = p_empno;
DBMS_OUTPUT.PUT_LINE('Employee # : ' || p_empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || v_ename);
DBMS_OUTPUT.PUT_LINE('Job : ' || v_job);
DBMS_OUTPUT.PUT_LINE('Hire Date : ' || v_hiredate);
DBMS_OUTPUT.PUT_LINE('Salary : ' || v_sal);
DBMS_OUTPUT.PUT_LINE('Dept # : ' || v_deptno);
 
SELECT AVG(sal) INTO v_avgsal
FROM emp WHERE deptno = v_deptno;
IF v_sal > v_avgsal THEN
DBMS_OUTPUT.PUT_LINE('Employee''s salary is more than the '
|| 'department average of ' || v_avgsal);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee''s salary does not exceed the '
|| 'department average of ' || v_avgsal);
END IF;
END;
上記の代わりに、プロシージャ の宣言セクションに emp テーブルのデータ型を 明示的にコーディングせずに、プロシージャを次のように記述することができ ます。
CREATE OR REPLACE PROCEDURE emp_sal_query (
p_empno IN emp.empno%TYPE
)
IS
v_ename emp.ename%TYPE;
v_job emp.job%TYPE;
v_hiredate emp.hiredate%TYPE;
v_sal emp.sal%TYPE;
v_deptno emp.deptno%TYPE;
v_avgsal v_sal%TYPE;
BEGIN
SELECT ename, job, hiredate, sal, deptno
INTO v_ename, v_job, v_hiredate, v_sal, v_deptno
FROM emp WHERE empno = p_empno;
DBMS_OUTPUT.PUT_LINE('Employee # : ' || p_empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || v_ename);
DBMS_OUTPUT.PUT_LINE('Job : ' || v_job);
DBMS_OUTPUT.PUT_LINE('Hire Date : ' || v_hiredate);
DBMS_OUTPUT.PUT_LINE('Salary : ' || v_sal);
DBMS_OUTPUT.PUT_LINE('Dept # : ' || v_deptno);
 
SELECT AVG(sal) INTO v_avgsal
FROM emp WHERE deptno = v_deptno;
IF v_sal > v_avgsal THEN
DBMS_OUTPUT.PUT_LINE('Employee''s salary is more than the '
|| 'department average of ' || v_avgsal);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee''s salary does not exceed the '
|| 'department average of ' || v_avgsal);
END IF;
END;
注: p_empno は、 %TYPE を使用して定義された仮パラメータの例を示しています
v_avgsal は、 %TYPE の使用法を示し、テーブル列の代わりに別の変数を参照します。
以下は、この手順を実行した場合の出力例です。
EXEC emp_sal_query(7698);
 
Employee # : 7698
Name : BLAKE
Job : MANAGER
Hire Date : 01-MAY-81 00:00:00
Salary : 2850.00
Dept # : 30
Employee's salary is more than the department average of 1566.67
 
3.3.3 レコード宣言での%ROWTYPEの使用
%TYPE 属性は、列のデータ型に依存して変数を作成する簡単な方法を提供します。 %ROWTYPE属性を使用すると、特定の表のすべての列に対応するフィールドを含むレコードを定義できます。各フィールドは、対応する列のデータ型を取ります。レコードのフィールドは、 NOT NULL句またはDEFAULT句で指定されたような列の他の属性を継承しません
レコードが命名され、フィールドのコレクションを命じました。 フィールドは変数に似ています。識別子とデータ型を持ちますが、レコードに属しているという追加の特性があり、レコード名を修飾子としてドット表記法を使用して参照する必要があります。
あなたは使用することができ 、レコードを宣言する%ROWTYPE属性を。 %ROWTYPE属性の前には表名が付いています。名前付きテーブルの各列は、列と同じデータ型を持つレコード内の同じ名前のフィールドを定義します。
record table %ROWTYPE ;
レコード レコードに 割り当てられた識別子です。 tableは、列がレコード内のフィールドを定義するテーブル(またはビュー)の名前です。次の例では、前のセクションからemp_sal_query手順EMP内の列の個々の変数を宣言する代わりr_empという名前のレコードを作成するためのemp%のROWTYPEを使用するように変更することができる方法を示しています。
CREATE OR REPLACE PROCEDURE emp_sal_query (
p_empno IN emp.empno%TYPE
)
IS
r_emp emp%ROWTYPE;
v_avgsal emp.sal%TYPE;
BEGIN
SELECT ename, job, hiredate, sal, deptno
INTO r_emp.ename, r_emp.job, r_emp.hiredate, r_emp.sal, r_emp.deptno
FROM emp WHERE empno = p_empno;
DBMS_OUTPUT.PUT_LINE('Employee # : ' || p_empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || r_emp.ename);
DBMS_OUTPUT.PUT_LINE('Job : ' || r_emp.job);
DBMS_OUTPUT.PUT_LINE('Hire Date : ' || r_emp.hiredate);
DBMS_OUTPUT.PUT_LINE('Salary : ' || r_emp.sal);
DBMS_OUTPUT.PUT_LINE('Dept # : ' || r_emp.deptno);
SELECT AVG(sal) INTO v_avgsal
FROM emp WHERE deptno = r_emp.deptno;
IF r_emp.sal > v_avgsal THEN
DBMS_OUTPUT.PUT_LINE('Employee''s salary is more than the '
|| 'department average of ' || v_avgsal);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee''s salary does not exceed the '
|| 'department average of ' || v_avgsal);
END IF;
END;
 
3.3.4 ユーザー定義のレコード・タイプとレコード変数
レコードは 3.3.3 項に示すように %ROWTYPE 属性 を使用する表定義に基づいて宣言 でき ます 。このセクションでは、特定のテーブル定義に関連付けられていない新しいレコード構造を定義する方法について説明します。
TYPEレコード型の定義を作成するために使用されるレコードですレコードタイプは、1つ以上の識別子とそれに対応するデータタイプで構成されるレコードの定義です。レコードタイプはそれ自体でデータを操作することはできません。
TYPE IS RECORDステートメントの構文は次のとおりです。
TYPE rec _ type IS RECORD( フィールド
where fieldsは、次の形式の1つ以上のフィールド定義のカンマ区切りリストです。
フィールド _ 名前 data_type [NOT NULL] [{:= | DEFAULT} デフォルト _ ]
場所:
rec_type
rec_type は、レコードタイプに割り当てられた識別子です。
フィールド名
field_name は、レコードタイプのフィールドに割り当てられた識別子です。
データ・タイプ
data_type は、 field_name のデータ型を指定します
DEFAULT default_value
DEFAULT句は、対応するフィールドのデフォルトデータ値を割り当てます。デフォルトの式のデータ型は、列のデータ型と一致する必要があります。デフォルトを指定しない場合、デフォルトはNULLです。
レコード変数または簡単に言えば、 レコードは 、レコード型のインスタンスです。レコードはレコードタイプから宣言されます。フィールド名や型などのレコードのプロパティは、レコードタイプから継承されます。
レコード宣言の構文は次のとおりです。
record rectype
record は、レコード変数に割り当てられた識別子です。 rectypeは、以前に定義されたレコードタイプの識別子です。一度宣言すると、レコードを使用してデータを保持できます。
ドット記法は、レコード内のフィールドを参照するために使用されます。
record.field
レコード は以前に宣言されたレコード変数であり、 フィールド レコードが定義されているレコードタイプに属するフィールドの識別子です
ユーザ定義レコード型とレコード変数を使用して、この時間- emp_sal_queryが再び変更されます。
CREATE OR REPLACE PROCEDURE emp_sal_query (
p_empno IN emp.empno%TYPE
)
IS
TYPE emp_typ IS RECORD (
ename emp.ename%TYPE,
job emp.job%TYPE,
hiredate emp.hiredate%TYPE,
sal emp.sal%TYPE,
deptno emp.deptno%TYPE
);
r_emp emp_typ;
v_avgsal emp.sal%TYPE;
BEGIN
SELECT ename, job, hiredate, sal, deptno
INTO r_emp.ename, r_emp.job, r_emp.hiredate, r_emp.sal, r_emp.deptno
FROM emp WHERE empno = p_empno;
DBMS_OUTPUT.PUT_LINE('Employee # : ' || p_empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || r_emp.ename);
DBMS_OUTPUT.PUT_LINE('Job : ' || r_emp.job);
DBMS_OUTPUT.PUT_LINE('Hire Date : ' || r_emp.hiredate);
DBMS_OUTPUT.PUT_LINE('Salary : ' || r_emp.sal);
DBMS_OUTPUT.PUT_LINE('Dept # : ' || r_emp.deptno);
 
SELECT AVG(sal) INTO v_avgsal
FROM emp WHERE deptno = r_emp.deptno;
IF r_emp.sal > v_avgsal THEN
DBMS_OUTPUT.PUT_LINE('Employee''s salary is more than the '
|| 'department average of ' || v_avgsal);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee''s salary does not exceed the '
|| 'department average of ' || v_avgsal);
END IF;
END;
データ型名を指定する代わりに、 %TYPE属性をレコード・タイプ定義内のフィールド・データ型に使用できることに注意してください
以下は、このストアドプロシージャの実行結果です。
EXEC emp_sal_query(7698);
 
Employee # : 7698
Name : BLAKE
Job : MANAGER
Hire Date : 01-MAY-81 00:00:00
Salary : 2850.00
Dept # : 30
Employee's salary is more than the department average of 1566.67
3.4 基本的なステートメント
このセクションでは、 SPL プログラムで 使用できるプログラミング文について説明し ます。
3.4.1 NULL
最も簡単なステートメントは NULL ステートメントです。このステートメントは、何も実行しない実行可能ステートメントです。
NULL;
以下は、最も単純で有効な有効な SPL プログラムです。
BEGIN
NULL;
END;
NULL は実行文は IF-THEN-ELSEの枝のような必要とされるプレースホルダとして機能することができます。
例えば:
CREATE OR REPLACE PROCEDURE divide_it (
p_numerator IN NUMBER,
p_denominator IN NUMBER,
p_result OUT NUMBER
)
IS
BEGIN
IF p_denominator = 0 THEN
NULL;
ELSE
p_result := p_numerator / p_denominator;
END IF;
END;
3.4.2 割り当て
代入文は、代入 の左側に指定された モード OUT または IN OUTの 変数または仮パラメータ :=を 代入 の右側に指定された評価式に設定します。
variable := expression ;
variable は、以前に宣言された変数、 OUT 仮パラメータ、または IN OUT 仮パラメータの 識別子です
expression は単一の値を生成する式です。式によって生成される値は、 変数 と互換性のあるデータ型でなければなりません
次の例は、プロシージャの実行可能セクションに代入文を使用する典型的な例を示しています。
CREATE OR REPLACE PROCEDURE dept_salary_rpt (
p_deptno NUMBER
)
IS
todays_date DATE;
rpt_title VARCHAR2(60);
base_sal INTEGER;
base_comm_rate NUMBER;
base_annual NUMBER;
BEGIN
todays_date := SYSDATE;
rpt_title := 'Report For Department # ' || p_deptno || ' on '
|| todays_date;
base_sal := 35525;
base_comm_rate := 1.33333;
base_annual := ROUND(base_sal * base_comm_rate, 2);
 
DBMS_OUTPUT.PUT_LINE(rpt_title);
DBMS_OUTPUT.PUT_LINE('Base Annual Salary: ' || base_annual);
END;
3.4.3 SELECT INTO
SELECT INTO ステートメント、SQL SPL の変動 であります SELECTコマンド、違いは:
その SELECT INTOは、結果を変数またはレコードに代入してSPLプログラムステートメントで使用できるように設計されています。
SELECT INTO のアクセス可能な結果セットは、たかだか1行です。
上記以外の WHEREORDER BYGROUP BYHAVINGなど SELECTコマンドのすべての句は、 SELECT INTOに対して有効です。 SELECT INTOの 2つのバリエーションは次のとおりです。
SELECT select_expressions INTO target FROM ...;
target はカンマで区切られた単純変数のリストです。 select_expressions と残りの文は SELECT コマンド と同じ です。選択された値は、データ型、数値、および順序がターゲットの構造と正確に一致する必要があります。また、実行時エラーが発生します。
SELECT * INTO record FROM table ...;
レコードは以前に宣言されたレコード変数です。
問合せがゼロ行を戻す場合、NULL値がターゲットに割り当てられます。クエリが複数の行を返す場合、最初の行はターゲットに割り当てられ、残りは破棄されます。 ( ORDER BYを使用していない限り 「最初の行」は明確に定義されていません)。
注意: どちらの場合も、行が返されないか、複数の行が返される場合、 SPLは例外をスローします。
注:コレクションに戻される複数の行の結果セットを許可するBULK COLLECT節を使用するSELECT INTOのバリエーションがあります。 SELECT INTO文にBULK COLLECT句を使用する方法の詳細は、第3.12.4.1項を参照してください。
EXCEPTIONブロック WHEN NO_DATA_FOUND節を使用して 、割り当てが成功したかどうか(つまり、クエリによって少なくとも1つの行が返されたかどうか)を判断できます。
このバージョンの emp_sal_queryプロシージャは、結果セットをレコードに戻すSELECT INTOのバリエーションを使用します。 WHEN NO_DATA_FOUND条件式を含むEXCEPTIONブロックの追加にも注意してください。
CREATE OR REPLACE PROCEDURE emp_sal_query (
p_empno IN emp.empno%TYPE
)
IS
r_emp emp%ROWTYPE;
v_avgsal emp.sal%TYPE;
BEGIN
SELECT * INTO r_emp
FROM emp WHERE empno = p_empno;
DBMS_OUTPUT.PUT_LINE('Employee # : ' || p_empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || r_emp.ename);
DBMS_OUTPUT.PUT_LINE('Job : ' || r_emp.job);
DBMS_OUTPUT.PUT_LINE('Hire Date : ' || r_emp.hiredate);
DBMS_OUTPUT.PUT_LINE('Salary : ' || r_emp.sal);
DBMS_OUTPUT.PUT_LINE('Dept # : ' || r_emp.deptno);
 
SELECT AVG(sal) INTO v_avgsal
FROM emp WHERE deptno = r_emp.deptno;
IF r_emp.sal > v_avgsal THEN
DBMS_OUTPUT.PUT_LINE('Employee''s salary is more than the '
|| 'department average of ' || v_avgsal);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee''s salary does not exceed the '
|| 'department average of ' || v_avgsal);
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Employee # ' || p_empno || ' not found');
END;
存在しない従業員番号を使用してクエリを実行すると、結果は次のように表示されます。
EXEC emp_sal_query(0);
 
Employee # 0 not found
SELECT INTOを 伴う EXCEPTION セクション で使用するもう1つの条件節 は、 TOO_MANY_ROWS 例外です。 SELECT INTO によって複数の行が選択されている場合 SPL によって例外がスローされます。
次のブロックを実行すると、指定された部門に従業員が多数いるため TOO_MANY_ROWS例外がスローされます。
DECLARE
v_ename emp.ename%TYPE;
BEGIN
SELECT ename INTO v_ename FROM emp WHERE deptno = 20 ORDER BY ename;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('More than one employee found');
DBMS_OUTPUT.PUT_LINE('First employee returned is ' || v_ename);
END;
 
More than one employee found
First employee returned is ADAMS
注: 3.5.7 項を参照して ください。 例外処理に関する詳細情報
3.4.4 INSERT
SQL 言語 で利用可能な INSERT コマンド 、SPLプログラムで使用することができます
で表現式がSQLの INSERTコマンドで許可されている場所SPL言語を使用することができます。したがって、 SPL変数およびパラメータを使用して、挿入操作に値を供給することができます。
以下は、呼び出し元のプログラムから渡されたデータを使用して新しい従業員の挿入を実行するプロシージャーの例です。
CREATE OR REPLACE PROCEDURE emp_insert (
p_empno IN emp.empno%TYPE,
p_ename IN emp.ename%TYPE,
p_job IN emp.job%TYPE,
p_mgr IN emp.mgr%TYPE,
p_hiredate IN emp.hiredate%TYPE,
p_sal IN emp.sal%TYPE,
p_comm IN emp.comm%TYPE,
p_deptno IN emp.deptno%TYPE
)
IS
BEGIN
INSERT INTO emp VALUES (
p_empno,
p_ename,
p_job,
p_mgr,
p_hiredate,
p_sal,
p_comm,
p_deptno);
 
DBMS_OUTPUT.PUT_LINE('Added employee...');
DBMS_OUTPUT.PUT_LINE('Employee # : ' || p_empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || p_ename);
DBMS_OUTPUT.PUT_LINE('Job : ' || p_job);
DBMS_OUTPUT.PUT_LINE('Manager : ' || p_mgr);
DBMS_OUTPUT.PUT_LINE('Hire Date : ' || p_hiredate);
DBMS_OUTPUT.PUT_LINE('Salary : ' || p_sal);
DBMS_OUTPUT.PUT_LINE('Commission : ' || p_comm);
DBMS_OUTPUT.PUT_LINE('Dept # : ' || p_deptno);
DBMS_OUTPUT.PUT_LINE('----------------------');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('OTHERS exception on INSERT of employee # '
|| p_empno);
DBMS_OUTPUT.PUT_LINE('SQLCODE : ' || SQLCODE);
DBMS_OUTPUT.PUT_LINE('SQLERRM : ' || SQLERRM);
END;
例外が発生した場合、プロシージャ内のすべてのデータベース変更が自動的にロールバックされます。この例では WHEN OTHERS 句を含む EXCEPTION セクションは すべての例外をキャッチします。 2つの変数が表示されます。 SQLCODE は、発生した特定の例外を識別する番号です。 SQLERRM は、エラーを説明するテキスト・メッセージです。例外処理の詳細については、 3.5.7 項を参照してください
この手順を実行したときの出力を以下に示します。
EXEC emp_insert(9503,'PETERSON','ANALYST',7902,'31-MAR-05',5000,NULL,40);
 
Added employee...
Employee # : 9503
Name : PETERSON
Job : ANALYST
Manager : 7902
Hire Date : 31-MAR-05 00:00:00
Salary : 5000
Dept # : 40
----------------------
 
SELECT * FROM emp WHERE empno = 9503;
 
empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+----------+---------+------+--------------------+---------+------+--------
9503 | PETERSON | ANALYST | 7902 | 31-MAR-05 00:00:00 | 5000.00 | | 40
(1 row)
注: INSERTコマンドはFORALLステートメントに含めることができます。 FORALL文を使用すると、1つまたは複数のコレクションで指定された値から複数の行をINSERTコマンドで挿入できます FORALL ステートメントの 詳細については、 3.12.3 参照してください
3.4.5 更新
SQL 言語 で利用可能 UPDATE コマンド 、SPLプログラムで使用することができます
SQL UPDATEコマンドで式が許可されている場合は SPL言語の式を使用できます 。したがって、 SPL変数およびパラメータを使用して、更新操作に値を供給することができます。
CREATE OR REPLACE PROCEDURE emp_comp_update (
p_empno IN emp.empno%TYPE,
p_sal IN emp.sal%TYPE,
p_comm IN emp.comm%TYPE
)
IS
BEGIN
UPDATE emp SET sal = p_sal, comm = p_comm WHERE empno = p_empno;
 
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('Updated Employee # : ' || p_empno);
DBMS_OUTPUT.PUT_LINE('New Salary : ' || p_sal);
DBMS_OUTPUT.PUT_LINE('New Commission : ' || p_comm);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee # ' || p_empno || ' not found');
END IF;
END;
行が FALSE さもなければ 、更新された場合 、SQL%FOUND 条件式は TRUEを 返し SQL%FOUNDと他の同様の式については、 3.4.8 項を参照してください
この手順を使用して従業員の更新を以下に示します。
EXEC emp_comp_update(9503, 6540, 1200);
 
Updated Employee # : 9503
New Salary : 6540
New Commission : 1200
 
SELECT * FROM emp WHERE empno = 9503;
 
empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+----------+---------+------+--------------------+---------+---------+--------
9503 | PETERSON | ANALYST | 7902 | 31-MAR-05 00:00:00 | 6540.00 | 1200.00 | 40
(1 row)
注: UPDATEコマンドは、 FORALLステートメントに組み込むことができます。 FORALL文を使用すると、1つ以上のコレクションで指定された値から1つのUPDATEコマンドで複数の行を更新できます。セクションを参照してください。 3.12.3を FORALL の詳細については
3.4.6 DELETE
(SQL 言語 で利用可能 )DELETE コマンドは 、SPLプログラムで使用することができます
で表現式がSQLコマンドをDELETEに許可されている場所SPL言語を使用することができます。したがって、 SPL変数およびパラメータを使用して、削除操作に値を供給することができます。
CREATE OR REPLACE PROCEDURE emp_delete (
p_empno IN emp.empno%TYPE
)
IS
BEGIN
DELETE FROM emp WHERE empno = p_empno;
 
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('Deleted Employee # : ' || p_empno);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee # ' || p_empno || ' not found');
END IF;
END;
SQL%は、 行が そうでなけれ FALSE 削除された場合 、条件式は TRUEを 返し 見出しました SQL%FOUNDと他の同様の式については、 3.4.8 項を参照してください
この手順を使用している従業員を削除する手順を以下に示します。
EXEC emp_delete(9503);
 
Deleted Employee # : 9503
 
SELECT * FROM emp WHERE empno = 9503;
 
empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+-------+-----+-----+----------+-----+------+--------
(0 rows)
注: DELETEコマンドは、 FORALLステートメントに組み込むことができます。 FORALL文では、1つ以上のコレクションで指定された値から複数の行を削除する単一のDELETEコマンドを使用できます 3.12.3 項を参照してください FORALLステートメントの詳細については、
3.4.7 RETURNING INTO句の使用
INSERT、UPDATE、および DELETE コマンド RETURNING INTO オプションが付加されてもよいです この句を使用すると、 SPL プログラムは INSERT UPDATE または DELETEコマンドの結果から新たに追加、変更、または削除された値を取得 できます
構文は次のとおりです。
{ insert | update | delete }
RETURNING { * | expr_1 [, expr_2 ] ...}
INTO { record | field_1 [, field_2 ] ...};
insert は有効な INSERT コマンドです。 update は有効な UPDATE コマンドです。 delete は有効な DELETE コマンドです。 *が 指定されている 場合 、INSERTの影響を受けた行の値 、UPDATE、またはDELETE コマンド INTO キーワード の右側にレコードまたはフィールドへの割り当てのために利用可能にされます (*の使用は、Advanced Serverの 拡張機能 であり 、Oracleデータベースと互換性が ない ことに注意してください 。)expr_1、expr_2 ... INSERT によって影響を受ける行時に評価される式 、UPDATE、またはDELETE コマンド です 。評価された結果は、 INTO キーワードの 右側のレコードに割り当てられ ます。 record は、番号と順序が一致するフィールドを含む必要のあるレコードの識別子で、 RETURNING 句の 値と互換性のあるデータ型 です。 field_1 field_2 、...は、番号と順序が一致しなければならない変数で、 RETURNING句の値のセットと互換性のあるデータ型です。
INSERTUPDATE 、またはDELETEコマンドが複数の行を含む結果セットを戻す場合、 SQLCODE 01422で例外がスローされ、複数の行が戻されます 。結果セットに行がない場合、 INTOキーワードに続く変数はNULLに設定されます。
注:コレクションに戻される複数の行の結果セットを許可するBULK COLLECT節を使用すると、 RETURNING INTOのバリエーションがあります。 BULK COLLECT句の詳細については、第3.12.4項を参照してください。
次の例は、 3.4.5項で導入され emp_comp_updateプロシージャの変更であり、 RETURNING INTO句が追加されています。
CREATE OR REPLACE PROCEDURE emp_comp_update (
p_empno IN emp.empno%TYPE,
p_sal IN emp.sal%TYPE,
p_comm IN emp.comm%TYPE
)
IS
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
v_job emp.job%TYPE;
v_sal emp.sal%TYPE;
v_comm emp.comm%TYPE;
v_deptno emp.deptno%TYPE;
BEGIN
UPDATE emp SET sal = p_sal, comm = p_comm WHERE empno = p_empno
RETURNING
empno,
ename,
job,
sal,
comm,
deptno
INTO
v_empno,
v_ename,
v_job,
v_sal,
v_comm,
v_deptno;
 
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('Updated Employee # : ' || v_empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || v_ename);
DBMS_OUTPUT.PUT_LINE('Job : ' || v_job);
DBMS_OUTPUT.PUT_LINE('Department : ' || v_deptno);
DBMS_OUTPUT.PUT_LINE('New Salary : ' || v_sal);
DBMS_OUTPUT.PUT_LINE('New Commission : ' || v_comm);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee # ' || p_empno || ' not found');
END IF;
END;
このプロシージャの出力は次のとおりです( emp_insert プロシージャ によって作成された 従業員 9503 が表内にまだ存在することが 前提 です)。
EXEC emp_comp_update(9503, 6540, 1200);
 
Updated Employee # : 9503
Name : PETERSON
Job : ANALYST
Department : 40
New Salary : 6540.00
New Commission : 1200.00
次の例は、 emp_delete プロシージャの 変更です 。レコード型を使用し RETURNING INTO 句が 追加されてい ます。
CREATE OR REPLACE PROCEDURE emp_delete (
p_empno IN emp.empno%TYPE
)
IS
r_emp emp%ROWTYPE;
BEGIN
DELETE FROM emp WHERE empno = p_empno
RETURNING
*
INTO
r_emp;
 
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('Deleted Employee # : ' || r_emp.empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || r_emp.ename);
DBMS_OUTPUT.PUT_LINE('Job : ' || r_emp.job);
DBMS_OUTPUT.PUT_LINE('Manager : ' || r_emp.mgr);
DBMS_OUTPUT.PUT_LINE('Hire Date : ' || r_emp.hiredate);
DBMS_OUTPUT.PUT_LINE('Salary : ' || r_emp.sal);
DBMS_OUTPUT.PUT_LINE('Commission : ' || r_emp.comm);
DBMS_OUTPUT.PUT_LINE('Department : ' || r_emp.deptno);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee # ' || p_empno || ' not found');
END IF;
END;
この手順の出力は次のとおりです。
EXEC emp_delete(9503);
 
Deleted Employee # : 9503
Name : PETERSON
Job : ANALYST
Manager : 7902
Hire Date : 31-MAR-05 00:00:00
Salary : 6540.00
Commission : 1200.00
Department : 40
3.4.8 結果ステータスの取得
コマンドの効果を判断するために使用できる属性はいくつかあります。 SQL%FOUND は、 少なくとも1つの行が INSERT UPDATE、 または DELETE コマンドの 影響を受けた 場合、または SELECT INTOコマンドが1つ以上の行を取得した場合に true を返すブール値です
次の無名ブロックは行を挿入し、その行が挿入されたという事実を表示します。
BEGIN
INSERT INTO emp (empno,ename,job,sal,deptno) VALUES (
9001, 'JONES', 'CLERK', 850.00, 40);
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('Row has been inserted');
END IF;
END;
 
Row has been inserted
SQL%ROWCOUNT は、 INSERT UPDATE DELETE 、または SELECT INTO コマンドの 影響を受ける行の数を提供します SQL%ROWCOUNTの 、BIGINT データ として返されます 。次の例は、挿入されたばかりの行を更新し、 SQL%ROWCOUNT を表示し ます
BEGIN
UPDATE emp SET hiredate = '03-JUN-07' WHERE empno = 9001;
DBMS_OUTPUT.PUT_LINE('# rows updated: ' || SQL%ROWCOUNT);
END;
 
# rows updated: 1
SQL%NOTFOUND SQL%FOUNDの 反対です SQL%NOTFOUND INSERT UPDATE または DELETE コマンド によって影響を受けた行がない場合、 または SELECT INTO コマンドが行を取得しなかった 場合 trueを 返し ます
BEGIN
UPDATE emp SET hiredate = '03-JUN-07' WHERE empno = 9000;
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('No rows were updated');
END IF;
END;
 
No rows were updated
3.5 制御構造
この節では SPL のプログラミングステートメントを使用して、 SQLの完全な手続き補完を説明します
3.5.1 IF宣言
IF 文を使用すると、特定の条件に基づいてコマンドを実行できます。 SPLに は4つの IF 形式があり ます。
3.5.1.1 IF-THEN
IF boolean-expression THEN
statements
END IF;
IF-THEN 文は、IFの最も単純な形式です 条件が真であれば、 THEN END IFの 間のステートメントが実行されます 。それ以外の場合はスキップされます。
次の例では、 IF-THENステートメントを使用して、手数料を持つ従業員をテストして表示します。
DECLARE
v_empno emp.empno%TYPE;
v_comm emp.comm%TYPE;
CURSOR emp_cursor IS SELECT empno, comm FROM emp;
BEGIN
OPEN emp_cursor;
DBMS_OUTPUT.PUT_LINE('EMPNO COMM');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH emp_cursor INTO v_empno, v_comm;
EXIT WHEN emp_cursor%NOTFOUND;
--
-- Test whether or not the employee gets a commission
--
IF v_comm IS NOT NULL AND v_comm > 0 THEN
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' ||
TO_CHAR(v_comm,'$99999.99'));
END IF;
END LOOP;
CLOSE emp_cursor;
END;
このプログラムの出力は次のとおりです。
EMPNO COMM
----- -------
7499 $300.00
7521 $500.00
7654 $1400.00
3.5.1.2 IF-THEN-ELSE
IF boolean-expression THEN
statements
ELSE
statements
END IF;
IF-THEN-ELSE ステートメントは、条件がfalseと評価された場合に実行されるステートメントの代替セットを指定させることによって、 IF-THENに 追加されます。
IF-THEN-ELSEステートメントを使用して、従業員が手数料を受け取らない場合は、 非手数料テキストを表示するように、前の例を変更しました
DECLARE
v_empno emp.empno%TYPE;
v_comm emp.comm%TYPE;
CURSOR emp_cursor IS SELECT empno, comm FROM emp;
BEGIN
OPEN emp_cursor;
DBMS_OUTPUT.PUT_LINE('EMPNO COMM');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH emp_cursor INTO v_empno, v_comm;
EXIT WHEN emp_cursor%NOTFOUND;
--
-- Test whether or not the employee gets a commission
--
IF v_comm IS NOT NULL AND v_comm > 0 THEN
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' ||
TO_CHAR(v_comm,'$99999.99'));
ELSE
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || 'Non-commission');
END IF;
END LOOP;
CLOSE emp_cursor;
END;
このプログラムの出力は次のとおりです。
EMPNO COMM
----- -------
7369 Non-commission
7499 $ 300.00
7521 $ 500.00
7566 Non-commission
7654 $ 1400.00
7698 Non-commission
7782 Non-commission
7788 Non-commission
7839 Non-commission
7844 Non-commission
7876 Non-commission
7900 Non-commission
7902 Non-commission
7934 Non-commission
3.5.1.3 IF-THERM-ELSE IF
IF 文を入れ子にして 、外部 IF文の条件真である であるかを判定したら 、代替 IF 文を呼び出すことができ ます
次の例では、外側 IF-THEN-ELSEステートメントは、従業員に手数料があるかどうかをテストします。 IF-THEN-ELSEの内側のステートメントは、従業員の総報酬が会社の平均を上回るか下回るかをテストします。
DECLARE
v_empno emp.empno%TYPE;
v_sal emp.sal%TYPE;
v_comm emp.comm%TYPE;
v_avg NUMBER(7,2);
CURSOR emp_cursor IS SELECT empno, sal, comm FROM emp;
BEGIN
--
-- Calculate the average yearly compensation in the company
--
SELECT AVG((sal + NVL(comm,0)) * 24) INTO v_avg FROM emp;
DBMS_OUTPUT.PUT_LINE('Average Yearly Compensation: ' ||
TO_CHAR(v_avg,'$999,999.99'));
OPEN emp_cursor;
DBMS_OUTPUT.PUT_LINE('EMPNO YEARLY COMP');
DBMS_OUTPUT.PUT_LINE('----- -----------');
LOOP
FETCH emp_cursor INTO v_empno, v_sal, v_comm;
EXIT WHEN emp_cursor%NOTFOUND;
--
-- Test whether or not the employee gets a commission
--
IF v_comm IS NOT NULL AND v_comm > 0 THEN
--
-- Test if the employee's compensation with commission exceeds the average
--
IF (v_sal + v_comm) * 24 > v_avg THEN
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' ||
TO_CHAR((v_sal + v_comm) * 24,'$999,999.99') ||
' Exceeds Average');
ELSE
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' ||
TO_CHAR((v_sal + v_comm) * 24,'$999,999.99') ||
' Below Average');
END IF;
ELSE
--
-- Test if the employee's compensation without commission exceeds the average
--
IF v_sal * 24 > v_avg THEN
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' ||
TO_CHAR(v_sal * 24,'$999,999.99') || ' Exceeds Average');
ELSE
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' ||
TO_CHAR(v_sal * 24,'$999,999.99') || ' Below Average');
END IF;
END IF;
END LOOP;
CLOSE emp_cursor;
END;
注: このプログラムのロジック は、カーソル宣言の SELECT コマンド 内で NVL 関数 を使用して従業員の年次報酬を計算することによって大幅に単純化できますが 、この例の目的は IF 文の使用 方法を示す ことです。
このプログラムの出力は次のとおりです。
Average Yearly Compensation: $ 53,528.57
EMPNO YEARLY COMP
----- -----------
7369 $ 19,200.00 Below Average
7499 $ 45,600.00 Below Average
7521 $ 42,000.00 Below Average
7566 $ 71,400.00 Exceeds Average
7654 $ 63,600.00 Exceeds Average
7698 $ 68,400.00 Exceeds Average
7782 $ 58,800.00 Exceeds Average
7788 $ 72,000.00 Exceeds Average
7839 $ 120,000.00 Exceeds Average
7844 $ 36,000.00 Below Average
7876 $ 26,400.00 Below Average
7900 $ 22,800.00 Below Average
7902 $ 72,000.00 Exceeds Average
7934 $ 31,200.00 Below Average
このフォームを使用すると、実際に は、外側の IF 文の ELSE 部分に IF がネストされます 。したがって 、ネストされた IF ごとに 1つの END IF が必要 で、親 IF-ELSEに 1つ必要 です。
3.5.1.4 IF-THEN-ELSIF-ELSE
IF boolean-expression THEN
statements
[ ELSIF boolean-expression THEN
statements
[ ELSIF boolean-expression THEN
statements ] ...]
[ ELSE
statements ]
END IF;
IF-THEN-ELSIF-ELSE は、1つのステートメントで多くの選択肢をチェックする方法を提供します。正式にはネストされた IF-THEN-ELSE-IF-THEN コマンド と同等ですが END IF1つだけ必要です。
次の例では、 IF-THEN-ELSIF-ELSEステートメントを使用して、従業員数を$ 25,000の補償範囲で数えます。
DECLARE
v_empno emp.empno%TYPE;
v_comp NUMBER(8,2);
v_lt_25K SMALLINT := 0;
v_25K_50K SMALLINT := 0;
v_50K_75K SMALLINT := 0;
v_75K_100K SMALLINT := 0;
v_ge_100K SMALLINT := 0;
CURSOR emp_cursor IS SELECT empno, (sal + NVL(comm,0)) * 24 FROM emp;
BEGIN
OPEN emp_cursor;
LOOP
FETCH emp_cursor INTO v_empno, v_comp;
EXIT WHEN emp_cursor%NOTFOUND;
IF v_comp < 25000 THEN
v_lt_25K := v_lt_25K + 1;
ELSIF v_comp < 50000 THEN
v_25K_50K := v_25K_50K + 1;
ELSIF v_comp < 75000 THEN
v_50K_75K := v_50K_75K + 1;
ELSIF v_comp < 100000 THEN
v_75K_100K := v_75K_100K + 1;
ELSE
v_ge_100K := v_ge_100K + 1;
END IF;
END LOOP;
CLOSE emp_cursor;
DBMS_OUTPUT.PUT_LINE('Number of employees by yearly compensation');
DBMS_OUTPUT.PUT_LINE('Less than 25,000 : ' || v_lt_25K);
DBMS_OUTPUT.PUT_LINE('25,000 - 49,9999 : ' || v_25K_50K);
DBMS_OUTPUT.PUT_LINE('50,000 - 74,9999 : ' || v_50K_75K);
DBMS_OUTPUT.PUT_LINE('75,000 - 99,9999 : ' || v_75K_100K);
DBMS_OUTPUT.PUT_LINE('100,000 and over : ' || v_ge_100K);
END;
このプログラムの出力は次のとおりです。
Number of employees by yearly compensation
Less than 25,000 : 2
25,000 - 49,9999 : 5
50,000 - 74,9999 : 6
75,000 - 99,9999 : 0
100,000 and over : 1
 
3.5.2 RETURN文
RETURN文は、現在の関数、プロシージャまたは無名ブロックを終了し、呼び出し元に制御を戻します。
RETURNステートメントには2つの形式がありますRETURN文の最初の形式は、 voidを返すプロシージャまたは関数を終了するために使用されます 。最初の形式の構文は次のとおりです。
戻ってください。
RETURN の2番目の形式は 、呼び出し側に値を返します。 RETURNステートメントの2番目の形式の構文は次のとおりです。
RETURN
は、関数の戻り値の型と同じデータ型に評価されなければなりません。
次の例では、 RETURN文を使用して呼び出し元に値を返します。
CREATE OR REPLACE FUNCTION emp_comp (
p_sal NUMBER,
p_comm NUMBER
) RETURN NUMBER
IS
BEGIN
RETURN (p_sal + NVL(p_comm, 0)) * 24;
END emp_comp;
 
3.5.3 GOTOステートメント
GOTO文は、指定されたラベルでのステートメントにジャンプし、実行のポイントになります。 GOTOステートメントの構文は次のとおりです。
GOTO ラベル
labelは実行可能なステートメントに割り当てられた名前です。 ラベルは、関数、プロシージャ、または匿名ブロックの範囲内で一意でなければなりません。
ステートメントにラベルを付けるには、次の構文を使用します。
<< label >> ステートメント
ステートメントは、プログラムがジャンプする実行ポイントです。
代入文、任意のSQL文( INSERTUPDATECREATEなど)および選択された手続き型言語文にラベルを付けることができます 。ラベル付けできる手続き言語ステートメントは次のとおりです。
IF
GET DIAGNOSTICSを
それに注意してください 出口がキーワードとみなされ、そしてラベルの名前として使用することはできません。
GOTO文は、条件付きブロックまたはサブブロックに制御移すことはできません 、条件付きブロックまたはサブブロックから制御移すことができます。
次の例では、従業員レコードに名前、職務内容、従業員雇用日が含まれていることを確認します。いずれかの情報が欠落している場合、 GOTOステートメントは、その実行ポイントを従業員が有効でないというメッセージを出力するステートメントに転送します。
CREATE OR REPLACE PROCEDURE verify_emp (
p_empno NUMBER
)
IS
v_ename emp.ename%TYPE;
v_job emp.job%TYPE;
v_hiredate emp.hiredate%TYPE;
BEGIN
SELECT ename, job, hiredate
INTO v_ename, v_job, v_hiredate FROM emp
WHERE empno = p_empno;
IF v_ename IS NULL THEN
GOTO invalid_emp;
END IF;
IF v_job IS NULL THEN
GOTO invalid_emp;
END IF;
IF v_hiredate IS NULL THEN
GOTO invalid_emp;
END IF;
DBMS_OUTPUT.PUT_LINE('Employee ' || p_empno ||
' validated without errors.');
RETURN;
<<invalid_emp>> DBMS_OUTPUT.PUT_LINE('Employee ' || p_empno ||
' is not a valid employee.');
END;
GOTOステートメントには次の制限があります。
GOTO文は、宣言にジャンプすることはできません。
GOTO文は、別の関数またはプロシージャに制御を転送することはできません。
ラベルは、ブロック、関数またはプロシージャの最後に配置されるべきではありません。
 
3.5.4 CASE式
CASE CASE式を式の中でどこにあるか置換されている値を返します
CASE式には、 検索された CASEと呼ばれるものとセレクタを使用するものの2つの形式があります
3.5.4.1 セレクタCASE式
セレクタ CASE 式は、セレクタと呼ばれる式を1つ以上の WHEN 句で 指定された式に一致させようとします result は、 CASE 式が使用さ れているコンテキストで型互換性のある 式です。一致が見つかると、対応する THEN 句に 指定された値 CASE によって返され ます。一致するものがなければ、 ELSEに 続く値 が返されます。 ELSEが 省略され た場合 、CASE はnullを返します。
CASE selector-expression
WHEN match-expression THEN
result
[ WHEN match-expression THEN
result
[ WHEN match-expression THEN
result ] ...]
[ ELSE
result ]
END;
match-expression は、 CASE 式の 中に現れる順に評価され ます。 result は、 CASE 式が使用さ れているコンテキストで型互換性のある 式です。 セレクタ式 等しい 最初の 一致式 見つかる と、対応する THEN 句の 結果 CASE 式の 値として返されます 一致式 のいずれも、 セレクタ式に 等しくない 場合 返される ELSE 以下 もたらします ELSE が指定されてい ない場合 CASE式はnullを戻します。
次の例では、セレクターの CASE式を使用して部門番号に基づいて部門名を変数に割り当てます。
DECLARE
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
v_deptno emp.deptno%TYPE;
v_dname dept.dname%TYPE;
CURSOR emp_cursor IS SELECT empno, ename, deptno FROM emp;
BEGIN
OPEN emp_cursor;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME DEPTNO DNAME');
DBMS_OUTPUT.PUT_LINE('----- ------- ------ ----------');
LOOP
FETCH emp_cursor INTO v_empno, v_ename, v_deptno;
EXIT WHEN emp_cursor%NOTFOUND;
v_dname :=
CASE v_deptno
WHEN 10 THEN 'Accounting'
WHEN 20 THEN 'Research'
WHEN 30 THEN 'Sales'
WHEN 40 THEN 'Operations'
ELSE 'unknown'
END;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || RPAD(v_ename, 10) ||
' ' || v_deptno || ' ' || v_dname);
END LOOP;
CLOSE emp_cursor;
END;
このプログラムの出力は次のとおりです。
EMPNO ENAME DEPTNO DNAME
----- ------- ------ ----------
7369 SMITH 20 Research
7499 ALLEN 30 Sales
7521 WARD 30 Sales
7566 JONES 20 Research
7654 MARTIN 30 Sales
7698 BLAKE 30 Sales
7782 CLARK 10 Accounting
7788 SCOTT 20 Research
7839 KING 10 Accounting
7844 TURNER 30 Sales
7876 ADAMS 20 Research
7900 JAMES 30 Sales
7902 FORD 20 Research
7934 MILLER 10 Accounting
3.5.4.2 検索されたCASE式
検索された CASE 式は、1つまたは複数のブール式を使用して、結果として返される値を決定します。
CASE WHEN boolean-expression THEN
result
[ WHEN boolean-expression THEN
result
[ WHEN boolean-expression THEN
result ] ...]
[ ELSE
result ]
END;
boolean-expression は、 CASE 式の 中に現れる順序で評価され ます。 result は、 CASE 式が使用さ れているコンテキストで型互換性のある 式です。最初の ブール式が と評価され、その検出され とき 対応する もたらす CASE の値として返されます boolean-expressionの どれもが 真でない場合、 ELSEに 続く 結果 が返されます。 ELSE が指定されてい ない場合 CASE式はnullを戻します。
次の例では、検索された CASE式を使用して部門番号に基づいて部門名を変数に割り当てます。
DECLARE
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
v_deptno emp.deptno%TYPE;
v_dname dept.dname%TYPE;
CURSOR emp_cursor IS SELECT empno, ename, deptno FROM emp;
BEGIN
OPEN emp_cursor;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME DEPTNO DNAME');
DBMS_OUTPUT.PUT_LINE('----- ------- ------ ----------');
LOOP
FETCH emp_cursor INTO v_empno, v_ename, v_deptno;
EXIT WHEN emp_cursor%NOTFOUND;
v_dname :=
CASE
WHEN v_deptno = 10 THEN 'Accounting'
WHEN v_deptno = 20 THEN 'Research'
WHEN v_deptno = 30 THEN 'Sales'
WHEN v_deptno = 40 THEN 'Operations'
ELSE 'unknown'
END;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || RPAD(v_ename, 10) ||
' ' || v_deptno || ' ' || v_dname);
END LOOP;
CLOSE emp_cursor;
END;
このプログラムの出力は次のとおりです。
EMPNO ENAME DEPTNO DNAME
----- ------- ------ ----------
7369 SMITH 20 Research
7499 ALLEN 30 Sales
7521 WARD 30 Sales
7566 JONES 20 Research
7654 MARTIN 30 Sales
7698 BLAKE 30 Sales
7782 CLARK 10 Accounting
7788 SCOTT 20 Research
7839 KING 10 Accounting
7844 TURNER 30 Sales
7876 ADAMS 20 Research
7900 JAMES 30 Sales
7902 FORD 20 Research
7934 MILLER 10 Accounting
 
3.5.5 CASEステートメント
CASE は、指定した検索条件が である1つ以上の文のセットを実行し ます。 先に述べた CASE式は式の一部として表示される必要がありながら、CASE文は、それ自体でスタンドアロンステートメントです
CASE文には、 検索された CASEと呼ばれる形式と セレクタを使用する形式の2つの形式があります
3.5.5.1 セレクタのCASE文
セレクタ CASE 文は、セレクタと呼ばれる式を1つ以上の WHEN 句で 指定された式に一致させようとします 。一致が見つかると、対応する1つまたは複数のステートメントが実行されます。
CASE selector-expression
WHEN match-expression THEN
statements
[ WHEN match-expression THEN
statements
[ WHEN match-expression THEN
statements ] ...]
[ ELSE
statements ]
END CASE;
selector-expression は、各 match-expression と型互換性のある値を返します match-expression は、 CASE 文の 中に現れる順に評価され ます。 ステートメント は1つ以上の SPL ステートメントで、それぞれがセミコロンで終了します。 セレクタ式 の値は、 最初の 一致式に 等しい 場合 対応する のステートメント(単数または複数)を 実行し、制御を エンドケースキーワード 以下継続されます 。一致するものがなければ、 ELSEに 続くステートメント が実行されます。一致するものがなく、 ELSEがない場合、例外がスローされます。
次の例では、セレクターの CASEステートメントを使用して、部署番号に基づいて部門名と場所を変数に割り当てます。
DECLARE
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
v_deptno emp.deptno%TYPE;
v_dname dept.dname%TYPE;
v_loc dept.loc%TYPE;
CURSOR emp_cursor IS SELECT empno, ename, deptno FROM emp;
BEGIN
OPEN emp_cursor;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME DEPTNO DNAME '
|| ' LOC');
DBMS_OUTPUT.PUT_LINE('----- ------- ------ ----------'
|| ' ---------');
LOOP
FETCH emp_cursor INTO v_empno, v_ename, v_deptno;
EXIT WHEN emp_cursor%NOTFOUND;
CASE v_deptno
WHEN 10 THEN v_dname := 'Accounting';
v_loc := 'New York';
WHEN 20 THEN v_dname := 'Research';
v_loc := 'Dallas';
WHEN 30 THEN v_dname := 'Sales';
v_loc := 'Chicago';
WHEN 40 THEN v_dname := 'Operations';
v_loc := 'Boston';
ELSE v_dname := 'unknown';
v_loc := '';
END CASE;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || RPAD(v_ename, 10) ||
' ' || v_deptno || ' ' || RPAD(v_dname, 14) || ' ' ||
v_loc);
END LOOP;
CLOSE emp_cursor;
END;
このプログラムの出力は次のとおりです。
EMPNO ENAME DEPTNO DNAME LOC
----- ------- ------ ---------- ---------
7369 SMITH 20 Research Dallas
7499 ALLEN 30 Sales Chicago
7521 WARD 30 Sales Chicago
7566 JONES 20 Research Dallas
7654 MARTIN 30 Sales Chicago
7698 BLAKE 30 Sales Chicago
7782 CLARK 10 Accounting New York
7788 SCOTT 20 Research Dallas
7839 KING 10 Accounting New York
7844 TURNER 30 Sales Chicago
7876 ADAMS 20 Research Dallas
7900 JAMES 30 Sales Chicago
7902 FORD 20 Research Dallas
7934 MILLER 10 Accounting New York
3.5.5.2 検索されたCASE文
検索された CASE ステートメントは、1つまたは複数のブール式を使用して、実行されるステートメントの結果セットを判別します。
CASE WHEN boolean-expression THEN
statements
[ WHEN boolean-expression THEN
statements
[ WHEN boolean-expression THEN
statements ] ...]
[ ELSE
statements ]
END CASE;
boolean-expression は、 CASE 文の 中に現れる順に評価され ます。 TRUE と評価される 最初の ブール式 検出されると 、対応する THEN の文 が実行され、制御は END CASE キーワードの 後に続きます boolean-expressionの どれも TRUE 評価され ない場合 ELSEに 続く文 が実行されます。 boolean-expressionの いずれも TRUE 評価され ず、 ELSEがない場合、例外がスローされます。
次の例では、検索された CASEステートメントを使用して、部署番号に基づいて部門名と場所を変数に割り当てます。
DECLARE
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
v_deptno emp.deptno%TYPE;
v_dname dept.dname%TYPE;
v_loc dept.loc%TYPE;
CURSOR emp_cursor IS SELECT empno, ename, deptno FROM emp;
BEGIN
OPEN emp_cursor;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME DEPTNO DNAME '
|| ' LOC');
DBMS_OUTPUT.PUT_LINE('----- ------- ------ ----------'
|| ' ---------');
LOOP
FETCH emp_cursor INTO v_empno, v_ename, v_deptno;
EXIT WHEN emp_cursor%NOTFOUND;
CASE
WHEN v_deptno = 10 THEN v_dname := 'Accounting';
v_loc := 'New York';
WHEN v_deptno = 20 THEN v_dname := 'Research';
v_loc := 'Dallas';
WHEN v_deptno = 30 THEN v_dname := 'Sales';
v_loc := 'Chicago';
WHEN v_deptno = 40 THEN v_dname := 'Operations';
v_loc := 'Boston';
ELSE v_dname := 'unknown';
v_loc := '';
END CASE;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || RPAD(v_ename, 10) ||
' ' || v_deptno || ' ' || RPAD(v_dname, 14) || ' ' ||
v_loc);
END LOOP;
CLOSE emp_cursor;
END;
このプログラムの出力は次のとおりです。
EMPNO ENAME DEPTNO DNAME LOC
----- ------- ------ ---------- ---------
7369 SMITH 20 Research Dallas
7499 ALLEN 30 Sales Chicago
7521 WARD 30 Sales Chicago
7566 JONES 20 Research Dallas
7654 MARTIN 30 Sales Chicago
7698 BLAKE 30 Sales Chicago
7782 CLARK 10 Accounting New York
7788 SCOTT 20 Research Dallas
7839 KING 10 Accounting New York
7844 TURNER 30 Sales Chicago
7876 ADAMS 20 Research Dallas
7900 JAMES 30 Sales Chicago
7902 FORD 20 Research Dallas
7934 MILLER 10 Accounting New York
 
3.5.6 ループ
LOOP、EXIT、CONTINUE、WHILE、および FOR 文は、 一連のコマンドを繰り返す あなたの SPL プログラム の手配をすることができます
3.5.6.1 ループ
LOOP
statements
END LOOP;
LOOP は、 EXIT または RETURN ステートメントで 終了するまで無期限に繰り返される無条件ループを定義します
3.5.6.2 EXIT
EXIT [ WHEN expression ];
最も内側のループが終了し、 END LOOPに 続くステートメントが次に実行されます。
場合存在する場合に、ループ出口が指定された条件がである場合にのみ発生し、そうでない場合はEXITの後のステートメントへのパスを制御します。
EXITを使用すると、すべてのタイプのループから早期に終了することができます。無条件ループでの使用に限定されません。
以下は、10回反復して終了するために EXITステートメントを使用するループの簡単な例です
DECLARE
v_counter NUMBER(2);
BEGIN
v_counter := 1;
LOOP
EXIT WHEN v_counter > 10;
DBMS_OUTPUT.PUT_LINE('Iteration # ' || v_counter);
v_counter := v_counter + 1;
END LOOP;
END;
このプログラムの出力は次のとおりです。
Iteration # 1
Iteration # 2
Iteration # 3
Iteration # 4
Iteration # 5
Iteration # 6
Iteration # 7
Iteration # 8
Iteration # 9
Iteration # 10
3.5.6.3は、 CONTINUE
CONTINUE文は、介在文をスキップして、ループの次の繰り返しを進めるための方法を提供します。
ときに CONTINUE文が検出され、最も内側のループの次の反復は、ループの最後までCONTINUE文を、次のすべてのステートメントをスキップし、開始されます。つまり、ループ制御式があれば制御が戻され、ループの本体が再評価されます。
場合 WHEN句が使用され、その後、ループの次の反復は、WHEN句で指定された式がと評価された場合にのみ開始されます。それ以外の場合は、 CONTINUEステートメントの次のステートメントに制御が渡されます。
CONTINUE文は、ループの外で使用することはできません。
以下は、 CONTINUEステートメントを使用して奇数の表示をスキップする前の例のバリエーションです
DECLARE
v_counter NUMBER(2);
BEGIN
v_counter := 0;
LOOP
v_counter := v_counter + 1;
EXIT WHEN v_counter > 10;
CONTINUE WHEN MOD(v_counter,2) = 1;
DBMS_OUTPUT.PUT_LINE('Iteration # ' || v_counter);
END LOOP;
END;
上記のプログラムの出力は次のとおりです。
Iteration # 2
Iteration # 4
Iteration # 6
Iteration # 8
Iteration # 10
3.5.6.4 WHILE
WHILE expression LOOP
statements
END LOOP;
WHILE文は条件式がTRUEに評価される一連の文を繰り返します。条件は、ループ本体への各エントリの直前でチェックされます。
ループを終了するタイミングを決定するためにEXITステートメントの代わりにWHILEステートメントを使用する点を除いて、前の例と同じロジックが次の例に含まれています。
注意: ループを終了するタイミングを決定する条件式を変更する必要があります。 EXIT は、その条件式が真のループを終了します。 WHILE ステートメント終了(または決してループを開始します)その条件式が偽のとき。
DECLARE
v_counter NUMBER(2);
BEGIN
v_counter := 1;
WHILE v_counter <= 10 LOOP
DBMS_OUTPUT.PUT_LINE('Iteration # ' || v_counter);
v_counter := v_counter + 1;
END LOOP;
END;
前の例と同じ結果がこの例で生成されます。
Iteration # 1
Iteration # 2
Iteration # 3
Iteration # 4
Iteration # 5
Iteration # 6
Iteration # 7
Iteration # 8
Iteration # 9
Iteration # 10
3.5.6.5 FOR(整数型)
FOR name IN [REVERSE] expression .. expression LOOP
statements
END LOOP;
FORの この形式は 、整数値の範囲を反復するループを作成します。変数 は自動的に INTEGER 型として定義され 、ループ内にのみ存在します。ループ範囲を与える2つの式は、ループに入るときに1回評価されます。反復ステップは1で、 名前は ... の左の の値で始まり 名前が .. の右側に の値を超える と終了し ます。したがって、2つの式は、 start-value .. end-valueという 役割を担い ます。
オプションの REVERSE句は、ループが逆の順序で繰り返されるように指定します。ループをはじめて実行するとき、 nameは最も右の式の値に設定されます。 名前が一番左のよりも小さい場合、ループは終了します。
次の例では 、1から10の繰り返しのFORループを使用することで WHILEループの例をさらに単純化しています。
BEGIN
FOR i IN 1 .. 10 LOOP
DBMS_OUTPUT.PUT_LINE('Iteration # ' || i);
END LOOP;
END;
FOR を使用した出力を以下に示します
Iteration # 1
Iteration # 2
Iteration # 3
Iteration # 4
Iteration # 5
Iteration # 6
Iteration # 7
Iteration # 8
Iteration # 9
Iteration # 10
開始値が終了値より大きい場合、ループ本体はまったく実行されません。次の例に示すように、エラーは発生しません。
BEGIN
FOR i IN 10 .. 1 LOOP
DBMS_OUTPUT.PUT_LINE('Iteration # ' || i);
END LOOP;
END;
ループ本体が実行されないので、この例からの出力はありません。
注: SPL CURSOR FOR ループ もサポートしてい ます 3.8.7 項を 参照 )。
 
 
 
 
3.5.7 例外処理
デフォルトでは、 SPL プログラムで 発生したエラー はプログラムの実行を中止します。 EXCEPTION セクションの ある BEGIN ブロックを 使用すると、エラーをトラップして回復することができ ます。構文は、 BEGIN ブロックの 通常の構文の拡張です
[ DECLARE
declarations ]
BEGIN
statements
EXCEPTION
WHEN condition [ OR condition ]... THEN
handler_statements
[ WHEN condition [ OR condition ]... THEN
handler_statements ]...
END;
エラーが発生しない場合、この形式のブロックは単にすべての ステートメントを 実行し、 ENDの 後の次のステートメントに制御を渡し ます。エラーが ステートメント 内で発生した場合 のさらなる処理が 放棄され、制御が 例外リスト に渡されます 。リストは 、発生したエラーと一致する 最初の 条件 が検索され ます。一致するものが見つかった場合は、対応する handler_statements が実行され、 ENDの 後の次のステートメントに制御が渡され ます。一致するものが見つからない場合、 EXCEPTION 句がまったく存在しない かのようにエラーが伝播し ます。 EXCEPTIONを使用 して囲みブロックでエラーを捕らえることができます 。囲みブロックがない場合は、そのサブプログラムの処理を中止します。
特殊条件名 OTHERSはすべてのエラー・タイプに一致します。条件名では大文字と小文字は区別されません。
選択した handler_statements 内で新しいエラーが発生した場合、このEXCEPTION句ではキャッチできませんが、伝播されます。周囲のEXCEPTION節がそれを捕まえることができます。
次の表は、使用できる条件名の一覧です。
表3-2例外条件名
アプリケーションで、 CASE 文の 中のどれもが TRUE 評価され ず、 ELSE 条件 が存在しない 状況が発生しました。
注意:条件名INVALID_NUMBERおよびVALUE_ERRORは、文字列を数値リテラルに変換できないことに起因する例外の条件名であるOracleデータベースとは互換性がありません。さらに、Oracleデータベースの場合、 INVALID_NUMBER例外はSQL文にのみ適用され、 VALUE_ERROR例外はプロシージャ文にのみ適用されます。
 
3.5.8 ユーザ定義の例外
プログラムの実行中に何らかのエラー(PL / SQLで 例外 と呼ばれる )が発生することがあります。例外がスローされると、プログラムの正常な実行が停止し、プログラムの制御がプログラムのエラー処理部分に移ります。 例外は、サーバーによって生成される事前定義されたエラーでも、ユーザー定義の例外を発生させる論理エラーでもかまいません。
ユーザー定義の例外はサーバーによって決して生成されません。それらは RAISEステートメントによって明示的に 呼び出されます。開発者定義の論理規則が壊れていると、ユーザー定義の例外が発生します。不十分な資金を有する口座に対して小切手が提示されると、論理規則の一般的な例が発生する。資金が不足している口座に対して小切手を現金化しようとすると、ユーザー定義の例外が発生します。
関数、プロシージャ、パッケージ、または匿名ブロックで例外を定義できます。同じブロック内で同じ例外を2回宣言することはできませんが、2つの異なるブロックで同じ例外を宣言できます。
ユーザー定義の例外を実装する前に、関数、プロシージャ、パッケージ、または匿名ブロックの宣言セクションで例外を宣言する必要があります。 RAISEを使用して例外を発生させることができます
宣言
exception_name EXCEPTION;
 
ベギン
...
RAISE exception_name ;
...
終わり;
exception_name例外の名前です。
未処理の例外は、呼び出しスタックを介して伝播します。例外が未処理のままである場合、例外は最終的にクライアントアプリケーションに報告されます。
ブロック内で宣言されたユーザ定義の例外は、そのブロックに対してローカルであり、ブロック内のネストされたブロックに対してグローバルであるとみなされます。外部ブロックにある例外を参照するには、外部ブロックにラベルを割り当てる必要があります。次に、例外の名前の前にブロック名を付けます。
ブロック _ 名前 例外 _ 名前
逆に、外側のブロックは、ネストされたブロックで宣言された例外を参照することはできません。
宣言のスコープは、パッケージで作成されない限り 宣言されているブロックに限定され、参照された場合はパッケージ名で修飾されます。たとえば、 inventory_controlという名前のパッケージにあるout_of_stockという例外を発生させるには、次のようなエラーが発生する必要があります。
inventory_control.out_of_stock
次の例は、パッケージ内のユーザー定義例外の宣言を示しています。ユーザ定義例外は 、例外と同じパッケージに存在するため check_balance 生成 されたときにパッケージ修飾子を必要としません
パッケージの作成または置換ar as
オーバーディング例外。
プロシージャcheck_balance(p_balance NUMBER、p_amount NUMBER);
終わり;
 
パッケージ本体の作成または交換
PROCEDURE check_balance(p_balance NUMBER、p_amount NUMBER)
IS
ベギン
IF(p_amount> p_balance)THEN
RAISE overdrawn;
END IF;
終わり;
 
次の手順( 購入 )でcheck_balanceプロシージャを呼び出します。 p_amountが p_balanceよりも大きい場合、CHECK_BALANCEは例外を発生させます。 購入ar.overdrawn例外をキャッチします。 購入は ARパッケージ内で定義されていないため、購入はパッケージ修飾名(ar.overdrawn)で例外を参照しなければなりません。
CReate PROCEDURE 購入 customerID int、 金額 NUMERIC)
として
ベギン
ar チェック _バランス getcustomerバランス customerid)、金額) ;
record_purchase(顧客ID、金額) ;
例外
WHEN THEN ar.overdrawn
raise_credit_limit(顧客ID、金額* 1.5) ;
終わり;
とき ar.check_balanceは 例外を発生させ、実行は 購入 で定義された例外ハンドラにジャンプ
例外
WHEN THEN ar.overdrawn
raise_credit_limit(顧客ID、金額* 1.5) ;
例外ハンドラは、顧客の与信限度額を引き上げて終了します。例外ハンドラが終了すると、 ar.check_balanceに 続く文で実行が再開されます
 
3.5.9 PRAGMA EXCEPTION_INIT
PRAGMA EXCEPTION_INITは 、ユーザー定義のエラーコードを例外に関連付けます。 PRAGMA EXCEPTION_INIT 宣言は、任意のブロック、サブブロックまたはパッケージに含まれていてもよいです。例外にのみエラーコードを割り当てることができます( PRAGMA EXCEPTION_INIT )を宣言します。 PRAGMA の形式 EXCEPTION_INIT 宣言は次のとおりです。
PRAGMA EXCEPTION_INIT( 例外 _ 名前
{ 例外 _ 番号|例外コード })
場所:
exception_name は、関連する例外の名前です。
exception_number 、プラグマに関連付けられ たユーザー定義のエラーコード です。 マップされていない exception_number を指定する と、サーバーは警告を返します。
exception_code は、事前定義された例外の名前です。有効な例外の完全なリストについては、以下にあるPostgresのコアドキュメントを参照してください
https://www.postgresql.org/docs/11/static/errcodes-appendix.html
前のセクション( ユーザー定義の例外 )に は、パッケージ内のユーザー定義の例外を明確にする ための例が含ま れていました。次の例では、同じ基本構造を使用しますが、 PRAGMA EXCEPTION_INIT 宣言 が追加されています
パッケージの作成または置換ar as
オーバーディング例外。
PRAGMA EXCEPTION_INIT(超過、-20100);
プロシージャcheck_balance(p_balance NUMBER、p_amount NUMBER);
終わり;
 
パッケージ本体の作成または交換
PROCEDURE check_balance(p_balance NUMBER、p_amount NUMBER)
IS
ベギン
IF(p_amount> p_balance)THEN
RAISE overdrawn;
END IF;
終わり;
 
次の手順( 購入 )でcheck_balanceプロシージャを呼び出します。 p_amountが p_balanceよりも大きい場合、CHECK_BALANCEは例外を発生させます。 購入ar.overdrawn例外をキャッチします。
CREATE PROCEDURE購入(customerID int、金額NUMERIC)
として
ベギン
ar.check_ balance getcustomerバランス顧客ID)、金額) ;
record_purchase(顧客ID、金額);
例外
いつ、
DBMS_OUTPUT.PUT_LINE( 'このアカウントは超過しています。 ');
DBMS_OUTPUT.PUT_LINE( 'SQLCode:' || SQLCODE || '' || SQLERRM);
終わり;
とき ar.check_balanceは 例外を発生させ、実行は 購入 で定義された例外ハンドラにジャンプします。
例外
いつ、
DBMS_OUTPUT.PUT_LINE( 'このアカウントは超過しています。');
DBMS_OUTPUT.PUT_LINE( 'SQLCode:' || SQLCODE || '' || SQLERRM);
例外ハンドラはエラーメッセージを返し、その後に SQLCODE 情報が 続き ます。
This account is overdrawn.
SQLCODE: -20100 User-Defined Exception
次の例は、事前定義された例外の使用方法を示しています。このコードは、 no_data_found例外の より意味のある名前を作成し ます 。指定された顧客が存在しない場合、コードは例外をキャッチし、 DBMS_OUTPUT.PUT_LINEを呼び出してエラーを報告し、元の例外を再発生させます。
パッケージの作成または置換ar as
オーバーディング例外。
PRAGMA EXCEPTION_INIT(unknown_customer、no_data_found);
プロシージャcheck_balance(p_customer_id NUMBER);
終わり;
 
パッケージ本体の作成または交換
PROCEDURE check_balance(p_customer_id NUMBER)
IS
宣言
v_バランスNUMBER;
ベギン
SELECT balance INTO v_balance FROM customer
どこcust_id = p_customer_id;
例外が未知の顧客の場合は例外THEN
DBMS_OUTPUT.PUT_LINE( '無効な顧客ID')。
上昇する。
終わり;
 
 
3.5.10 RAISE_APPLICATION_ERROR
プロシージャ RAISE_APPLICATION_ERROR を使用すると、開発者は SPL プログラム 内で意図的に処理を中止し 、例外を発生させることで呼び出すことができます。例外は、 3.5.7 項で説明したのと同じ方法で処理され ます。さらに、 RAISE_APPLICATION_ERROR プロシージャは、プログラムで使用可能なユーザー定義コードとエラー・メッセージを作成し、それを使用して例外を識別します。
RAISE_APPLICATION_ERROR( error_number , message );
場所:
error_number は、 プロシージャーの実行時に SQLCODE という名前の変数に戻される整数値または式です エラー番号は、-20000 -20999 の間の値でなければなりません
message は、 SQLERRM という名前の変数に戻される文字列リテラルまたは式です
詳細については SQLCODE SQLERRM 変数、のSec ション 参照 3.13を エラーとメッセージ
次の例では、 RAISE_APPLICATION_ERRORプロシージャを使用して 、従業員に欠落している情報に応じて異なるコードとメッセージを表示します。
CREATE OR REPLACE PROCEDURE verify_emp (
p_empno NUMBER
)
IS
v_ename emp.ename%TYPE;
v_job emp.job%TYPE;
v_mgr emp.mgr%TYPE;
v_hiredate emp.hiredate%TYPE;
BEGIN
SELECT ename, job, mgr, hiredate
INTO v_ename, v_job, v_mgr, v_hiredate FROM emp
WHERE empno = p_empno;
IF v_ename IS NULL THEN
RAISE_APPLICATION_ERROR(-20010, 'No name for ' || p_empno);
END IF;
IF v_job IS NULL THEN
RAISE_APPLICATION_ERROR(-20020, 'No job for' || p_empno);
END IF;
IF v_mgr IS NULL THEN
RAISE_APPLICATION_ERROR(-20030, 'No manager for ' || p_empno);
END IF;
IF v_hiredate IS NULL THEN
RAISE_APPLICATION_ERROR(-20040, 'No hire date for ' || p_empno);
END IF;
DBMS_OUTPUT.PUT_LINE('Employee ' || p_empno ||
' validated without errors');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
END;
従業員レコードにマネージャー番号がない場合の出力を次に示します。
EXEC verify_emp(7839);
 
SQLCODE: -20030
SQLERRM: EDB-20030: No manager for 7839
3.6 トランザクション制御
データベースへのすべての更新が正常に行われることが望まれる場合、またはエラーが発生した場合には何も起こらないことが望ましい場合があります。すべてが1つのユニットとして正常に実行されるか、まったく発生しないデータベース更新セットは、 トランザクション と呼ばれます
銀行業務における一般的な例は、2つの口座間の資金移動です。取引の2つの部分は、1つの口座からの資金の引き出しと、別の口座への資金の預金です。この取引の両方の部分が発生しなければ、銀行の本の残高がなくなります。預金と引き出しは1回の取引です。
次の条件が満たされている場合、Oracleデータベースと互換性のあるトランザクション制御スタイルを使用する SPLアプリケーションを作成できます。
edb_stmt_level_txパラメータTRUEに設定する必要があります。これにより、例外が発生した場合にBEGIN / ENDブロック内のすべてのデータベース更新を無条件にロールバックするアクションが防止されます。 edb_stmt_level_txパラメータの詳細は、第1.3.4項を参照してください。
トランザクションは、最初の SQLコマンドがSPLプログラムで検出されたときに開始され ます 。後続のすべてのSQLコマンドは、そのトランザクションの一部として組み込まれます。トランザクションは、次のいずれかが発生したときに終了します。
COMMITコマンドが検出された場合永久になるトランザクション中に行われたすべてのデータベースの更新の影響をインチ
ROLLBACKコマンドは、トランザクション中に行われたすべてのデータベースの更新の効果はロールバックされ、トランザクションが中止された場合に発生します。新しいSQLコマンドが検出されると、新しいトランザクションが開始されます。
制御は呼び出し元のアプリケーション(Java、 PSQLなど)に戻ります 。この場合、トランザクションがPRAGMA AUTONOMOUS_TRANSACTIONが宣言されているブロック内にある場合を除いて、トランザクションがコミットまたはロールバックされるかどうかがアプリケーションのアクションによって判断されますトランザクションのコミットメントまたはロールバックは呼び出しプログラムとは独立して行われます。
注意: Oracleと異なり、 CREATE TABLEなどのDDLコマンドは、自分のトランザクション内で暗黙的に発生しません。したがって、 DDLコマンドはOracleの場合のように即時データベースコミットを自動的には引き起こさず、 DMLコマンドのようにDDLコマンドをロールバックすることができます。
トランザクションは、1つ以上の BEGIN / ENDブロックにまたがることができ、1つのBEGIN / ENDブロックには1つ以上のトランザクションを含めることができます。
以降のセクションでは、 COMMITコマンドとROLLBACKコマンドについて詳しく説明します。
3.6.1 COMMIT
COMMITコマンドは、永久的な現在のトランザクション中に行われたすべてのデータベースの更新を行い、現在のトランザクションを終了します。
COMMIT [ WORK ];
COMMITコマンドは、匿名ブロック、ストアドプロシージャ、または関数内で使用することができます。 SPLプログラム内では、実行可能セクションおよび/または例外セクションに表示されることがあります。
次の例では 、匿名ブロックの3番目の INSERTコマンドがエラーになります。最初の2つのINSERTコマンドの効果は、最初のSELECTコマンドのように保持されます。 ROLLBACKコマンドを発行した後でも、2つの行は、実際にコミットされたことを確認する2番目のSELECTコマンドに示されているように、テーブルに残ります。
注意:次の例に示すedb_stmt_level_tx設定パラメータは、 ALTER DATABASEコマンドを使用してデータベース全体に対して設定することも、 postgresql.confファイルでデータベースサーバ全体を設定することもできます。
\set AUTOCOMMIT off
SET edb_stmt_level_tx TO on;
 
BEGIN
INSERT INTO dept VALUES (50, 'FINANCE', 'DALLAS');
INSERT INTO dept VALUES (60, 'MARKETING', 'CHICAGO');
COMMIT;
INSERT INTO dept VALUES (70, 'HUMAN RESOURCES', 'CHICAGO');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
END;
 
SQLERRM: value too long for type character varying(14)
SQLCODE: 22001
 
SELECT * FROM dept;
 
deptno | dname | loc
--------+------------+----------
10 | ACCOUNTING | NEW YORK
20 | RESEARCH | DALLAS
30 | SALES | CHICAGO
40 | OPERATIONS | BOSTON
50 | FINANCE | DALLAS
60 | MARKETING | CHICAGO
(6 rows)
 
ROLLBACK;
 
SELECT * FROM dept;
 
deptno | dname | loc
--------+------------+----------
10 | ACCOUNTING | NEW YORK
20 | RESEARCH | DALLAS
30 | SALES | CHICAGO
40 | OPERATIONS | BOSTON
50 | FINANCE | DALLAS
60 | MARKETING | CHICAGO
(6 rows)
3.6.2ロールバック
ROLLBACKコマンドは、現在のトランザクション中に行われたすべてのデータベース更新を元に戻して、現在のトランザクションを終了します。
ROLLBACK [ WORK ];
ROLLBACKコマンドは、匿名ブロック、ストアドプロシージャ、または関数内で使用することができます。 SPLプログラム内では、実行可能セクションおよび/または例外セクションに表示されることがあります。
次の例では、例外セクションに ROLLBACKコマンドが含まれてい ます 。最初の2つのINSERTコマンドが正常に実行されたにもかかわらず、3番目の例外の結果、匿名ブロック内のすべてのINSERTコマンドのロールバックが発生します。
\set AUTOCOMMIT off
SET edb_stmt_level_tx TO on;
 
BEGIN
INSERT INTO dept VALUES (50, 'FINANCE', 'DALLAS');
INSERT INTO dept VALUES (60, 'MARKETING', 'CHICAGO');
INSERT INTO dept VALUES (70, 'HUMAN RESOURCES', 'CHICAGO');
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
END;
 
SQLERRM: value too long for type character varying(14)
SQLCODE: 22001
 
SELECT * FROM dept;
 
deptno | dname | loc
--------+------------+----------
10 | ACCOUNTING | NEW YORK
20 | RESEARCH | DALLAS
30 | SALES | CHICAGO
40 | OPERATIONS | BOSTON
(4 rows)
以下は、 COMMITROLLBACKの 両方を使用するより複雑な例 です 。まず、新しい従業員を挿入する次のストアドプロシージャが作成されます。
\set AUTOCOMMIT off
SET edb_stmt_level_tx TO on;
 
CREATE OR REPLACE PROCEDURE emp_insert (
p_empno IN emp.empno%TYPE,
p_ename IN emp.ename%TYPE,
p_job IN emp.job%TYPE,
p_mgr IN emp.mgr%TYPE,
p_hiredate IN emp.hiredate%TYPE,
p_sal IN emp.sal%TYPE,
p_comm IN emp.comm%TYPE,
p_deptno IN emp.deptno%TYPE
)
IS
BEGIN
INSERT INTO emp VALUES (
p_empno,
p_ename,
p_job,
p_mgr,
p_hiredate,
p_sal,
p_comm,
p_deptno);
 
DBMS_OUTPUT.PUT_LINE('Added employee...');
DBMS_OUTPUT.PUT_LINE('Employee # : ' || p_empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || p_ename);
DBMS_OUTPUT.PUT_LINE('Job : ' || p_job);
DBMS_OUTPUT.PUT_LINE('Manager : ' || p_mgr);
DBMS_OUTPUT.PUT_LINE('Hire Date : ' || p_hiredate);
DBMS_OUTPUT.PUT_LINE('Salary : ' || p_sal);
DBMS_OUTPUT.PUT_LINE('Commission : ' || p_comm);
DBMS_OUTPUT.PUT_LINE('Dept # : ' || p_deptno);
DBMS_OUTPUT.PUT_LINE('----------------------');
END;
このプロシージャには例外セクションがないため、発生する可能性のあるエラーは呼び出し側プログラムに伝播されます。
次の匿名ブロックが実行されます。 emp_insertプロシージャーと例外セクションのROLLBACKコマンドをすべて呼び出した後にCOMMITコマンドを使用することに注意してください
BEGIN
emp_insert(9601,'FARRELL','ANALYST',7902,'03-MAR-08',5000,NULL,40);
emp_insert(9602,'TYLER','ANALYST',7900,'25-JAN-08',4800,NULL,40);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('An error occurred - roll back inserts');
ROLLBACK;
END;
 
Added employee...
Employee # : 9601
Name : FARRELL
Job : ANALYST
Manager : 7902
Hire Date : 03-MAR-08 00:00:00
Salary : 5000
Commission :
Dept # : 40
----------------------
Added employee...
Employee # : 9602
Name : TYLER
Job : ANALYST
Manager : 7900
Hire Date : 25-JAN-08 00:00:00
Salary : 4800
Commission :
Dept # : 40
----------------------
次の SELECTコマンドは、FarrellとTylerの従業員が正常に追加されたことを示しています。
SELECT * FROM emp WHERE empno > 9600;
 
empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+---------+---------+------+--------------------+---------+------+--------
9601 | FARRELL | ANALYST | 7902 | 03-MAR-08 00:00:00 | 5000.00 | | 40
9602 | TYLER | ANALYST | 7900 | 25-JAN-08 00:00:00 | 4800.00 | | 40
(2 rows)
次に、次の匿名ブロックを実行します。
BEGIN
emp_insert(9603,'HARRISON','SALESMAN',7902,'13-DEC-07',5000,3000,20);
emp_insert(9604,'JARVIS','SALESMAN',7902,'05-MAY-08',4800,4100,11);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('An error occurred - roll back inserts');
ROLLBACK;
END;
 
Added employee...
Employee # : 9603
Name : HARRISON
Job : SALESMAN
Manager : 7902
Hire Date : 13-DEC-07 00:00:00
Salary : 5000
Commission : 3000
Dept # : 20
----------------------
SQLERRM: insert or update on table "emp" violates foreign key constraint "emp_ref_dept_fk"
An error occurred - roll back inserts
テーブルに対して実行SELECTコマンドでは、次のように得られます。
SELECT * FROM emp WHERE empno > 9600;
 
empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+---------+---------+------+--------------------+---------+------+--------
9601 | FARRELL | ANALYST | 7902 | 03-MAR-08 00:00:00 | 5000.00 | | 40
9602 | TYLER | ANALYST | 7900 | 25-JAN-08 00:00:00 | 4800.00 | | 40
(2 rows)
例外セクション ROLLBACKコマンドは、従業員Harrisonの挿入を正常に取り消します。また、ファレル(Farrell)とタイラー(Tyler)の従業員は、最初の匿名ブロックのCOMMITコマンドによってその挿入が永続化されているため、テーブルに残っていることにも注意してください。
注意: plpgsqlプロシージャでCOMMITまたはROLLBACKを実行すると、ランタイム・スタックにOracleスタイルのSPLプロシージャがある場合はエラーがスローされます。
3.6.3 PRAGMA AUTONOMOUS_TRANSACTION
SPLプログラムは、SPLブロックの宣言セクションで次の指令を指定することによって、自律型トランザクションとして宣言できます。
PRAGMA AUTONOMOUS_TRANSACTION;
自律型トランザクションは、呼び出しプログラムによって開始される独立したトランザクションです。自律型トランザクション内のSQLコマンドのコミットまたはロールバックは、呼び出し側プログラムのトランザクションでのコミットまたはロールバックには影響しません。呼び出し元プログラムのコミットまたはロールバックは、自律型トランザクションのSQLコマンドのコミットまたはロールバックには影響しません。
次のSPLプログラムには、 PRAGMA AUTONOMOUS_TRANSACTION が含まれます
自律型トランザクションに関連する問題と制限事項は次のとおりです。
各自律型トランザクションは、進行中の間、接続スロットを消費します。場合によっては、 postgresql.confファイルのmax_connectionsパラメータを上げる必要があるかもしれません。
ほとんどの点で、自律型トランザクションは完全に別々のセッションであるかのように動作しますが、GUC(つまり SET で設定された設定 )は意図的な例外です。自律型トランザクションは周囲の値を吸収し、外部トランザクションにコミットする値を伝播できます。
次の一連の例は、自律型トランザクションの使用方法を示しています。この最初の一連のシナリオは、自律型トランザクションがない場合のデフォルトの動作を示しています。
各シナリオの前に、 deptテーブルは次の初期値にリセットされます。
SELECT * FROM dept;
 
deptno | dname | loc
--------+------------+----------
10 | ACCOUNTING | NEW YORK
20 | RESEARCH | DALLAS
30 | SALES | CHICAGO
40 | OPERATIONS | BOSTON
(4 rows)
シナリオ1a - 最終的なCOMMITのみの自律型トランザクションはありません。
この最初の一連のシナリオでは、トランザクションの最初の BEGINコマンドの直後 、開始トランザクション内の匿名ブロック内から、最後に匿名ブロック内から実行されるストアドプロシージャから3行の挿入が示されます。
ストアドプロシージャは次のとおりです。
CREATE OR REPLACE PROCEDURE insert_dept_70 IS
BEGIN
INSERT INTO dept VALUES (70,'MARKETING','LOS ANGELES');
END;
PSQLセッションは次のとおりです。
BEGIN;
INSERT INTO dept VALUES (50,'HR','DENVER');
BEGIN
INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
insert_dept_70;
END;
COMMIT;
最後のコミットの後、3つの行がすべて挿入されます。
SELECT * FROM dept ORDER BY 1;
 
deptno | dname | loc
--------+------------+-------------
10 | ACCOUNTING | NEW YORK
20 | RESEARCH | DALLAS
30 | SALES | CHICAGO
40 | OPERATIONS | BOSTON
50 | HR | DENVER
60 | FINANCE | CHICAGO
70 | MARKETING | LOS ANGELES
(7 rows)
シナリオ1b - 自律型トランザクションはありませんが、最終的なROLLBACK
次のシナリオでは、すべての挿入後の最後の ROLLBACKコマンドは、3つの挿入すべてのロールバックになります。
BEGIN;
INSERT INTO dept VALUES (50,'HR','DENVER');
BEGIN
INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
insert_dept_70;
END;
ROLLBACK;
 
SELECT * FROM dept ORDER BY 1;
 
deptno | dname | loc
--------+------------+----------
10 | ACCOUNTING | NEW YORK
20 | RESEARCH | DALLAS
30 | SALES | CHICAGO
40 | OPERATIONS | BOSTON
(4 rows)
シナリオ1c - 自律型トランザクションはありませんが、無名ブロックROLLBACK
匿名ブロックの最後に与えられ ROLLBACKコマンドは、以前の3つの挿入もすべて削除します。
BEGIN;
INSERT INTO dept VALUES (50,'HR','DENVER');
BEGIN
INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
insert_dept_70;
ROLLBACK;
END;
COMMIT;
 
SELECT * FROM dept ORDER BY 1;
 
deptno | dname | loc
--------+------------+----------
10 | ACCOUNTING | NEW YORK
20 | RESEARCH | DALLAS
30 | SALES | CHICAGO
40 | OPERATIONS | BOSTON
(4 rows)
この次のシナリオは、さまざまな場所 PRAGMA AUTONOMOUS_TRANSACTION を使用して自律型トランザクションを使用した場合の影響を示しています。
シナリオ2a - COMMITによる無名ブロックの自律的トランザクション
プロシージャは最初に作成されたままです。
CREATE OR REPLACE PROCEDURE insert_dept_70 IS
BEGIN
INSERT INTO dept VALUES (70,'MARKETING','LOS ANGELES');
END;
今、 PRAGMA AUTONOMOUS_TRANSACTIONは、匿名ブロックとともに、匿名ブロックの最後にあるCOMMITコマンドとともに与えられます。
BEGIN;
INSERT INTO dept VALUES (50,'HR','DENVER');
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
insert_dept_70;
COMMIT;
END;
ROLLBACK;
トランザクションの終了時にROLLBACKの 後、トランザクションの最初の行の挿入だけが破棄されます。 PRAGMA AUTONOMOUS_TRANSACTIONを持つ無名ブロック内の他の2行の挿入は、独立してコミットされています。
SELECT * FROM dept ORDER BY 1;
 
deptno | dname | loc
--------+------------+-------------
10 | ACCOUNTING | NEW YORK
20 | RESEARCH | DALLAS
30 | SALES | CHICAGO
40 | OPERATIONS | BOSTON
60 | FINANCE | CHICAGO
70 | MARKETING | LOS ANGELES
(6 rows)
シナリオ2b - ROLLBACKによるプロシージャーを含むCOMMITを使用した自律型トランザクション無名ブロック(自律型トランザクション・プロシージャーではありません)
さて、プロシージャーの最後に ROLLBACKコマンドがあり ます 。ただし、 PRAGMA ANONYMOUS_TRANSACTIONはこの手順に含まれていないことに注意してください。
CREATE OR REPLACE PROCEDURE insert_dept_70 IS
BEGIN
INSERT INTO dept VALUES (70,'MARKETING','LOS ANGELES');
ROLLBACK;
END;
プロシージャ内のロールバックでは、無名ブロック内の最後のCOMMITコマンドの前に無名ブロック( deptno 60および70) 内に挿入された2行が削除されます
BEGIN;
INSERT INTO dept VALUES (50,'HR','DENVER');
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
insert_dept_70;
COMMIT;
END;
COMMIT;
トランザクション終了時の最後のコミットの後、挿入される行はトランザクションの最初の行だけです。匿名ブロックは自律型トランザクションなので、囲まれたプロシージャ内のロールバックは、匿名ブロックが実行される前に発生する挿入には影響しません。
SELECT * FROM dept ORDER by 1;
 
deptno | dname | loc
--------+------------+----------
10 | ACCOUNTING | NEW YORK
20 | RESEARCH | DALLAS
30 | SALES | CHICAGO
40 | OPERATIONS | BOSTON
50 | HR | DENVER
(5 rows)
シナリオ2c - COMMITを使用した自律型トランザクション匿名ブロック(自律型トランザクションプロシージャでもあるROLLBACKプロシージャを含む)
現在、最後にROLLBACKコマンドを使用するプロシージャには、 PRAGMA ANONYMOUS_TRANSACTIONが含まれています。これにより、プロシージャー内のROLLBACKコマンドの効果が分離されます。
CREATE OR REPLACE PROCEDURE insert_dept_70 IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO dept VALUES (70,'MARKETING','LOS ANGELES');
ROLLBACK;
END;
プロシージャ内でロールバックすると、プロシージャによって挿入された行は削除されますが、無名ブロック内に挿入された行は削除されません。
BEGIN;
INSERT INTO dept VALUES (50,'HR','DENVER');
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
insert_dept_70;
COMMIT;
END;
COMMIT;
トランザクションの最後に最後のコミットが行われた後、挿入された行は、トランザクションの開始からの最初の行と、匿名ブロックの先頭に挿入された行です。ロールバックされるのはプロシージャ内の挿入だけです。
SELECT * FROM dept ORDER by 1;
 
deptno | dname | loc
--------+------------+----------
10 | ACCOUNTING | NEW YORK
20 | RESEARCH | DALLAS
30 | SALES | CHICAGO
40 | OPERATIONS | BOSTON
50 | HR | DENVER
60 | FINANCE | CHICAGO
(6 rows)
以下のセクションでは 、他のいくつかのSPLプログラムタイプ PRAGMA AUTONOMOUS_TRANSACTIONの 例を示します。
自律的トランザクショントリガー
次の例は、 PRAGMA AUTONOMOUS_TRANSACTION を使用してトリガを宣言した場合の影響を示しています
次の表は、 empへの変更を記録するために作成されたものです。
CREATE TABLE empauditlog (
audit_date DATE,
audit_user VARCHAR2(20),
audit_desc VARCHAR2(20)
);
これらの変更をempauditlog表に挿入する emp表に添付されたトリガーは、次のとおりです。 PRAGMA AUTONOMOUS_TRANSACTIONを宣言セクションにインクルードすることに注意してください。
CREATE OR REPLACE TRIGGER emp_audit_trig
AFTER INSERT OR UPDATE OR DELETE ON emp
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
v_action VARCHAR2(20);
BEGIN
IF INSERTING THEN
v_action := 'Added employee(s)';
ELSIF UPDATING THEN
v_action := 'Updated employee(s)';
ELSIF DELETING THEN
v_action := 'Deleted employee(s)';
END IF;
INSERT INTO empauditlog VALUES (SYSDATE, USER,
v_action);
END;
BEGINコマンドで開始されたトランザクション内で、 次の2つの挿入が empテーブルに作成されます。
BEGIN;
INSERT INTO emp VALUES (9001,'SMITH','ANALYST',7782,SYSDATE,NULL,NULL,10);
INSERT INTO emp VALUES (9002,'JONES','CLERK',7782,SYSDATE,NULL,NULL,10);
以下は、 empの2つの新しい行と、 empauditlog表の2つの項目を示しています。
SELECT * FROM emp WHERE empno > 9000;
 
empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+-------+---------+------+--------------------+-----+------+--------
9001 | SMITH | ANALYST | 7782 | 23-AUG-18 07:12:27 | | | 10
9002 | JONES | CLERK | 7782 | 23-AUG-18 07:12:27 | | | 10
(2 rows)
 
SELECT TO_CHAR(AUDIT_DATE,'DD-MON-YY HH24:MI:SS') AS "audit date",
audit_user, audit_desc FROM empauditlog ORDER BY 1 ASC;
 
audit date | audit_user | audit_desc
--------------------+--------------+-------------------
23-AUG-18 07:12:27 | enterprisedb | Added employee(s)
23-AUG-18 07:12:27 | enterprisedb | Added employee(s)
(2 rows)
しかし、このセッション中にROLLBACKコマンドが与えられますemp表には2つの行が含まれなくなりましたが、 empauditlog表にはトリガーが暗黙的にコミットを実行し、 PRAGMA AUTONOMOUS_TRANSACTIONが呼び出しトランザクションで指定されたロールバックから独立して変更をコミットするため、
ROLLBACK;
 
SELECT * FROM emp WHERE empno > 9000;
 
empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+-------+-----+-----+----------+-----+------+--------
(0 rows)
 
SELECT TO_CHAR(AUDIT_DATE,'DD-MON-YY HH24:MI:SS') AS "audit date",
audit_user, audit_desc FROM empauditlog ORDER BY 1 ASC;
 
audit date | audit_user | audit_desc
--------------------+--------------+-------------------
23-AUG-18 07:12:27 | enterprisedb | Added employee(s)
23-AUG-18 07:12:27 | enterprisedb | Added employee(s)
(2 rows)
自律型トランザクションオブジェクト型メソッド
次の例は、 PRAGMA AUTONOMOUS_TRANSACTION を使用してオブジェクト・メソッドを宣言した場合の影響を示しています
次のオブジェクトタイプおよびオブジェクトタイプの本文が登録されます。オブジェクト型本体内のメンバー・プロシージャには、 PRAGMA AUTONOMOUS_TRANSACTIONが宣言セクションに含まれ 、プロシージャの最後にCOMMITがあります。
CREATE OR REPLACE TYPE insert_dept_typ AS OBJECT (
deptno NUMBER(2),
dname VARCHAR2(14),
loc VARCHAR2(13),
MEMBER PROCEDURE insert_dept
);
 
CREATE OR REPLACE TYPE BODY insert_dept_typ AS
MEMBER PROCEDURE insert_dept
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO dept VALUES (SELF.deptno,SELF.dname,SELF.loc);
COMMIT;
END;
END;
次の無名ブロックでは、オブジェクトのinsert_deptメソッドが呼び出され、無名ブロックにROLLBACKコマンドで終わる挿入が deptテーブルに挿入されます。
BEGIN;
DECLARE
v_dept INSERT_DEPT_TYP :=
insert_dept_typ(60,'FINANCE','CHICAGO');
BEGIN
INSERT INTO dept VALUES (50,'HR','DENVER');
v_dept.insert_dept;
ROLLBACK;
END;
insert_deptは自律型トランザクションとして宣言されているため 、部門番号60の挿入はテーブルに残りますが、ロールバックで部門50の挿入が削除されます。
SELECT * FROM dept ORDER BY 1;
 
deptno | dname | loc
--------+------------+----------
10 | ACCOUNTING | NEW YORK
20 | RESEARCH | DALLAS
30 | SALES | CHICAGO
40 | OPERATIONS | BOSTON
60 | FINANCE | CHICAGO
(5 rows)
3.7 動的SQL
動的SQLは、コマンドが実行されるまで知られていないSQLコマンドを実行する機能を提供するテクニックです。これまでは、 SPLプログラムで示したSQLコマンドは静的SQLでした。プログラム以外の完全なコマンド(変数を除く)をプログラムに組み込んでおく必要があります。したがって、動的SQLを使用すると、実行されたSQLはプログラム実行時に変更される可能性があります。
さらに、動的 SQLは、 CREATE TABLEなどのデータ定義コマンドをSPLプログラム内から実行できる唯一の方法です。
ただし、動的 SQLの 実行時パフォーマンスは静的SQLよりも遅くなります
EXECUTE IMMEDIATEコマンドが動的SQLコマンドを実行するために使用されます。
EXECUTE IMMEDIATE ' sql_expression ;'
[ INTO { variable [, ...] | record } ]
[ USING expression [, ...] ]
sql_expression は、 動的に実行される SQL コマンドを 含む文字列式 です。 変数 は、 sql_expressionで SQL コマンド を実行した結果として作成された 、通常は SELECT コマンド の結果セットの出力を受け取り ます 。変数の数、順序、およびタイプは、数値、順序と一致し、結果セットのフィールドと型互換性がなければなりません。あるいは、レコードのフィールドが数値、順序と一致し、結果セットと型互換性がある限り、レコードを指定することができます。 INTO を使用する場合 は、結果セットに1行だけを返す必要があります。それ以外の場合は例外が発生します。 USING を使用すると expression の値が プレースホルダに 渡され ます。プレースホルダは、 sql_expression のSQLコマンド内に埋め込まれているように見え ますが、変数は使用できます。 名前 - :()接頭辞 プレースホルダは、コロンと識別子が付されています 。評価式の数、順序、および結果のデータ型は、数値と順序が一致し、 sql_expression のプレースホルダと型互換性がなければなりません 。プレースホルダは SPL プログラムの どこにでも宣言されていないことに注意してください これらは sql_expression にのみ表示され ます
次の例は、基本的な動的 SQLコマンドを文字列リテラルとして示しています。
DECLARE
v_sql VARCHAR2(50);
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE job (jobno NUMBER(3),' ||
' jname VARCHAR2(9))';
v_sql := 'INSERT INTO job VALUES (100, ''ANALYST'')';
EXECUTE IMMEDIATE v_sql;
v_sql := 'INSERT INTO job VALUES (200, ''CLERK'')';
EXECUTE IMMEDIATE v_sql;
END;
次の例は、 SQL文字列のプレースホルダに値を渡すUSING句を示しています。
DECLARE
v_sql VARCHAR2(50) := 'INSERT INTO job VALUES ' ||
'(:p_jobno, :p_jname)';
v_jobno job.jobno%TYPE;
v_jname job.jname%TYPE;
BEGIN
v_jobno := 300;
v_jname := 'MANAGER';
EXECUTE IMMEDIATE v_sql USING v_jobno, v_jname;
v_jobno := 400;
v_jname := 'SALESMAN';
EXECUTE IMMEDIATE v_sql USING v_jobno, v_jname;
v_jobno := 500;
v_jname := 'PRESIDENT';
EXECUTE IMMEDIATE v_sql USING v_jobno, v_jname;
END;
次の例は、 INTO句とUSING句の両方を示しています。 SELECTコマンドを最後に実行すると、結果が個々の変数ではなくレコードに返されることに注意してください。
DECLARE
v_sql VARCHAR2(60);
v_jobno job.jobno%TYPE;
v_jname job.jname%TYPE;
r_job job%ROWTYPE;
BEGIN
DBMS_OUTPUT.PUT_LINE('JOBNO JNAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
v_sql := 'SELECT jobno, jname FROM job WHERE jobno = :p_jobno';
EXECUTE IMMEDIATE v_sql INTO v_jobno, v_jname USING 100;
DBMS_OUTPUT.PUT_LINE(v_jobno || ' ' || v_jname);
EXECUTE IMMEDIATE v_sql INTO v_jobno, v_jname USING 200;
DBMS_OUTPUT.PUT_LINE(v_jobno || ' ' || v_jname);
EXECUTE IMMEDIATE v_sql INTO v_jobno, v_jname USING 300;
DBMS_OUTPUT.PUT_LINE(v_jobno || ' ' || v_jname);
EXECUTE IMMEDIATE v_sql INTO v_jobno, v_jname USING 400;
DBMS_OUTPUT.PUT_LINE(v_jobno || ' ' || v_jname);
EXECUTE IMMEDIATE v_sql INTO r_job USING 500;
DBMS_OUTPUT.PUT_LINE(r_job.jobno || ' ' || r_job.jname);
END;
前の無名ブロックからの出力は次のとおりです。
JOBNO JNAME
----- -------
100 ANALYST
200 CLERK
300 MANAGER
400 SALESMAN
500 PRESIDENT
BULK COLLECT句を使用するとEXECUTE IMMEDIATE文の結果セットを名前付きコレクションにアセンブルできます 。セクションを参照してください。 3.12.4を 、BULK COLLECT 使用方法については 、COLLECT IMMEDIATE BULKを実行します。
3.8 静的カーソル
クエリ全体を一度に実行するのではなく 、クエリをカプセル化 した カーソル を設定し、一度に 1行ずつクエリ結果セットを読み取ることができます。これにより、結果セットから行を取り出し、その行のデータを処理し、次の行を取り出してプロセスを繰り返すSPLプログラム・ロジックを作成できます。
カーソルは、 FORまたはWHILEループのコンテキストで最も頻繁に使用されます。プログラムがループを終了できるように結果セットの終わりに達したことを検出する条件付きテストをSPLロジックに組み込む必要があります。
3.8.1 カーソルの宣言
カーソルを使用するには、最初に SPL プログラムの 宣言セクションで宣言する必要があります 。カーソル宣言は次のように表示されます。
CURSOR name IS query ;
name は、カーソルとその結果セットを後でプログラムで参照するために使用される識別子です。 クエリ SQLです カーソルによって検索可能な結果セットを決定するSELECTコマンド。
注意:この構文を拡張すると、パラメータを使用できます。これについては3.8.8節で詳しく説明します。
カーソル宣言の例を次に示します。
CREATE OR REPLACE PROCEDURE cursor_example
IS
CURSOR emp_cur_1 IS SELECT * FROM emp;
CURSOR emp_cur_2 IS SELECT empno, ename FROM emp;
CURSOR emp_cur_3 IS SELECT empno, ename FROM emp WHERE deptno = 10
ORDER BY empno;
BEGIN
...
END;
3.8.2 カーソルを開く
行を取り出すためにカーソルを使用する前に、カーソルを最初に開く必要があります。これは、 OPEN ステートメントで実行されます。
OPEN name ;
name は、 SPL プログラムの 宣言セクションで以前に宣言されたカーソルの識別子です OPEN文は、既にされているカーソル上で実行され、まだ開いてはいけません。
以下に 、対応するカーソル宣言を伴うOPENステートメントを示します。
CREATE OR REPLACE PROCEDURE cursor_example
IS
CURSOR emp_cur_3 IS SELECT empno, ename FROM emp WHERE deptno = 10
ORDER BY empno;
BEGIN
OPEN emp_cur_3;
...
END;
3.8.3 カーソルから行をフェッチする
カーソルがオープンされると、 FETCH を使用してカーソルの結果セットから行を取り出すことができます
FETCH name INTO { record | variable [ , variable_2 ]... };
name は、以前に開いたカーソルの識別子です。 record は、以前に定義されたレコードの識別子です(たとえば、 テーブル %ROWTYPEを使用 )。 変数 variable_2 ...は 、フェッチされた行からフィールドデータを受け取る SPL 変数です。 レコード または 変数 、variable_2 ... のフィールドは、 数と順序に一致している必要があり、各フィールドは、 カーソル宣言で与えられたクエリの SELECT リスト 内に返されました SELECT リスト 内のフィールドのデータ型が 一致し、または レコード 内のフィールド または 変数 のデータ型 、variable_2 のデータ型に暗黙的に変換可能である必要があります ...
注:一度に複数の行をコレクションに戻すことができるBULK COLLECT節を使用すると、 FETCH INTOのバリエーションがあります。 FETCH INTO文でBULK COLLECT句を使用する方法の詳細は、第3.12.4項を参照してください。
FETCHは次のとおりです。
CREATE OR REPLACE PROCEDURE cursor_example
IS
v_empno NUMBER(4);
v_ename VARCHAR2(10);
CURSOR emp_cur_3 IS SELECT empno, ename FROM emp WHERE deptno = 10
ORDER BY empno;
BEGIN
OPEN emp_cur_3;
FETCH emp_cur_3 INTO v_empno, v_ename;
...
END;
ターゲット変数のデータ型を明示的に宣言する代わりに、代わりに %TYPE を使用できます。このように、データベース列のデータ型が変更された場合、 SPL プログラム 内のターゲット変数の宣言を 変更する必要はありません。 %TYPE は、指定された列の新しいデータ型を自動的に選択します。
CREATE OR REPLACE PROCEDURE cursor_example
IS
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
CURSOR emp_cur_3 IS SELECT empno, ename FROM emp WHERE deptno = 10
ORDER BY empno;
BEGIN
OPEN emp_cur_3;
FETCH emp_cur_3 INTO v_empno, v_ename;
...
END;
表の中のすべての列が表に定義されている順序で検索された場合は、 %ROWTYPE を使用して、 FETCH 文が検索されたデータを 入れるレコードを定義でき ます。レコード内の各フィールドは、ドット表記法を使用してアクセスできます。
CREATE OR REPLACE PROCEDURE cursor_example
IS
v_emp_rec emp%ROWTYPE;
CURSOR emp_cur_1 IS SELECT * FROM emp;
BEGIN
OPEN emp_cur_1;
FETCH emp_cur_1 INTO v_emp_rec;
DBMS_OUTPUT.PUT_LINE('Employee Number: ' || v_emp_rec.empno);
DBMS_OUTPUT.PUT_LINE('Employee Name : ' || v_emp_rec.ename);
...
END;
 
3.8.4 カーソルのクローズ
すべての目的の行がカーソル結果セットから取得されたら、カーソルを閉じる必要があります。クローズすると、結果セットにアクセスできなくなります。 次のように CLOSE 文が表示されます。
CLOSE name ;
name は、現在開いているカーソルの識別子です。一旦カーソルが閉じられると、それは再び閉じられてはならない。ただし、カーソルがクローズ されると、クローズされたカーソルで OPEN 文を再度発行し、問合せ結果セットを再構築した後、 FETCH文を使用して新しい結果セットの行を取り出すことができます。
次の例は、 CLOSE文の使用方法を示しています
CREATE OR REPLACE PROCEDURE cursor_example
IS
v_emp_rec emp%ROWTYPE;
CURSOR emp_cur_1 IS SELECT * FROM emp;
BEGIN
OPEN emp_cur_1;
FETCH emp_cur_1 INTO v_emp_rec;
DBMS_OUTPUT.PUT_LINE('Employee Number: ' || v_emp_rec.empno);
DBMS_OUTPUT.PUT_LINE('Employee Name : ' || v_emp_rec.ename);
CLOSE emp_cur_1;
END;
このプロシージャは、起動時に次の出力を生成します。従業員番号 7369 SMITH は結果セットの最初の行です。
EXEC cursor_example;
 
Employee Number: 7369
Employee Name : SMITH
 
3.8.5 カーソル付き%ROWTYPEの使用
%ROWTYPE 属性 を使用 すると、カーソルまたはカーソル変数からフェッチされたすべての列に対応するフィールドを含むレコードを定義できます。各フィールドは、対応する列のデータ型を取ります。 %ROWTYPE 属性は、カーソル名またはカーソル変数名が付けられます。
record cursor %ROWTYPE;
レコード レコードに 割り当てられた識別子です。 cursorは、現在のスコープ内で明示的に宣言されたカーソルです。
次の例は、 %ROWTYPEの カーソルを 使用して、どの部門のどの従業員がどの部門で働いているかに関する情報を得る方法を示しています
CREATE OR REPLACE PROCEDURE emp_info
IS
CURSOR empcur IS SELECT ename, deptno FROM emp;
myvar empcur%ROWTYPE;
BEGIN
OPEN empcur;
LOOP
FETCH empcur INTO myvar;
EXIT WHEN empcur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE( myvar.ename || ' works in department '
|| myvar.deptno );
END LOOP;
CLOSE empcur;
END;
この手順の出力は次のとおりです。
EXEC emp_info;
 
SMITH works in department 20
ALLEN works in department 30
WARD works in department 30
JONES works in department 20
MARTIN works in department 30
BLAKE works in department 30
CLARK works in department 10
SCOTT works in department 20
KING works in department 10
TURNER works in department 30
ADAMS works in department 20
JAMES works in department 30
FORD works in department 20
MILLER works in department 10
 
 
3.8.6 カーソルの属性
各カーソルには、プログラムがカーソルの状態をテストできるように関連する一連の属性があります。これらの属性は %ISOPEN %FOUND %NOTFOUND %ROWCOUNT です。これらの属性については、次のセクションで説明します。
3.8.6.1 %ISOPEN
%ISOPEN 属性はカーソルがオープンしているかどうかをテストするために使用されます。
cursor_name %ISOPEN
cursor_name は、 カーソルが開いている場合は BOOLEAN データ型 TRUE が返される カーソルの名前 FALSE さもないと。
以下は %ISOPEN の使用例です
CREATE OR REPLACE PROCEDURE cursor_example
IS
...
CURSOR emp_cur_1 IS SELECT * FROM emp;
...
BEGIN
...
IF emp_cur_1%ISOPEN THEN
NULL;
ELSE
OPEN emp_cur_1;
END IF;
FETCH emp_cur_1 INTO ...
...
END;
3.8.6.2 %が見つかりました
%FOUND 属性は、 カーソルで FETCH 後行が指定されたカーソルの結果セットから取得されたか否かをテストするために使用されます
cursor_name %FOUND
cursor_name は、 FETCHの 後にカーソルの結果セットから行が取り出された場合 TRUEの BOOLEAN データ・タイプ が戻される カーソルの名前です
結果セットの最後の行が FETCH された後、次のFETCH%FOUNDを返してFALSEを返します。先頭に結果セットに行がない場合は、最初のFETCHの後にFALSEも戻されます。
カーソルがオープンされる前または閉じられた後にカーソルで%FOUND参照すると、 INVALID_CURSOR例外がスローされます。
%FOUND 、カーソルが開いているとき、最初の FETCHの 前に参照されている場合は nullを 返し ます
次の例では、 %FOUNDを 使用しています。
CREATE OR REPLACE PROCEDURE cursor_example
IS
v_emp_rec emp%ROWTYPE;
CURSOR emp_cur_1 IS SELECT * FROM emp;
BEGIN
OPEN emp_cur_1;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
FETCH emp_cur_1 INTO v_emp_rec;
WHILE emp_cur_1%FOUND LOOP
DBMS_OUTPUT.PUT_LINE(v_emp_rec.empno || ' ' || v_emp_rec.ename);
FETCH emp_cur_1 INTO v_emp_rec;
END LOOP;
CLOSE emp_cur_1;
END;
前の手順が呼び出されると、次のように出力されます。
EXEC cursor_example;
 
EMPNO ENAME
----- ------
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER
 
3.8.6.3 %NOTFOUND
%のNOTFOUND 属性、FOUND%の論理的に反対です
cursor_name %NOTFOUND
cursor_name は、 FETCHの 後のカーソルの結果セットから行が検索された場合に、FALSEの BOOLEAN データ・タイプが戻される カーソルの名前です
結果セットの最後の行が FETCH された後、次のFETCH%NOTFOUNDTRUEを返します。また、最初に結果セットに行がない場合は、最初のFETCHの後にTRUEも戻されます。
カーソルがオープンされる前、または閉じられた後に%NOTFOUND参照すると、 INVALID_CURSOR例外がスローされます。
%NOTFOUND 、カーソルが開いているときに、最初の FETCHの 前に参照されている場合は nullを 返し ます
次の例では、 %NOTFOUNDを 使用してい ます
CREATE OR REPLACE PROCEDURE cursor_example
IS
v_emp_rec emp%ROWTYPE;
CURSOR emp_cur_1 IS SELECT * FROM emp;
BEGIN
OPEN emp_cur_1;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH emp_cur_1 INTO v_emp_rec;
EXIT WHEN emp_cur_1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_emp_rec.empno || ' ' || v_emp_rec.ename);
END LOOP;
CLOSE emp_cur_1;
END;
前の例と同様に、このプロシージャは起動時に同じ出力を生成します。
EXEC cursor_example;
 
EMPNO ENAME
----- ------
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER
 
 
 
ROWCOUNT 3.8.6.4
%のROWCOUNT 属性は、行の数を示す整数で 指定されたカーソルからこれまで編 FETCH 返します
cursor_name %ROWCOUNT
cursor_name は、 %ROWCOUNT がそれまでに検索された行数を戻す カーソルの名前です 。最後の行は、 行の合計数に設定 %のROWCOUNTが 残って 、検索された後に カーソルが参照場合、%ROWCOUNTは、INVALID_CURSOR 例外スローされ た時点でクローズされるまで戻りました
カーソルがオープンされる前、または閉じられた後に%ROWCOUNT参照すると、 INVALID_CURSOR例外がスローされます。
%ROWCOUNT 、カーソルが開いているときに、最初の FETCHの 前に参照されている場合は 0を 返します %ROWCOUNTは また 、最初に結果セットに行がない場合、最初の FETCHの 後に 0 返します
次の例では、 %ROWCOUNTを 使用してい ます
CREATE OR REPLACE PROCEDURE cursor_example
IS
v_emp_rec emp%ROWTYPE;
CURSOR emp_cur_1 IS SELECT * FROM emp;
BEGIN
OPEN emp_cur_1;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH emp_cur_1 INTO v_emp_rec;
EXIT WHEN emp_cur_1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_emp_rec.empno || ' ' || v_emp_rec.ename);
END LOOP;
DBMS_OUTPUT.PUT_LINE('**********************');
DBMS_OUTPUT.PUT_LINE(emp_cur_1%ROWCOUNT || ' rows were retrieved');
CLOSE emp_cur_1;
END;
このプロシージャは、従業員リストの最後に検索された行の総数を次のように出力します。
EXEC cursor_example;
 
EMPNO ENAME
----- -------
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER
**********************
14 rows were retrieved
3.8.6.5 カーソル状態と属性の概要
次の表は、カーソルの可能性のある状態と、カーソル属性によって返される値をまとめたものです。
表3-3カーソルの属性
OPENの 前に
OPEN&第一の前に FETCH
0
FETCHが 成功した後
1
n (最後の行)を FETCH 成功番目
n
n + 1番目の (最後の行の後)FETCH
n
CLOSE
3.8.7 カーソルFORループ
カーソルの結果セットを処理するために必要なプログラミング・ロジックには、カーソルを開くための文、結果セットの各行を取り出すためのループ構造、結果セットの最後のテスト、そして最後にカーソルを閉じるためのステートメント。 カーソルFORループは、個別に記載されているだけでステートメントをコーディングする必要がなくなりループ構造です。
カーソル FORループは、以前に宣言されたカーソルをオープンし、カーソル結果セット内のすべての行を取り出してから、カーソルをクローズします。
カーソル FORループを作成する構文は次のとおりです。
FOR record IN cursor
LOOP
statements
END LOOP;
レコード は暗黙的に宣言されたレコードに割り当てられた識別子、 カーソル %ROWTYPE です。 cursor は、以前に宣言されたカーソルの名前です。 ステートメント は、1つ以上の SPLステートメントです。少なくとも1つのステートメントが必要です。
次の例は、カーソルFORループを使用するように変更された3.8.6.3 項の例を示しています。
CREATE OR REPLACE PROCEDURE cursor_example
IS
CURSOR emp_cur_1 IS SELECT * FROM emp;
BEGIN
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
FOR v_emp_rec IN emp_cur_1 LOOP
DBMS_OUTPUT.PUT_LINE(v_emp_rec.empno || ' ' || v_emp_rec.ename);
END LOOP;
END;
次の出力に示すように同じ結果が得られます。
EXEC cursor_example;
 
EMPNO ENAME
----- -------
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER
 
3.8.8 パラメータ化されたカーソル
ユーザーは、パラメーターを受け入れる静的カーソルを宣言し、そのカーソルを開くときにそれらのパラメーターの値を渡すこともできます。次の例では、パラメーター化されたカーソルを作成しました。このカーソルは、 emp 表の給与が指定された値よりも小さく、パラメーターとして渡される すべての従業員の名前と給与を表示し ます。
DECLARE
my_record emp%ROWTYPE;
CURSOR c1 (max_wage NUMBER) IS
SELECT * FROM emp WHERE sal < max_wage;
BEGIN
OPEN c1(2000);
LOOP
FETCH c1 INTO my_record;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Name = ' || my_record.ename || ', salary = '
|| my_record.sal);
END LOOP;
CLOSE c1;
END;
たとえば、2000という値を max_wage として 渡すと、給与が2000未満のすべての従業員の名前と給与のみが表示されます。上記のクエリの結果は次のとおりです。
Name = SMITH, salary = 800.00
Name = ALLEN, salary = 1600.00
Name = WARD, salary = 1250.00
Name = MARTIN, salary = 1250.00
Name = TURNER, salary = 1500.00
Name = ADAMS, salary = 1100.00
Name = JAMES, salary = 950.00
Name = MILLER, salary = 1300.00
3.9 REF CURSORおよびカーソル変数
このセクションでは、前述の静的カーソルよりもはるかに大きな柔軟性を提供する別のタイプのカーソルについて説明します。
3.9.1 REF CURSORの概要
カーソル変数は、 実際に 、クエリ結果セットへのポインタを含むカーソルです。 結果セットは 、カーソル変数を使用したOPEN FOR文の実行によって決定されます。
カーソル変数は、静的カーソルのような単一の特定のクエリに結びついていません。異なるカーソルを含むOPEN FOR文を使用して、同じカーソル変数を何度も開くことができます。毎回、そのクエリから新しい結果セットが作成され、カーソル変数を介して使用可能になります。
REF CURSOR 型は、ストアドプロシージャとストアドプロシージャ間でパラメータとして渡すことが できます 。関数の戻り値の型は、 REF CURSOR 型であって もよい 。これは、プログラム間にカーソル変数を渡すことにより、カーソル上の操作を別々のプログラムにモジュール化する機能を提供します。
3.9.2 カーソル変数の宣言
SPL は、 SYS_REFCURSOR ビルトイン・データ型と REF CURSOR 型を作成し、 その型の変数を宣言する だけでなく 、カーソル変数の宣言もサポート しています。 SYS_REFCURSOR REF CURSOR 型で、結果セットを関連付けることができます。これは、 弱く型付けされた REFカーソル
SYS_REFCURSORとユーザー定義のREF CURSOR変数の宣言だけが異なります。カーソルを開く、カーソルに選択する、カーソルを閉じるなどの残りの使用法は、両方のカーソルタイプで同じです。この章の残りの部分では、主にSYS_REFCURSORカーソルを使用する例を示します。ユーザー定義のREF CURSORで動作させるために例で変更する必要があるのは、宣言セクションです。
注: 強くタイプされた REF CURSOR は、結果セットが、互換性のあるデータ型を持つフィールドの宣言された数と順序に適合することを要求し、オプションで結果セットを返すこともできます。
3.9.2.1 SYS_REFCURSORカーソル変数の宣言
SYS_REFCURSOR カーソル変数 を宣言する構文は次のとおり です。
name SYS_REFCURSOR;
nameはカーソル変数に割り当てられた識別子です。
以下は、 SYS_REFCURSOR変数宣言の例です
DECLARE
emp_refcur SYS_REFCURSOR;
...
 
3.9.2.2 ユーザ定義のREF CURSOR型変数の宣言
ユーザー定義の REF CURSOR変数を使用するには、2つの異なる宣言手順を実行する必要があります。
ユーザー定義の REF CURSORを作成する構文は次のとおりです。
TYPE cursor_type_name IS REF CURSOR [ RETURN return_type ];
以下は、カーソル変数宣言の例です。
DECLARE
TYPE emp_cur_type IS REF CURSOR RETURN emp%ROWTYPE;
my_rec emp_cur_type;
...
 
3.9.3 カーソル変数を開く
カーソル変数が宣言されると、関連する SELECT コマンドで 開く必要があります OPEN FOR は、 結果セットを作成するために使用する SELECT コマンドを 指定します
OPEN name FOR query ;
name は、以前に宣言されたカーソル変数の識別子です。 query 、ステートメントの実行時に結果セットを決定 する SELECT コマンドです。 OPEN FOR文が実行された後のカーソル変数の値は 、結果セットを識別します。
次の例では、結果セットは選択した部門の従業員番号と名前のリストです。変数またはパラメータは 、式が通常表示される任意の場所でSELECTコマンドで使用できます。この場合、部門番号の等価性テストでパラメータが使用されます。
CREATE OR REPLACE PROCEDURE emp_by_dept (
p_deptno emp.deptno%TYPE
)
IS
emp_refcur SYS_REFCURSOR;
BEGIN
OPEN emp_refcur FOR SELECT empno, ename FROM emp WHERE deptno = p_deptno;
...
 
3.9.4 カーソル変数からの行のフェッチ
カーソル変数がオープンされた後、 FETCH ステートメント を使用して結果セットから行を検索することができます 結果セットから行を取り出すためにFETCH文を使用する方法の詳細は、 3.8.3 を参照してください
以下の例では 、前の例にFETCHステートメントが追加されたので、結果セットは2つの変数に戻されて表示されます。静的カーソルのカーソル状態を決定するために使用されるカーソル属性は、カーソル変数とともに使用することもできます。カーソル属性の詳細は、 3.8.6項を参照してください。
CREATE OR REPLACE PROCEDURE emp_by_dept (
p_deptno emp.deptno%TYPE
)
IS
emp_refcur SYS_REFCURSOR;
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
BEGIN
OPEN emp_refcur FOR SELECT empno, ename FROM emp WHERE deptno = p_deptno;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH emp_refcur INTO v_empno, v_ename;
EXIT WHEN emp_refcur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_ename);
END LOOP;
...
 
3.9.5 カーソル変数のクローズ
3.8.4 項で説明し CLOSE 文を 使用して 、結果セットを解放します。
注:静的カーソルとは異なり、カーソル変数を再度開く前に閉じる必要はありません。前回開いた結果セットは失われます。
この例では、 CLOSE文が追加されています。
CREATE OR REPLACE PROCEDURE emp_by_dept (
p_deptno emp.deptno%TYPE
)
IS
emp_refcur SYS_REFCURSOR;
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
BEGIN
OPEN emp_refcur FOR SELECT empno, ename FROM emp WHERE deptno = p_deptno;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH emp_refcur INTO v_empno, v_ename;
EXIT WHEN emp_refcur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_ename);
END LOOP;
CLOSE emp_refcur;
END;
この手順を実行すると、次のように出力されます。
EXEC emp_by_dept(20)
 
EMPNO ENAME
----- -------
7369 SMITH
7566 JONES
7788 SCOTT
7876 ADAMS
7902 FORD
 
3.9.6 使用制限
カーソル変数の使用に関する制限事項は次のとおりです。
さらに、次の表は、プロシージャーまたは関数内のカーソル変数に対する操作に応じて、プロシージャーまたは関数のパラメーターとして使用されるカーソル変数の使用可能なパラメーター・モードを示しています。
表3-4許容カーソル変数のパラメータ・モード
たとえば、 プロシージャーが仮パラメーターとして宣言されたカーソル変数の OPEN FOR FETCH 、および CLOSEの 3つの操作をすべて実行する場合、 そのパラメーターは IN OUT モードで 宣言する必要があり ます。
3.9.7
次の例は、カーソル変数の使用法を示しています。
3.9.7.1 関数からREF CURSORを返す
次の例では、カーソル変数が、特定のジョブで従業員を選択するクエリで開かれています。カーソル変数はこの関数の RETURN ステートメントで 指定されている ので、 関数の 呼び出し側が結果セットを使用できるようになります。
CREATE OR REPLACE FUNCTION emp_by_job (p_job VARCHAR2)
RETURN SYS_REFCURSOR
IS
emp_refcur SYS_REFCURSOR;
BEGIN
OPEN emp_refcur FOR SELECT empno, ename FROM emp WHERE job = p_job;
RETURN emp_refcur;
END;
この関数は、次の無名ブロックで呼び出されます。無名ブロックの宣言セクションで宣言されたカーソル変数に関数の戻り値を代入します。結果セットはこのカーソル変数を使用してフェッチされ、次にクローズされます。
DECLARE
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
v_job emp.job%TYPE := 'SALESMAN';
v_emp_refcur SYS_REFCURSOR;
BEGIN
DBMS_OUTPUT.PUT_LINE('EMPLOYEES WITH JOB ' || v_job);
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
v_emp_refcur := emp_by_job(v_job);
LOOP
FETCH v_emp_refcur INTO v_empno, v_ename;
EXIT WHEN v_emp_refcur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_ename);
END LOOP;
CLOSE v_emp_refcur;
END;
匿名ブロックが実行されたときの出力は次のとおりです。
EMPLOYEES WITH JOB SALESMAN
EMPNO ENAME
----- -------
7499 ALLEN
7521 WARD
7654 MARTIN
7844 TURNER
3.9.7.2 カーソル操作のモジュール化
次の例は、カーソル変数のさまざまな操作を別々のプログラムにモジュール化する方法を示しています。
次のプロシージャは、すべての行を検索する SELECTコマンドを使用して、指定されたカーソル変数をオープンします。
CREATE OR REPLACE PROCEDURE open_all_emp (
p_emp_refcur IN OUT SYS_REFCURSOR
)
IS
BEGIN
OPEN p_emp_refcur FOR SELECT empno, ename FROM emp;
END;
このバリエーションは、指定されたカーソル変数を、 すべての行を検索 する SELECT コマンドで 開きますが、指定さ れた部門のものです。
CREATE OR REPLACE PROCEDURE open_emp_by_dept (
p_emp_refcur IN OUT SYS_REFCURSOR,
p_deptno emp.deptno%TYPE
)
IS
BEGIN
OPEN p_emp_refcur FOR SELECT empno, ename FROM emp
WHERE deptno = p_deptno;
END;
この第3のバリエーションは、 すべての行を検索 する SELECT コマンドを使用 して、指定されたカーソル変数をオープンします が、別の表から オープンし ます。また、関数の戻り値はオープンされたカーソル変数です。
CREATE OR REPLACE FUNCTION open_dept (
p_dept_refcur IN OUT SYS_REFCURSOR
) RETURN SYS_REFCURSOR
IS
v_dept_refcur SYS_REFCURSOR;
BEGIN
v_dept_refcur := p_dept_refcur;
OPEN v_dept_refcur FOR SELECT deptno, dname FROM dept;
RETURN v_dept_refcur;
END;
このプロシージャは、従業員番号と名前で構成されるカーソル変数結果セットをフェッチして表示します。
CREATE OR REPLACE PROCEDURE fetch_emp (
p_emp_refcur IN OUT SYS_REFCURSOR
)
IS
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
BEGIN
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH p_emp_refcur INTO v_empno, v_ename;
EXIT WHEN p_emp_refcur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_ename);
END LOOP;
END;
このプロシージャは、部門番号と名前で構成されるカーソル変数結果セットをフェッチして表示します。
CREATE OR REPLACE PROCEDURE fetch_dept (
p_dept_refcur IN SYS_REFCURSOR
)
IS
v_deptno dept.deptno%TYPE;
v_dname dept.dname%TYPE;
BEGIN
DBMS_OUTPUT.PUT_LINE('DEPT DNAME');
DBMS_OUTPUT.PUT_LINE('---- ---------');
LOOP
FETCH p_dept_refcur INTO v_deptno, v_dname;
EXIT WHEN p_dept_refcur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_deptno || ' ' || v_dname);
END LOOP;
END;
このプロシージャは、指定されたカーソル変数をクローズします。
CREATE OR REPLACE PROCEDURE close_refcur (
p_refcur IN OUT SYS_REFCURSOR
)
IS
BEGIN
CLOSE p_refcur;
END;
次の無名ブロックは、前述のすべてのプログラムを実行します。
DECLARE
gen_refcur SYS_REFCURSOR;
BEGIN
DBMS_OUTPUT.PUT_LINE('ALL EMPLOYEES');
open_all_emp(gen_refcur);
fetch_emp(gen_refcur);
DBMS_OUTPUT.PUT_LINE('****************');
 
DBMS_OUTPUT.PUT_LINE('EMPLOYEES IN DEPT #10');
open_emp_by_dept(gen_refcur, 10);
fetch_emp(gen_refcur);
DBMS_OUTPUT.PUT_LINE('****************');
 
DBMS_OUTPUT.PUT_LINE('DEPARTMENTS');
fetch_dept(open_dept(gen_refcur));
DBMS_OUTPUT.PUT_LINE('*****************');
 
close_refcur(gen_refcur);
END;
以下は無名ブロックからの出力です。
ALL EMPLOYEES
EMPNO ENAME
----- -------
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER
****************
EMPLOYEES IN DEPT #10
EMPNO ENAME
----- -------
7782 CLARK
7839 KING
7934 MILLER
****************
DEPARTMENTS
DEPT DNAME
---- ---------
10 ACCOUNTING
20 RESEARCH
30 SALES
40 OPERATIONS
*****************
 
3.9.8 REF CURSORを使用した動的問合せ
Advanced Server は、 OPEN FOR USING を使用して動的クエリをサポートしてい ます 。文字列リテラルまたは文字列変数は、 OPEN FOR USING 文で SELECT コマンドに 提供され ます。
OPEN name FOR dynamic_string
[ USING bind_arg [, bind_arg_2 ] ... ];
name は、以前に宣言されたカーソル変数の識別子です。 dynamic_string は、 セミコロンを終了せずに SELECT コマンド を含む文字列リテラルまたは文字列変数です bind_arg bind_arg_2 ...は 、カーソル変数がオープンされたときに、 SELECTコマンドの対応するプレースホルダに変数を渡すために使用されるバインド引数です 。プレースホルダは、コロン文字を前に付けた識別子です。
以下は、文字列リテラルを使用する動的クエリの例です。
CREATE OR REPLACE PROCEDURE dept_query
IS
emp_refcur SYS_REFCURSOR;
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
BEGIN
OPEN emp_refcur FOR 'SELECT empno, ename FROM emp WHERE deptno = 30' ||
' AND sal >= 1500';
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH emp_refcur INTO v_empno, v_ename;
EXIT WHEN emp_refcur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_ename);
END LOOP;
CLOSE emp_refcur;
END;
以下はプロシージャ実行時の出力です。
EXEC dept_query;
 
EMPNO ENAME
----- -------
7499 ALLEN
7698 BLAKE
7844 TURNER
次の例では、以前のクエリはバインド引数を使用してクエリパラメータを渡すように変更されています。
CREATE OR REPLACE PROCEDURE dept_query (
p_deptno emp.deptno%TYPE,
p_sal emp.sal%TYPE
)
IS
emp_refcur SYS_REFCURSOR;
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
BEGIN
OPEN emp_refcur FOR 'SELECT empno, ename FROM emp WHERE deptno = :dept'
|| ' AND sal >= :sal' USING p_deptno, p_sal;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH emp_refcur INTO v_empno, v_ename;
EXIT WHEN emp_refcur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_ename);
END LOOP;
CLOSE emp_refcur;
END;
結果は次のようになります。
EXEC dept_query(30, 1500);
 
EMPNO ENAME
----- -------
7499 ALLEN
7698 BLAKE
7844 TURNER
最後に、文字列変数を使用して 、最も柔軟性の高い SELECT を渡し ます。
CREATE OR REPLACE PROCEDURE dept_query (
p_deptno emp.deptno%TYPE,
p_sal emp.sal%TYPE
)
IS
emp_refcur SYS_REFCURSOR;
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
p_query_string VARCHAR2(100);
BEGIN
p_query_string := 'SELECT empno, ename FROM emp WHERE ' ||
'deptno = :dept AND sal >= :sal';
OPEN emp_refcur FOR p_query_string USING p_deptno, p_sal;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH emp_refcur INTO v_empno, v_ename;
EXIT WHEN emp_refcur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_ename);
END LOOP;
CLOSE emp_refcur;
END;
EXEC dept_query(20, 1500);
 
EMPNO ENAME
----- -------
7566 JONES
7788 SCOTT
7902 FORD
3.10 コレクション
コレクションは、同じデータ型の注文データ項目のセットです。一般に、データ項目はスカラー項目ですが、ユーザー定義型の各フィールドを構成する構造体とデータ型が同じであれば、レコード型やオブジェクト型などのユーザー定義型でもかまいませんセット内の各要素に対してセット内の各特定のデータ項目は、一対の括弧内の添字表記を使用して参照されます。
注:マルチレベルコレクション(つまり、コレクションのデータ項目が別のコレクションである)はサポートされていません。
最も一般的に知られているタイプのコレクションは配列です。で 高度なサーバー 、サポートコレクション型は、 連想配列 (以前はインデックス・バイ・テーブルオラクルで呼ばれる)、 ネストした表およびVARRAYのです。
コレクションを使用する一般的な手順は次のとおりです。
目的の型のコレクションを定義する必要があります。これはSPLプログラムの宣言セクションで行うことができ、そのプログラム内でのみアクセスできるローカルタイプになります。ネストした表およびVARRAY型の場合、これはCREATE TYPEコマンドを使用して行うこともできます。このコマンドは、データベース内の任意のSPLプログラムによって参照できる永続的なスタンドアロン型を作成します。
コレクション型の変数が宣言されています。変数宣言の一部として値の割り当てがない場合、宣言された変数に関連付けられたコレクションは 、この時点 初期化されていない と言われます
ネストした表およびVARRAYの初期化されていないコレクションはNULLです。 ヌルコレクションがまだ存在していません。通常、 COLLECTION_IS_NULL例外は、コレクションがnullコレクションで呼び出された場合にスローされます。
各コレクションタイプの具体的なプロセスについては、次のセクションで説明します。
3.10.1 連想配列
連想配列は値を持つ一意のキーを関連付け、コレクションの一種です。キーは数値である必要はありませんが、文字データでもかまいません。
連想配列には、次の特性があります。
連想配列型は、 配列変数は、その配列型の宣言することができた後に定義する必要があります。データ操作は、配列変数を使用して行われます。
INDEX BY BINARY_INTEGERまたはPLS_INTEGERが指定されている場合、キーには負の整数、正の整数、またはゼロを指定できます。
INDEX BY VARCHAR2が指定されている場合、キーは文字データです
TYPEは、OF ...文のBY INDEX TABLEは、連想配列タイプを定義するために使用さます。
TYPE assoctype IS TABLE OF { datatype | rectype | objtype }
INDEX BY { BINARY_INTEGER | PLS_INTEGER | VARCHAR2( n ) } ;
assoctype は配列型に割り当てられた識別子です。 datatype は、 VARCHAR2 または NUMBER などのスカラー・データ型 です。 rectypeは、以前に定義されたレコードタイプです。 objtypeは、以前に定義されたオブジェクト型です。 nは文字キーの最大長です。
配列を使用するには、その配列型で変数を宣言する必要があります。配列変数を宣言する構文は次のとおりです。
array assoctype
配列 は、連想配列に割り当てられた識別子です。 assoctypeは、あらかじめ定義された配列型の識別子です。
配列の要素は、次の構文を使用して参照されます。
array ( n )[. field ]
array は、以前に宣言された配列の識別子です。 n はキー値で、 INDEX BY 句で 指定されたデータ型と型互換性があります アレイ の配列型は、 レコード型またはオブジェクト型から定義されている 場合 、[。 フィールド ]は、配列タイプが定義されているオブジェクトタイプ内のレコードタイプまたは属性内の個々のフィールドを参照する必要があります。あるいは、レコード全体を参照するには、[。 フィールド ]をクリックします。
次の例では、 empから最初の10の従業員名を読み取り、配列に格納してから配列の結果を表示します。
DECLARE
TYPE emp_arr_typ IS TABLE OF VARCHAR2(10) INDEX BY BINARY_INTEGER;
emp_arr emp_arr_typ;
CURSOR emp_cur IS SELECT ename FROM emp WHERE ROWNUM <= 10;
i INTEGER := 0;
BEGIN
FOR r_emp IN emp_cur LOOP
i := i + 1;
emp_arr(i) := r_emp.ename;
END LOOP;
FOR j IN 1..10 LOOP
DBMS_OUTPUT.PUT_LINE(emp_arr(j));
END LOOP;
END;
上記の例では、次の出力が生成されます。
SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
前の例は、配列定義でレコードタイプを使用するように変更されました。
DECLARE
TYPE emp_rec_typ IS RECORD (
empno NUMBER(4),
ename VARCHAR2(10)
);
TYPE emp_arr_typ IS TABLE OF emp_rec_typ INDEX BY BINARY_INTEGER;
emp_arr emp_arr_typ;
CURSOR emp_cur IS SELECT empno, ename FROM emp WHERE ROWNUM <= 10;
i INTEGER := 0;
BEGIN
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
FOR r_emp IN emp_cur LOOP
i := i + 1;
emp_arr(i).empno := r_emp.empno;
emp_arr(i).ename := r_emp.ename;
END LOOP;
FOR j IN 1..10 LOOP
DBMS_OUTPUT.PUT_LINE(emp_arr(j).empno || ' ' ||
emp_arr(j).ename);
END LOOP;
END;
以下は、この無名ブロックからの出力です。
EMPNO ENAME
----- -------
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
EMPの%ROWTYPE 属性は、 以下に示すように emp_rec_typ レコードタイプを 使用して代わりのを emp_arr_typ 定義するために使用することができます
DECLARE
TYPE emp_arr_typ IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
emp_arr emp_arr_typ;
CURSOR emp_cur IS SELECT empno, ename FROM emp WHERE ROWNUM <= 10;
i INTEGER := 0;
BEGIN
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
FOR r_emp IN emp_cur LOOP
i := i + 1;
emp_arr(i).empno := r_emp.empno;
emp_arr(i).ename := r_emp.ename;
END LOOP;
FOR j IN 1..10 LOOP
DBMS_OUTPUT.PUT_LINE(emp_arr(j).empno || ' ' ||
emp_arr(j).ename);
END LOOP;
END;
結果は前の例と同じです。
レコードの各フィールドを個別に割り当てる代わりに、レコードレベルの割り当てr_emp から emp_arr行う ことができます
DECLARE
TYPE emp_rec_typ IS RECORD (
empno NUMBER(4),
ename VARCHAR2(10)
);
TYPE emp_arr_typ IS TABLE OF emp_rec_typ INDEX BY BINARY_INTEGER;
emp_arr emp_arr_typ;
CURSOR emp_cur IS SELECT empno, ename FROM emp WHERE ROWNUM <= 10;
i INTEGER := 0;
BEGIN
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
FOR r_emp IN emp_cur LOOP
i := i + 1;
emp_arr(i) := r_emp;
END LOOP;
FOR j IN 1..10 LOOP
DBMS_OUTPUT.PUT_LINE(emp_arr(j).empno || ' ' ||
emp_arr(j).ename);
END LOOP;
END;
連想配列のキーは、次の例に示すように文字データです。
DECLARE
TYPE job_arr_typ IS TABLE OF NUMBER INDEX BY VARCHAR2(9);
job_arr job_arr_typ;
BEGIN
job_arr('ANALYST') := 100;
job_arr('CLERK') := 200;
job_arr('MANAGER') := 300;
job_arr('SALESMAN') := 400;
job_arr('PRESIDENT') := 500;
DBMS_OUTPUT.PUT_LINE('ANALYST : ' || job_arr('ANALYST'));
DBMS_OUTPUT.PUT_LINE('CLERK : ' || job_arr('CLERK'));
DBMS_OUTPUT.PUT_LINE('MANAGER : ' || job_arr('MANAGER'));
DBMS_OUTPUT.PUT_LINE('SALESMAN : ' || job_arr('SALESMAN'));
DBMS_OUTPUT.PUT_LINE('PRESIDENT: ' || job_arr('PRESIDENT'));
END;
 
ANALYST : 100
CLERK : 200
MANAGER : 300
SALESMAN : 400
PRESIDENT: 500
3.10.2 ネストした表
ネストされたテーブルの値と正の整数を関連付けるコレクションの一種です。ネストした表には、次の特性があります。
ネストした表型は、 ネストされたテーブル変数は、そのネストした表型の宣言することができた後に定義する必要があります。データ操作は、ネストした表変数、または単純に「表」を使用して行われます。
ネストした表変数が宣言されると、ネストした表は最初は存在しません(ヌル集合です)。 NULLテーブルは コンストラクタ で初期化する必要があります 。また、代入文の右辺が同じ型の初期化された表である代入文を使用して、表を初期化することもできます。 注意:ネストした表の初期化はOracleでは必須ですが、SPLではオプションです。
コンストラクタは、テーブル内の要素の数を設定します。 EXTEND方法は、テーブルに追加要素を追加します。収集方法については、 3.11節を参照してください。 注意:コンストラクタを使用して表の要素数を設定し、 EXTENDメソッドを使用して表に要素を追加する方法は、Oracleでは必須ですが、SPLではオプションです。
TYPEは、TABLE文SPLプログラムの宣言セクション内にネストされたテーブル・タイプを定義するために使用されています
TYPE tbltype IS TABLE OF { datatype | rectype | objtype } ;
tbltype は、ネストした表の型に割り当てられた識別子です。 datatype は、 VARCHAR2 または NUMBER などのスカラー・データ型 です。 rectypeは、以前に定義されたレコードタイプです。 objtypeは、以前に定義されたオブジェクト型です。
注意: CREATE TYPEコマンドを使用して、データベース内のすべてのSPLプログラムで使用可能なネストした表の型を定義できます。 CREATE TYPEコマンドの詳細は、「Oracle Developer Reference Guide」のデータベース互換性を参照してください。
表を使用するには、そのネストした表の型の変数を宣言する必要があります。以下は、表変数を宣言するための構文です。
table tbltype
table は、ネストした表に割り当てられた識別子です。 tbltypeは、以前に定義されたネストしたテーブル型の識別子です。
ネストした表のコンストラクタを使用してネストした表を初期化します。
tbltype ([ { expr1 | NULL } [, { expr2 | NULL } ] [, ...] ])
tbltypeは、ネストした表の型と同じ名前のネストした表の型のコンストラクタの識別子です。 expr1expr2 、...は、テーブルの要素型と型互換性のある式です。 NULLが指定された場合、対応する要素はnullに設定されます。パラメータ・リストが空の場合、空のネストした表が戻されます。これは、表に要素がないことを意味します。表がオブジェクト型から定義されている場合、 exprnはそのオブジェクト型のオブジェクトを返す必要があります。オブジェクトは、関数またはオブジェクト型のコンストラクタの戻り値にすることも、同じ型の別のネストした表の要素にすることもできます。
EXISTS 以外の収集メソッドを初期化されていないネストした表に適用すると、 COLLECTION_IS_NULL例外がスローされます。収集方法については、 3.11節を参照してください。
次は、ネストした表のコンストラクタの例です。
DECLARE
TYPE nested_typ IS TABLE OF CHAR(1);
v_nested nested_typ := nested_typ('A','B');
次の構文を使用して、テーブルの要素が参照されます。
table ( n )[. element ]
table は、以前に宣言されたテーブルの識別子です。 n は正の整数です。 テーブル のテーブルタイプは、 レコード・タイプまたはオブジェクト・タイプから定義されている 場合 、[。 要素 ]は、ネストした表の型が定義されているオブジェクト型内のレコード型または属性内の個々のフィールドを参照する必要があります。あるいは、レコードまたはオブジェクト全体を参照するには、[。 要素 ]。
次の例は、4つの要素があることがわかっているネストした表の例です。
DECLARE
TYPE dname_tbl_typ IS TABLE OF VARCHAR2(14);
dname_tbl dname_tbl_typ;
CURSOR dept_cur IS SELECT dname FROM dept ORDER BY dname;
i INTEGER := 0;
BEGIN
dname_tbl := dname_tbl_typ(NULL, NULL, NULL, NULL);
FOR r_dept IN dept_cur LOOP
i := i + 1;
dname_tbl(i) := r_dept.dname;
END LOOP;
DBMS_OUTPUT.PUT_LINE('DNAME');
DBMS_OUTPUT.PUT_LINE('----------');
FOR j IN 1..i LOOP
DBMS_OUTPUT.PUT_LINE(dname_tbl(j));
END LOOP;
END;
上記の例では、次の出力が生成されます。
DNAME
----------
ACCOUNTING
OPERATIONS
RESEARCH
SALES
次の例では、 empから最初の10の従業員名を読み取り、ネストした表に格納してから表の結果を表示します。 SPLコードは、返される従業員の数が事前に分かっていないと仮定して書かれています。
DECLARE
TYPE emp_rec_typ IS RECORD (
empno NUMBER(4),
ename VARCHAR2(10)
);
TYPE emp_tbl_typ IS TABLE OF emp_rec_typ;
emp_tbl emp_tbl_typ;
CURSOR emp_cur IS SELECT empno, ename FROM emp WHERE ROWNUM <= 10;
i INTEGER := 0;
BEGIN
emp_tbl := emp_tbl_typ();
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
FOR r_emp IN emp_cur LOOP
i := i + 1;
emp_tbl.EXTEND;
emp_tbl(i) := r_emp;
END LOOP;
FOR j IN 1..10 LOOP
DBMS_OUTPUT.PUT_LINE(emp_tbl(j).empno || ' ' ||
emp_tbl(j).ename);
END LOOP;
END;
匿名ブロックの実行可能セクションの最初のステートメントとして、 コンストラクタ emp_tbl_typ()使用 して空のテーブルを作成することに注意してください 。次に、 EXTENDコレクション・メソッドを使用して、結果セットから戻された各従業員の表に要素を追加します。 EXTENDについては、第3.11.4項を参照してください。
以下は出力です。
EMPNO ENAME
----- -------
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
次の例は、オブジェクト型のネストした表を使用する方法を示しています 。まず、部門名と場所の属性を持つオブジェクトタイプが作成されます。
CREATE TYPE dept_obj_typ AS OBJECT (
dname VARCHAR2(14),
loc VARCHAR2(13)
);
次の無名ブロックは、要素が dept_obj_typオブジェクト型で構成されたネストした表の型を定義します。ネストした表変数は宣言され、初期化され、次にdept表から移入されます。最後に、ネストした表の要素が表示されます。
DECLARE
TYPE dept_tbl_typ IS TABLE OF dept_obj_typ;
dept_tbl dept_tbl_typ;
CURSOR dept_cur IS SELECT dname, loc FROM dept ORDER BY dname;
i INTEGER := 0;
BEGIN
dept_tbl := dept_tbl_typ(
dept_obj_typ(NULL,NULL),
dept_obj_typ(NULL,NULL),
dept_obj_typ(NULL,NULL),
dept_obj_typ(NULL,NULL)
);
FOR r_dept IN dept_cur LOOP
i := i + 1;
dept_tbl(i).dname := r_dept.dname;
dept_tbl(i).loc := r_dept.loc;
END LOOP;
DBMS_OUTPUT.PUT_LINE('DNAME LOC');
DBMS_OUTPUT.PUT_LINE('---------- ----------');
FOR j IN 1..i LOOP
DBMS_OUTPUT.PUT_LINE(RPAD(dept_tbl(j).dname,14) || ' ' ||
dept_tbl(j).loc);
END LOOP;
END;
注意:ネストした表のコンストラクタdept_tbl_typを構成するパラメータは、オブジェクト型のコンストラクタdept_obj_typへのコールです。
以下は無名ブロックからの出力です。
DNAME LOC
---------- ----------
ACCOUNTING NEW YORK
OPERATIONS BOSTON
RESEARCH DALLAS
SALES CHICAGO
3.10.3 Varrays
VARRAYまたは可変サイズアレイは、値が正の整数を関連付けるコレクションの一種です。多くの点で、ネストした表に似ています。
VARRAYの特徴は次のとおりです。
VARRAY型は、最大サイズの制限と一緒に定義されなければなりません。 VARRAY型が定義されると、そのVARRAY型のVARRAY型変数を宣言できます。データ操作は、varray変数、または単に「varray」を使用して行われます。 VARRAYの要素数は、VARRAY型定義で設定されている最大サイズ制限を超えることはできません。
VARRAY変数が宣言されると、VARRAYは最初は存在しません(これはヌル・コレクションです)。 null VARRAYは、 コンストラクタ で初期化する必要があります 。代入文の右辺が同じ型の初期化されたVARRAYである代入文を使用して、VARRAYを初期化することもできます。
コンストラクタは、最大サイズ制限を超えてはならないVARRAY内の要素の数を設定します。 EXTEND方法は、最大サイズ限界までVARRAYに付加的な要素を追加することができます。収集方法については、 3.11節を参照してください。
TYPEは、VARRAYステートメントSPLプログラムの宣言セクション内のVARRAY型を定義するために使用されています
TYPE varraytype IS { VARRAY | VARYING ARRAY }( maxsize )
OF { datatype | objtype };
varraytype は、VARRAY型に割り当てられた識別子です。 datatype は、 VARCHAR2 または NUMBER などのスカラー・データ型 です。 maxsize は、その型のVARRAYで許される要素の最大数です。 objtype は、以前に定義されたオブジェクト型です。
注: CREATE TYPEコマンドを使用して、データベース内のすべてのSPLプログラムで使用可能なVARRAYタイプを定義することができます。 VARRAYを使用するには、VARRAY型の変数を宣言する必要があります。次に、VARRAY変数を宣言するための構文を示します。
varray varraytype
varray は、 VARRAYに 割り当てられた識別子です。 varraytypeは、あらかじめ定義されたVARRAY型の識別子です。
VARRAYは、VARRAY型のコンストラクタを使用して初期化されます。
varraytype ([ { expr1 | NULL } [, { expr2 | NULL } ]
[, ...] ])
varraytypeは、VARRAY型のコンストラクタの識別子で、VARRAY型と同じ名前を持ちます。 expr1expr2 、...は、VARRAYの要素型と型互換性のある式です。 NULLが指定された場合、対応する要素はnullに設定されます。パラメータリストが空の場合、空のVARRAYが返されます。つまり、VARRAYには要素がありません。 VARRAYがオブジェクト型から定義されている場合、 exprnはそのオブジェクト型のオブジェクトを返す必要があります。オブジェクトは、関数の戻り値、またはオブジェクト型のコンストラクタの戻り値です。オブジェクトは、同じVARRAY型の別のVARRAYの要素でもあります。
EXISTS 以外の収集メソッドを初期化されていないVARRAYに適用すると、 COLLECTION_IS_NULL例外がスローされます。収集方法については、 3.11節を参照してください。
次に、VARRAYのコンストラクタの例を示します。
DECLARE
TYPE varray_typ IS VARRAY(2) OF CHAR(1);
v_varray varray_typ := varray_typ('A','B');
VARRAYの要素は、次の構文を使用して参照されます。
varray ( n )[. element ]
varray は、以前に宣言されたVARRAYの識別子です。 n は正の整数です。 VARRAY のVARRAY型は、 オブジェクトタイプから定義されている 場合 、[。 要素 ] は、VARRY型が定義されているオブジェクト型内の属性を参照する必要があります。あるいは、 [。]を 省略してオブジェクト全体を参照することもできます 要素 ]
以下は、4つの要素があることが分かっているVARRAYの例です。
DECLARE
TYPE dname_varray_typ IS VARRAY(4) OF VARCHAR2(14);
dname_varray dname_varray_typ;
CURSOR dept_cur IS SELECT dname FROM dept ORDER BY dname;
i INTEGER := 0;
BEGIN
dname_varray := dname_varray_typ(NULL, NULL, NULL, NULL);
FOR r_dept IN dept_cur LOOP
i := i + 1;
dname_varray(i) := r_dept.dname;
END LOOP;
DBMS_OUTPUT.PUT_LINE('DNAME');
DBMS_OUTPUT.PUT_LINE('----------');
FOR j IN 1..i LOOP
DBMS_OUTPUT.PUT_LINE(dname_varray(j));
END LOOP;
END;
上記の例では、次の出力が生成されます。
DNAME
----------
ACCOUNTING
OPERATIONS
RESEARCH
SALES
3.11 コレクションメソッド
コレクションメソッドは、コレクション内のデータの処理を支援するコレクションに関する有用な情報を提供する関数およびプロシージャです。次のセクションでは、Advanced Serverでサポートされている収集方法について説明します。
3.11.1 COUNT
COUNT は、コレクション内の要素の数を返すメソッドです。 COUNT を使用するための構文 は次のとおりです。
collection .COUNT
collectionコレクションの名前です。
VARRAYの場合、 COUNTは常にLASTと等しくなります。
以下の例は、連想配列がまばらに配置される(すなわち、割り当てられた要素のシーケンスに「ギャップ」がある)ことを示しています。 COUNTには、値が割り当てられた要素のみが含まれます。
DECLARE
TYPE sparse_arr_typ IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
sparse_arr sparse_arr_typ;
BEGIN
sparse_arr(-100) := -100;
sparse_arr(-10) := -10;
sparse_arr(0) := 0;
sparse_arr(10) := 10;
sparse_arr(100) := 100;
DBMS_OUTPUT.PUT_LINE('COUNT: ' || sparse_arr.COUNT);
END;
次の出力は、 COUNTに 5つの要素が含まれていることを示しています
COUNT: 5
3.11.2 DELETE
DELETEメソッドは、コレクションからエントリを削除します。 DELETEメソッドは、3つの異なる方法で呼び出すことができます。
DELETEメソッドの最初の形式を使用して 、コレクションからすべてのエントリを削除します。
コレクション .DELETE
指定したエントリをコレクションから削除するには、 DELETEメソッドの2番目の形式を使用します。
コレクション .DELET( 下付き文字
第三の形態を使用コレクションから(first_subscriptlast_subscriptのエントリを含む)first_subscriptlast_subscriptで指定された範囲内にあるエントリを削除するDELETEメソッドを。
コレクション .DELETE( 最初の _ 添字 最後の _ 添字
first_subscriptおよびlast_subscriptが存在しない要素を参照する場合 、指定された添字間の範囲にある要素が削除されます。 first_subscriptが last_subscriptよりも大きい場合、またはあなたが引数のいずれかにNULL値を指定した場合、 削除した場合は効果がありません。
エントリを削除すると、サブスクリプトはコレクションに残ることに注意してください。代わりのエントリで添え字を再利用することができます。 DELETEメソッドへの呼び出しに存在しない添字を指定するとDELETEは例外を発生させません。
次の例は、 DELETEメソッドを使用して 、コレクションからサブスクリプト0の要素を削除する方法を示しています。
DECLARE
TYPE sparse_arr_typ IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
sparse_arr sparse_arr_typ;
v_results VARCHAR2(50);
v_sub NUMBER;
BEGIN
sparse_arr(-100) := -100;
sparse_arr(-10) := -10;
sparse_arr(0) := 0;
sparse_arr(10) := 10;
sparse_arr(100) := 100;
DBMS_OUTPUT.PUT_LINE('COUNT: ' || sparse_arr.COUNT);
sparse_arr.DELETE(0);
DBMS_OUTPUT.PUT_LINE('COUNT: ' || sparse_arr.COUNT);
v_sub := sparse_arr.FIRST;
WHILE v_sub IS NOT NULL LOOP
IF sparse_arr(v_sub) IS NULL THEN
v_results := v_results || 'NULL ';
ELSE
v_results := v_results || sparse_arr(v_sub) || ' ';
END IF;
v_sub := sparse_arr.NEXT(v_sub);
END LOOP;
DBMS_OUTPUT.PUT_LINE('Results: ' || v_results);
END;
 
COUNT: 5
COUNT: 4
Results: -100 -10 10 100
COUNTは、 DELETEメソッドの前にコレクションに5つの要素があったことを示します。 DELETEメソッドが呼び出された後、コレクションには4つの要素が含まれます。
3.11.3は、 EXISTS
この方法は、添字がコレクション内に存在することを確認しEXISTS。 EXISTSは、添え字が存在する場合はTRUEを返します。添え字が存在しない場合、 EXISTSFALSEを返します 。このメソッドは単一の引数をとります。あなたがテストしている添字 。構文は次のとおりです。
コレクション .EXISTS( 下付き文字
collectionコレクションの名前です。
添え字はあなたがテストしている値です。値にNULLを指定すると、 EXISTSfalseを返します
次の例では、添字 10が連想配列内に存在することを確認しています
DECLARE
TYPE sparse_arr_typ IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
sparse_arr sparse_arr_typ;
BEGIN
sparse_arr(-100) := -100;
sparse_arr(-10) := -10;
sparse_arr(0) := 0;
sparse_arr(10) := 10;
sparse_arr(100) := 100;
DBMS_OUTPUT.PUT_LINE('The index exists: ' ||
CASE WHEN sparse_arr.exists(10) = TRUE THEN 'true' ELSE 'false' END);
END;
 
The index exists: true
指定されたコレクション内に存在しない添字を使用して呼び出すと、一部のコレクションメソッドで例外が発生します。エラーを発生させるのではなく、 EXISTSメソッドはFALSEの値を返します
3.11.4 EXTEND
EXTENDメソッドは、コレクションのサイズを増大させます。 EXTENDメソッドには3つのバリエーションがあります。最初のバリエーションは、単一のNULL要素をコレクションに追加します 。最初のバリエーションの構文は次のとおりです。
コレクション .EXTEND
collectionコレクションの名前です。
次の例は、 EXTENDメソッドを使用して単一のnull要素をコレクションに追加する方法を示しています。
DECLARE
TYPE sparse_arr_typ IS TABLE OF NUMBER;
sparse_arr sparse_arr_typ := sparse_arr_typ(-100,-10,0,10,100);
v_results VARCHAR2(50);
BEGIN
DBMS_OUTPUT.PUT_LINE('COUNT: ' || sparse_arr.COUNT);
sparse_arr.EXTEND;
DBMS_OUTPUT.PUT_LINE('COUNT: ' || sparse_arr.COUNT);
FOR i IN sparse_arr.FIRST .. sparse_arr.LAST LOOP
IF sparse_arr(i) IS NULL THEN
v_results := v_results || 'NULL ';
ELSE
v_results := v_results || sparse_arr(i) || ' ';
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Results: ' || v_results);
END;
 
COUNT: 5
COUNT: 6
Results: -100 -10 0 10 100 NULL
COUNTは、 EXTENDメソッドの前にコレクションに5つの要素があったことを示します。 EXTENDメソッドが呼び出された後、コレクションには6つの要素が含まれます。
EXTENDメソッドの2つ目のバリエーションは、指定された数の要素をコレクションの末尾に追加します。
コレクション .EXTEND( count
collectionコレクションの名前です。
countは、コレクションの末尾に追加されたヌル要素の数です。
次の例は、 EXTENDメソッドを使用して複数のnull要素をコレクションに追加する方法を示しています。
DECLARE
TYPE sparse_arr_typ IS TABLE OF NUMBER;
sparse_arr sparse_arr_typ := sparse_arr_typ(-100,-10,0,10,100);
v_results VARCHAR2(50);
BEGIN
DBMS_OUTPUT.PUT_LINE('COUNT: ' || sparse_arr.COUNT);
sparse_arr.EXTEND(3);
DBMS_OUTPUT.PUT_LINE('COUNT: ' || sparse_arr.COUNT);
FOR i IN sparse_arr.FIRST .. sparse_arr.LAST LOOP
IF sparse_arr(i) IS NULL THEN
v_results := v_results || 'NULL ';
ELSE
v_results := v_results || sparse_arr(i) || ' ';
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Results: ' || v_results);
END;
 
COUNT: 5
COUNT: 8
Results: -100 -10 0 10 100 NULL NULL NULL
COUNTは、 EXTENDメソッドの前にコレクションに5つの要素があったことを示します。 EXTENDメソッドが呼び出された後、コレクションには8つの要素が含まれます。
EXTENDメソッドの3番目のバリエーションは、特定の要素の指定された数のコピーをコレクションの末尾に追加します。
コレクション .EXTEND( count index_number
collectionコレクションの名前です。
countは、コレクションの最後に追加された要素の数です。
index_numberは、コレクションにコピーされている要素の添え字です。
次の例は、 EXTENDメソッドを使用して 、2番目の要素の複数のコピーをコレクションに追加する方法を示しています。
DECLARE
TYPE sparse_arr_typ IS TABLE OF NUMBER;
sparse_arr sparse_arr_typ := sparse_arr_typ(-100,-10,0,10,100);
v_results VARCHAR2(50);
BEGIN
DBMS_OUTPUT.PUT_LINE('COUNT: ' || sparse_arr.COUNT);
sparse_arr.EXTEND(3, 2);
DBMS_OUTPUT.PUT_LINE('COUNT: ' || sparse_arr.COUNT);
FOR i IN sparse_arr.FIRST .. sparse_arr.LAST LOOP
IF sparse_arr(i) IS NULL THEN
v_results := v_results || 'NULL ';
ELSE
v_results := v_results || sparse_arr(i) || ' ';
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Results: ' || v_results);
END;
 
COUNT: 5
COUNT: 8
Results: -100 -10 0 10 100 -10 -10 -10
COUNTは、 EXTENDメソッドの前にコレクションに5つの要素があったことを示します。 EXTENDメソッドが呼び出された後、コレクションには8つの要素が含まれます。
注: EXTENDメソッドは、ヌルまたは空のコレクションでは使用できません。
3.11.5 FIRST
FIRSTは、コレクション内の最初の要素の添字を返すメソッドです。 FIRSTを使用するための構文は次のとおりです。
collection .FIRST
collectionコレクションの名前です。
次の例は、連想配列の最初の要素を表示します。
DECLARE
TYPE sparse_arr_typ IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
sparse_arr sparse_arr_typ;
BEGIN
sparse_arr(-100) := -100;
sparse_arr(-10) := -10;
sparse_arr(0) := 0;
sparse_arr(10) := 10;
sparse_arr(100) := 100;
DBMS_OUTPUT.PUT_LINE('FIRST element: ' || sparse_arr(sparse_arr.FIRST));
END;
 
FIRST element: -100
 
3.11.6 LAST
LASTは、コレクション内の最後の要素の添字を返すメソッドです。 LASTを使用するための構文は次のとおりです。
collection .LAST
collectionコレクションの名前です。
次の例は、連想配列の最後の要素を表示します。
DECLARE
TYPE sparse_arr_typ IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
sparse_arr sparse_arr_typ;
BEGIN
sparse_arr(-100) := -100;
sparse_arr(-10) := -10;
sparse_arr(0) := 0;
sparse_arr(10) := 10;
sparse_arr(100) := 100;
DBMS_OUTPUT.PUT_LINE('LAST element: ' || sparse_arr(sparse_arr.LAST));
END;
 
LAST element: 100
 
3.11.7 リミット
LIMIT は、コレクション内で許可される要素の最大数を返すメソッドです。 LIMIT はVARRAYにのみ適用されます。 LIMIT を使用するための構文 は次のとおりです。
collection .LIMIT
collectionコレクションの名前です。
初期化されたVARRAYの場合、 LIMITはVARRAY型定義によって決定される最大サイズ制限を戻します。 VARRAYが初期化されていない場合(つまり、VARRAYがNULLの場合)、例外がスローされます。
連想配列または初期化されたネストした表の場合、 LIMITNULLを戻します 。ネストした表が初期化されていない場合(つまり、ネストした表がNULLの場合)は、例外がスローされます。
3.11.8 NEXT
NEXTは、指定された添え字に続く添え字を返すメソッドです。このメソッドは単一の引数をとります。あなたがテストしている添字
collection .NEXT( subscript )
collectionコレクションの名前です。
指定された添え字がコレクション内の最初の添え字よりも小さい場合、関数は最初の添え字を返します。添字に後続がない場合、 NEXTNULLを返しますNULL添字を指定すると、 PRIORは値を返しません。
次の例は、 NEXT使用して、連想配列sparse_arrの下付き文字10に続く添字を返します。
DECLARE
TYPE sparse_arr_typ IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
sparse_arr sparse_arr_typ;
BEGIN
sparse_arr(-100) := -100;
sparse_arr(-10) := -10;
sparse_arr(0) := 0;
sparse_arr(10) := 10;
sparse_arr(100) := 100;
DBMS_OUTPUT.PUT_LINE('NEXT element: ' || sparse_arr.next(10));
END;
 
NEXT element: 100
 
3.11.9 先行
従来の方法は、 コレクション内の指定の添字の前の添字を返します このメソッドは単一の引数をとります 。あなたがテストしている添字 構文は次のとおりです。
コレクション .PRIOR( 下付き文字
collectionコレクションの名前です。
指定された添え字に 先行 文字がない場合、 PRIOR NULLを 返し ます 。指定された添え字がコレクション内の最後の添え字より大きい場合、このメソッドは最後の添え字を返します。 NULL 添字 を指定すると PRIOR は値を返しません。
次の例では 、連想配列sparse_arrの 添字 100 より前の添字を返します
DECLARE
TYPE sparse_arr_typ IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
sparse_arr sparse_arr_typ;
BEGIN
sparse_arr(-100) := -100;
sparse_arr(-10) := -10;
sparse_arr(0) := 0;
sparse_arr(10) := 10;
sparse_arr(100) := 100;
DBMS_OUTPUT.PUT_LINE('PRIOR element: ' || sparse_arr.prior(100));
END;
 
PRIOR element: 10
3.11.10 トリム
TRIM方法は、コレクションの末尾から要素または要素を除去します。 TRIMメソッドの構文は次のとおりです。
コレクション .TRIM [( count )]
collectionコレクションの名前です。
countは、コレクションの最後から削除された要素の数です。 count0より小さいか、コレクション内の要素の数よりも多い場合、Advanced Serverはエラーを返します。
次の例は、 TRIMメソッドを使用して 、コレクションの最後から要素を削除する方法を示しています。
DECLARE
TYPE sparse_arr_typ IS TABLE OF NUMBER;
sparse_arr sparse_arr_typ := sparse_arr_typ(-100,-10,0,10,100);
BEGIN
DBMS_OUTPUT.PUT_LINE('COUNT: ' || sparse_arr.COUNT);
sparse_arr.TRIM;
DBMS_OUTPUT.PUT_LINE('COUNT: ' || sparse_arr.COUNT);
END;
 
COUNT: 5
COUNT: 4
COUNTは、 TRIMメソッドの前にコレクションに5つの要素があったことを示します。 TRIMメソッドが呼び出された後、コレクションには4つの要素が含まれます。
TRIMメソッドを使用して、コレクションの最後から削除する要素の数を指定することもできます
DECLARE
TYPE sparse_arr_typ IS TABLE OF NUMBER;
sparse_arr sparse_arr_typ := sparse_arr_typ(-100,-10,0,10,100);
v_results VARCHAR2(50);
BEGIN
DBMS_OUTPUT.PUT_LINE('COUNT: ' || sparse_arr.COUNT);
sparse_arr.TRIM(2);
DBMS_OUTPUT.PUT_LINE('COUNT: ' || sparse_arr.COUNT);
FOR i IN sparse_arr.FIRST .. sparse_arr.LAST LOOP
IF sparse_arr(i) IS NULL THEN
v_results := v_results || 'NULL ';
ELSE
v_results := v_results || sparse_arr(i) || ' ';
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Results: ' || v_results);
END;
 
COUNT: 5
COUNT: 3
Results: -100 -10 0
COUNTは、 TRIMメソッドの前にコレクションに5つの要素があったことを示します。 TRIMメソッドが呼び出された後、コレクションには3つの要素が含まれます。
3.12 コレクションの操作
コレクション演算子を使用すると、コレクションの内容を変換、照会、および操作できます。
3.12.1 TABLE()
TABLE() 関数を 使用して 、配列のメンバーを一連の行に変換します。署名は次のとおりです。
TABLE( collection_value
場所:
コレクション値
collection_value は、コレクション型の値に評価される式です。
表() 関数は、テーブル形式にコレクションのネストされた内容を拡張します。 通常のテーブル式を使用する場所であれば TABLE() 関数を使用できます。
表() 関数は SETOFを 返します ANYELEMENT (任意の型の値の集合)。たとえば、この関数に渡された引数が 日付の 配列である 場合、 TABLE() SETOF 日付 。この関数に渡された引数が パスの 配列である 場合、 TABLE() SETOF パス
TABLE() 関数を 使用する と、コレクションの内容を表形式に展開 できます
postgres=# SELECT * FROM TABLE(monthly_balance(445.00, 980.20, 552.00));
 
monthly_balance
----------------
445.00
980.20
552.00
(3 rows)
3.12.2 MULTISET UNION演算子の使用
MULTISET UNION演算子は、第三のコレクションを形成するために、2つのコレクションを兼ね備えています。署名は次のとおりです。
coll_1 マルチセット 結合 [すべて| DISTINCT] coll_2
coll_1coll_2は結合するコレクションの名前を指定します。
重複する要素( coll_1coll_2の両方に存在する要素)を元のコレクションに存在するたびに1回ずつ結果に表示するように指定するには、 ALLキーワードを含めます 。これは、 MULTISET UNIONのデフォルトの動作です。
重複した要素を結果に1回だけ含めるように指定するには、 DISTINCTキーワードを含め ます
次の例は、 MULTISET UNION演算子を使用して、2つのコレクション( collection_1およびcollection_2 )を3番目のコレクション( collection_3 )に結合する方法を示しています
DECLARE
TYPE int_arr_typ IS TABLE OF NUMBER(2);
collection_1 int_arr_typ;
collection_2 int_arr_typ;
collection_3 int_arr_typ;
v_results VARCHAR2(50);
BEGIN
collection_1 := int_arr_typ(10,20,30);
collection_2 := int_arr_typ(30,40);
collection_3 := collection_1 MULTISET UNION ALL collection_2;
DBMS_OUTPUT.PUT_LINE('COUNT: ' || collection_3.COUNT);
FOR i IN collection_3.FIRST .. collection_3.LAST LOOP
IF collection_3(i) IS NULL THEN
v_results := v_results || 'NULL ';
ELSE
v_results := v_results || collection_3(i) || ' ';
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Results: ' || v_results);
END;
 
COUNT: 5
Results: 10 20 30 30 40
結果のコレクションには、 collection_1およびcollection_2の 各要素に1つのエントリが含まれます。 DISTINCTキーワードを使用すると、結果は次のようになります。
DECLARE
TYPE int_arr_typ IS TABLE OF NUMBER(2);
collection_1 int_arr_typ;
collection_2 int_arr_typ;
collection_3 int_arr_typ;
v_results VARCHAR2(50);
BEGIN
collection_1 := int_arr_typ(10,20,30);
collection_2 := int_arr_typ(30,40);
collection_3 := collection_1 MULTISET UNION DISTINCT collection_2;
DBMS_OUTPUT.PUT_LINE('COUNT: ' || collection_3.COUNT);
FOR i IN collection_3.FIRST .. collection_3.LAST LOOP
IF collection_3(i) IS NULL THEN
v_results := v_results || 'NULL ';
ELSE
v_results := v_results || collection_3(i) || ' ';
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Results: ' || v_results);
END;
 
COUNT: 4
Results: 10 20 30 40
結果のコレクションには、異なる値を持つメンバーのみが含まれます。次の例では、 MULTISET UNION DISTINCT演算子も同じコレクション内に格納されている重複エントリを削除しています。
DECLARE
TYPE int_arr_typ IS TABLE OF NUMBER(2);
collection_1 int_arr_typ;
collection_2 int_arr_typ;
collection_3 int_arr_typ;
v_results VARCHAR2(50);
BEGIN
collection_1 := int_arr_typ(10,20,30,30);
collection_2 := int_arr_typ(40,50);
collection_3 := collection_1 MULTISET UNION DISTINCT collection_2;
DBMS_OUTPUT.PUT_LINE('COUNT: ' || collection_3.COUNT);
FOR i IN collection_3.FIRST .. collection_3.LAST LOOP
IF collection_3(i) IS NULL THEN
v_results := v_results || 'NULL ';
ELSE
v_results := v_results || collection_3(i) || ' ';
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Results: ' || v_results);
END;
 
COUNT: 5
Results: 10 20 30 40 50
 
3.12.3 FORALL文の使用
コレクションを使用すると、 DELETEINSERT 、またはUPDATEコマンドの繰り返し実行に使用するすべての値を、新しい値でDMLコマンドを反復的に呼び出すのではなく、データベース・サーバーに渡すことで、 DMLコマンドをより効率的に処理できます。このように処理されるDMLコマンドは、 FORALL文で指定されます。さらに、コマンドが実行されるたびに異なる値が代入されるDMLコマンドには、1つ以上のコレクションが指定されています
FORALL index IN lower_bound .. upper_bound
{ insert_stmt | update_stmt | delete_stmt };
インデックスが insert_stmtで指定されたコレクション内の位置であり、update_stmt、またはDML delete_stmt UPPER_BOUND含むまでLOWER_BOUNDとして整数値から反復が与えられたコマンド。
注:例外はFORALL文の任意の反復中に発生した場合は、FORALL文の実行の開始以降に発生したすべての更新が自動的にロールバックされます。この動作はOracleデータベースと互換性がありません。 Oracleでは、 COMMITまたはROLLBACKコマンドを明示的に使用して、例外の前に発生した更新をコミットまたはロールバックするかどうかを制御できます。
FORALL文は、ループを作成します-ループの各反復は、 インデックス変数を(あなたは、通常のコレクションのメンバーを選択するには、ループ内のインデックスを使用)インクリメント。反復回数は、 lower_bound .. upper_bound節によって制御されます 。ループはlower_boundupper_boundの間の整数ごとに1回実行され、インデックスは各反復ごとに1つずつインクリメントされます。例えば:
私は2 .. 5でFORALL
4回実行されるループを作成します。最初の反復では、 indexi )は値2に設定されます。 2番目の反復では、インデックスは値3に設定されます。ループは値5で実行され、終了します。
次の例では、 emp表の空のコピーである表( emp_copy )を作成します。この例では、配列emp_tblを宣言します。この型は、配列empの作成に使用される列定義で構成される配列の各要素が複合型である配列です。この例では、 emp_tbl型の索引も作成します。
t_empは、 emp_tbl型の連想配列ですSELECTステートメントでは、 BULK COLLECT INTOコマンドを使用してt_emp配列に値を設定します。 t_emp配列が移入された後、 FORALL文はt_emp配列索引の値( i )を反復し、各レコードの行をemp_copyに挿入します
CREATE TABLE emp_copy(LIKE emp);
 
DECLARE
 
TYPE emp_tbl IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
 
t_emp emp_tbl;
 
BEGIN
  SELECT * FROM emp BULK COLLECT INTO t_emp;
 
 FORALL i IN t_emp.FIRST .. t_emp.LAST
    INSERT INTO emp_copy VALUES t_emp(i);
 
END;
次の例では、 FORALL文を使用して 3人の従業員の給与を更新します。
DECLARE
TYPE empno_tbl IS TABLE OF emp.empno%TYPE INDEX BY BINARY_INTEGER;
TYPE sal_tbl IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;
t_empno EMPNO_TBL;
t_sal SAL_TBL;
BEGIN
t_empno(1) := 9001;
t_sal(1) := 3350.00;
t_empno(2) := 9002;
t_sal(2) := 2000.00;
t_empno(3) := 9003;
t_sal(3) := 4100.00;
FORALL i IN t_empno.FIRST..t_empno.LAST
UPDATE emp SET sal = t_sal(i) WHERE empno = t_empno(i);
END;
 
SELECT * FROM emp WHERE empno > 9000;
 
empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+--------+---------+-----+----------+---------+------+--------
9001 | JONES | ANALYST | | | 3350.00 | | 40
9002 | LARSEN | CLERK | | | 2000.00 | | 40
9003 | WILSON | MANAGER | | | 4100.00 | | 40
(3 rows)
次の例では、 FORALLで3人の従業員を削除します
DECLARE
TYPE empno_tbl IS TABLE OF emp.empno%TYPE INDEX BY BINARY_INTEGER;
t_empno EMPNO_TBL;
BEGIN
t_empno(1) := 9001;
t_empno(2) := 9002;
t_empno(3) := 9003;
FORALL i IN t_empno.FIRST..t_empno.LAST
DELETE FROM emp WHERE empno = t_empno(i);
END;
 
SELECT * FROM emp WHERE empno > 9000;
 
empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+-------+-----+-----+----------+-----+------+--------
(0 rows)
 
3.12.4 BULK COLLECT句の使用
多数の行からなる結果セットを返すSQLコマンドは、結果セット全体を転送するためにデータベースサーバとクライアントの間で行われなければならない定数的な切り替えのため、できるだけ効率的に動作しない可能性があります。この非効率性は、コレクションを使用して、クライアントがアクセスできるメモリー内の結果セット全体を収集することによって軽減できます。 BULK COLLECT句を使用して、結果セットの集約をコレクションに指定します。
BULK句収集 INTO FETCHIMMEDIATEコマンドを実行、DELETE、INSERT、およびUPDATEコマンドRETURNING INTO句で、SELECT INTOで使用することができます。これらのそれぞれについて以下のセクションで説明します。
3.12.4.1 SELECT BULK COLLECT
次のようにBULK COLLECT句は、SELECT INTO文で使用することができます。 SELECT INTO文の詳細は、 3.4.3項を参照してください。
SELECT select_expressions BULK COLLECT INTO collection
[, ...] FROM ...;
シングルコレクションが指定されている場合は、その コレクションは 、単一のフィールドの集合体であってもよいし、レコード型の集合であってもよいです。複数のコレクションが指定されている場合、各コレクションは単一のフィールドで構成されている必要があります。 select_expressionsは、ターゲットコレクション内のすべてのフィールドの番号、順序、型互換性が一致する必要があります。
次の例は、 BULK COLLECT句の使用方法を示しています。ここで、ターゲットコレクションは、単一のフィールドで構成される連想配列です。
DECLARE
TYPE empno_tbl IS TABLE OF emp.empno%TYPE INDEX BY BINARY_INTEGER;
TYPE ename_tbl IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;
TYPE job_tbl IS TABLE OF emp.job%TYPE INDEX BY BINARY_INTEGER;
TYPE hiredate_tbl IS TABLE OF emp.hiredate%TYPE INDEX BY BINARY_INTEGER;
TYPE sal_tbl IS TABLE OF emp.sal%TYPE INDEX BY BINARY_INTEGER;
TYPE comm_tbl IS TABLE OF emp.comm%TYPE INDEX BY BINARY_INTEGER;
TYPE deptno_tbl IS TABLE OF emp.deptno%TYPE INDEX BY BINARY_INTEGER;
t_empno EMPNO_TBL;
t_ename ENAME_TBL;
t_job JOB_TBL;
t_hiredate HIREDATE_TBL;
t_sal SAL_TBL;
t_comm COMM_TBL;
t_deptno DEPTNO_TBL;
BEGIN
SELECT empno, ename, job, hiredate, sal, comm, deptno BULK COLLECT
INTO t_empno, t_ename, t_job, t_hiredate, t_sal, t_comm, t_deptno
FROM emp;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME JOB HIREDATE ' ||
'SAL ' || 'COMM DEPTNO');
DBMS_OUTPUT.PUT_LINE('----- ------- --------- --------- ' ||
'-------- ' || '-------- ------');
FOR i IN 1..t_empno.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(t_empno(i) || ' ' ||
RPAD(t_ename(i),8) || ' ' ||
RPAD(t_job(i),10) || ' ' ||
TO_CHAR(t_hiredate(i),'DD-MON-YY') || ' ' ||
TO_CHAR(t_sal(i),'99,999.99') || ' ' ||
TO_CHAR(NVL(t_comm(i),0),'99,999.99') || ' ' ||
t_deptno(i));
END LOOP;
END;
 
EMPNO ENAME JOB HIREDATE SAL COMM DEPTNO
----- ------- --------- --------- -------- -------- ------
7369 SMITH CLERK 17-DEC-80 800.00 .00 20
7499 ALLEN SALESMAN 20-FEB-81 1,600.00 300.00 30
7521 WARD SALESMAN 22-FEB-81 1,250.00 500.00 30
7566 JONES MANAGER 02-APR-81 2,975.00 .00 20
7654 MARTIN SALESMAN 28-SEP-81 1,250.00 1,400.00 30
7698 BLAKE MANAGER 01-MAY-81 2,850.00 .00 30
7782 CLARK MANAGER 09-JUN-81 2,450.00 .00 10
7788 SCOTT ANALYST 19-APR-87 3,000.00 .00 20
7839 KING PRESIDENT 17-NOV-81 5,000.00 .00 10
7844 TURNER SALESMAN 08-SEP-81 1,500.00 .00 30
7876 ADAMS CLERK 23-MAY-87 1,100.00 .00 20
7900 JAMES CLERK 03-DEC-81 950.00 .00 30
7902 FORD ANALYST 03-DEC-81 3,000.00 .00 20
7934 MILLER CLERK 23-JAN-82 1,300.00 .00 10
次の例は、同じ結果を生成しますが、 %ROWTYPE属性で定義されたレコード・タイプに対して連想配列を 使用します。
DECLARE
TYPE emp_tbl IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
t_emp EMP_TBL;
BEGIN
SELECT * BULK COLLECT INTO t_emp FROM emp;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME JOB HIREDATE ' ||
'SAL ' || 'COMM DEPTNO');
DBMS_OUTPUT.PUT_LINE('----- ------- --------- --------- ' ||
'-------- ' || '-------- ------');
FOR i IN 1..t_emp.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(t_emp(i).empno || ' ' ||
RPAD(t_emp(i).ename,8) || ' ' ||
RPAD(t_emp(i).job,10) || ' ' ||
TO_CHAR(t_emp(i).hiredate,'DD-MON-YY') || ' ' ||
TO_CHAR(t_emp(i).sal,'99,999.99') || ' ' ||
TO_CHAR(NVL(t_emp(i).comm,0),'99,999.99') || ' ' ||
t_emp(i).deptno);
END LOOP;
END;
 
EMPNO ENAME JOB HIREDATE SAL COMM DEPTNO
----- ------- --------- --------- -------- -------- ------
7369 SMITH CLERK 17-DEC-80 800.00 .00 20
7499 ALLEN SALESMAN 20-FEB-81 1,600.00 300.00 30
7521 WARD SALESMAN 22-FEB-81 1,250.00 500.00 30
7566 JONES MANAGER 02-APR-81 2,975.00 .00 20
7654 MARTIN SALESMAN 28-SEP-81 1,250.00 1,400.00 30
7698 BLAKE MANAGER 01-MAY-81 2,850.00 .00 30
7782 CLARK MANAGER 09-JUN-81 2,450.00 .00 10
7788 SCOTT ANALYST 19-APR-87 3,000.00 .00 20
7839 KING PRESIDENT 17-NOV-81 5,000.00 .00 10
7844 TURNER SALESMAN 08-SEP-81 1,500.00 .00 30
7876 ADAMS CLERK 23-MAY-87 1,100.00 .00 20
7900 JAMES CLERK 03-DEC-81 950.00 .00 30
7902 FORD ANALYST 03-DEC-81 3,000.00 .00 20
7934 MILLER CLERK 23-JAN-82 1,300.00 .00 10
 
3.12.4.2 FETCH BULK COLLECT
BULK COLLECT句は、FETCH文で使用することができます。 ( FETCH文の詳細は、 3.8.3項を参照してください。) FETCH BULK COLLECTは、結果セットから一度に1つの行を戻す代わりに、結果セットからすべての行を指定されたコレクションに戻します。 LIMIT句。
FETCH name BULK COLLECT INTO collection [, ...] [ LIMIT n ];
シングルコレクションが指定されている場合は、その コレクションは 、単一のフィールドの集合体であってもよいし、レコード型の集合であってもよいです。複数のコレクションが指定されている場合、各コレクションは単一のフィールドで構成されている必要があります。 名前で識別されるカーソルのSELECTリスト内の式は、ターゲットコレクション内のすべてのフィールドの番号、順序、型互換性が一致する必要があります。 LIMIT nを指定すると、各FETCHのコレクションに戻される行の数はnを超えません。
次の例では、 FETCH BULK COLLECTステートメントを使用して行を連想配列に戻します。
DECLARE
TYPE emp_tbl IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
t_emp EMP_TBL;
CURSOR emp_cur IS SELECT * FROM emp;
BEGIN
OPEN emp_cur;
FETCH emp_cur BULK COLLECT INTO t_emp;
CLOSE emp_cur;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME JOB HIREDATE ' ||
'SAL ' || 'COMM DEPTNO');
DBMS_OUTPUT.PUT_LINE('----- ------- --------- --------- ' ||
'-------- ' || '-------- ------');
FOR i IN 1..t_emp.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(t_emp(i).empno || ' ' ||
RPAD(t_emp(i).ename,8) || ' ' ||
RPAD(t_emp(i).job,10) || ' ' ||
TO_CHAR(t_emp(i).hiredate,'DD-MON-YY') || ' ' ||
TO_CHAR(t_emp(i).sal,'99,999.99') || ' ' ||
TO_CHAR(NVL(t_emp(i).comm,0),'99,999.99') || ' ' ||
t_emp(i).deptno);
END LOOP;
END;
 
EMPNO ENAME JOB HIREDATE SAL COMM DEPTNO
----- ------- --------- --------- -------- -------- ------
7369 SMITH CLERK 17-DEC-80 800.00 .00 20
7499 ALLEN SALESMAN 20-FEB-81 1,600.00 300.00 30
7521 WARD SALESMAN 22-FEB-81 1,250.00 500.00 30
7566 JONES MANAGER 02-APR-81 2,975.00 .00 20
7654 MARTIN SALESMAN 28-SEP-81 1,250.00 1,400.00 30
7698 BLAKE MANAGER 01-MAY-81 2,850.00 .00 30
7782 CLARK MANAGER 09-JUN-81 2,450.00 .00 10
7788 SCOTT ANALYST 19-APR-87 3,000.00 .00 20
7839 KING PRESIDENT 17-NOV-81 5,000.00 .00 10
7844 TURNER SALESMAN 08-SEP-81 1,500.00 .00 30
7876 ADAMS CLERK 23-MAY-87 1,100.00 .00 20
7900 JAMES CLERK 03-DEC-81 950.00 .00 30
7902 FORD ANALYST 03-DEC-81 3,000.00 .00 20
7934 MILLER CLERK 23-JAN-82 1,300.00 .00 10
 
3.12.4.3 IMMEDIATE BULK COLLECTをEXECUTE
BULK COLLECT句は、返される行を受信するコレクションを指定するには、EXECUTE IMMEDIATE文で使用することができます。
EXECUTE IMMEDIATE ' sql_expression; '
BULK COLLECT INTO collection [,...]
[USING {[ bind _ type ] bind _ argument } [, ...]}];
collectionは、コレクションの名前を指定します。
bind_typeは のbind_argumentのパラメータ・モードを指定します。
INバインド _ タイプは、 バインドが _ 引数が SQL _ に渡された値が含まれていることを指定します。
OUTバインド _ タイプは、 バインドが _ 引数が SQL _ から値を受け取ることを指定します。
、IN OUTバインド _ タイプは のbind_argumentが sql_expressionに渡されることを指定し、SQL _ の戻り値を格納します。
bind_argumentは (INbind_typeで指定)sql_expressionに渡されたいずれかの値が含まれているパラメータを指定する、またはそれは、(OUTbind_typeで指定)sql_expressionから値を受け取り、またはその両方(INbind_typeで指定しますOUT )。
シングルコレクションが指定されている場合は、その コレクションは 、単一のフィールド、またはレコード型の集合の集合であってもよいです。複数のコレクションが指定されている場合、各コレクションは単一のフィールドで構成されている必要があります。
3.12.4.4 BULK COLLECTの返却
BULK COLLECT句は、DELETE、INSERT、またはUPDATEコマンドINTORETURNINGに添加することができます。 ( RETURNING INTO句の詳細は、 3.4.7項を参照してください。)
{ insert | update | delete }
RETURNING { * | expr_1 [, expr_2 ] ...}
BULK COLLECT INTO collection [, ...];
INSERTUPDATE 、およびDELETEコマンドは、 3.4.4項、 3.4.5項および3.4.6項でそれぞれ説明した挿入更新および削除です。シングルコレクションが指定されている場合は、そのコレクションは 、単一のフィールドの集合体であってもよいし、レコード型の集合であってもよいです。複数のコレクションが指定されている場合、各コレクションは単一のフィールドで構成されている必要があります。 RETURNINGキーワードの後に​​続く式は、ターゲットコレクション内のすべてのフィールドの数、順序、および型互換性で一致する必要があります。 *を指定すると、影響を受ける表のすべての列が戻されます。 (*の使用は、Advanced Serverの 拡張機能 であり 、Oracleデータベースと互換性が ない ことに注意してください 。)
以下に示すように、EMP表をコピーして作成したclerkempテーブルは、このセクションの残りの実施例で使用されています。
CREATE TABLE clerkemp AS SELECT * FROM emp WHERE job = 'CLERK';
 
SELECT * FROM clerkemp;
 
empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+--------+-------+------+--------------------+---------+------+--------
7369 | SMITH | CLERK | 7902 | 17-DEC-80 00:00:00 | 800.00 | | 20
7876 | ADAMS | CLERK | 7788 | 23-MAY-87 00:00:00 | 1100.00 | | 20
7900 | JAMES | CLERK | 7698 | 03-DEC-81 00:00:00 | 950.00 | | 30
7934 | MILLER | CLERK | 7782 | 23-JAN-82 00:00:00 | 1300.00 | | 10
(4 rows)
次の例では、全員の給与を1.5倍に増やし、従業員の番号、名前、および新しい給与を3つの連想配列に格納し、最後にこれらの配列の内容を表示します。
DECLARE
TYPE empno_tbl IS TABLE OF emp.empno%TYPE INDEX BY BINARY_INTEGER;
TYPE ename_tbl IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;
TYPE sal_tbl IS TABLE OF emp.sal%TYPE INDEX BY BINARY_INTEGER;
t_empno EMPNO_TBL;
t_ename ENAME_TBL;
t_sal SAL_TBL;
BEGIN
UPDATE clerkemp SET sal = sal * 1.5 RETURNING empno, ename, sal
BULK COLLECT INTO t_empno, t_ename, t_sal;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME SAL ');
DBMS_OUTPUT.PUT_LINE('----- ------- -------- ');
FOR i IN 1..t_empno.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(t_empno(i) || ' ' || RPAD(t_ename(i),8) ||
' ' || TO_CHAR(t_sal(i),'99,999.99'));
END LOOP;
END;
 
EMPNO ENAME SAL
----- ------- --------
7369 SMITH 1,200.00
7876 ADAMS 1,650.00
7900 JAMES 1,425.00
7934 MILLER 1,950.00
次の例では、前の例と同じ機能を実行しますが、レコード型で定義された単一のコレクションを使用して、従業員の番号、名前、および新しい給与を格納します。
DECLARE
TYPE emp_rec IS RECORD (
empno emp.empno%TYPE,
ename emp.ename%TYPE,
sal emp.sal%TYPE
);
TYPE emp_tbl IS TABLE OF emp_rec INDEX BY BINARY_INTEGER;
t_emp EMP_TBL;
BEGIN
UPDATE clerkemp SET sal = sal * 1.5 RETURNING empno, ename, sal
BULK COLLECT INTO t_emp;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME SAL ');
DBMS_OUTPUT.PUT_LINE('----- ------- -------- ');
FOR i IN 1..t_emp.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(t_emp(i).empno || ' ' ||
RPAD(t_emp(i).ename,8) || ' ' ||
TO_CHAR(t_emp(i).sal,'99,999.99'));
END LOOP;
END;
 
EMPNO ENAME SAL
----- ------- --------
7369 SMITH 1,200.00
7876 ADAMS 1,650.00
7900 JAMES 1,425.00
7934 MILLER 1,950.00
次の例では、 clerkempからすべての行を削除し、削除された行の情報を連想配列に戻して表示します。
DECLARE
TYPE emp_rec IS RECORD (
empno emp.empno%TYPE,
ename emp.ename%TYPE,
job emp.job%TYPE,
hiredate emp.hiredate%TYPE,
sal emp.sal%TYPE,
comm emp.comm%TYPE,
deptno emp.deptno%TYPE
);
TYPE emp_tbl IS TABLE OF emp_rec INDEX BY BINARY_INTEGER;
r_emp EMP_TBL;
BEGIN
DELETE FROM clerkemp RETURNING empno, ename, job, hiredate, sal,
comm, deptno BULK COLLECT INTO r_emp;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME JOB HIREDATE ' ||
'SAL ' || 'COMM DEPTNO');
DBMS_OUTPUT.PUT_LINE('----- ------- --------- --------- ' ||
'-------- ' || '-------- ------');
FOR i IN 1..r_emp.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(r_emp(i).empno || ' ' ||
RPAD(r_emp(i).ename,8) || ' ' ||
RPAD(r_emp(i).job,10) || ' ' ||
TO_CHAR(r_emp(i).hiredate,'DD-MON-YY') || ' ' ||
TO_CHAR(r_emp(i).sal,'99,999.99') || ' ' ||
TO_CHAR(NVL(r_emp(i).comm,0),'99,999.99') || ' ' ||
r_emp(i).deptno);
END LOOP;
END;
 
EMPNO ENAME JOB HIREDATE SAL COMM DEPTNO
----- ------- --------- --------- -------- -------- ------
7369 SMITH CLERK 17-DEC-80 1,200.00 .00 20
7876 ADAMS CLERK 23-MAY-87 1,650.00 .00 20
7900 JAMES CLERK 03-DEC-81 1,425.00 .00 30
7934 MILLER CLERK 23-JAN-82 1,950.00 .00 10
3.13 エラーとメッセージ
メッセージを報告 するには、 DBMS_OUTPUT.PUT_LINE 文を 使用し ます。
DBMS_OUTPUT.PUT_LINE ( message );
messageは、文字列に評価される任意の式です。
この例では、ユーザーの出力ディスプレイにメッセージを表示します。
DBMS_OUTPUT.PUT_LINE('My name is John');
特殊変数 SQLCODE および SQLERRMに は、最後に 発行された SQL コマンドの 結果を記述する数値コードおよびテキスト・メッセージがそれぞれ含まれています 。ゼロ除算のような他のエラーがプログラムで発生した場合、これらの変数にはエラーに関する情報が含まれます。
4 トリガ
この章では Advanced Serverの トリガ について説明 ます 。プロシージャと関数と同様に、トリガは SPL 言語で 記述され ます。
4.1 概要
トリガーは、 テーブルに関連付けられてデータベースに格納され た名前付き SPL コードブロックです。関連するテーブルで指定されたイベントが発生すると、 SPL コードブロックが実行されます。トリガは 、コードブロックが実行されとき 起動 されると言われます
トリガを発生させるイベントは、直接または間接的にテーブル上で実行される挿入、更新、または削除の任意の組み合わせです。表が SQLの INSERTUPDATEまたはDELETEコマンドのオブジェクトである場合、対応する挿入イベント、更新イベントまたは削除イベントがトリガー・イベントとして定義されていると仮定して、トリガーが直接起動されます。トリガを起動するイベントは、 CREATE TRIGGERコマンドで定義します。
別の表で開始されたイベントの結果として表上でトリガー・イベントが発生すると、間接的にトリガーを起動することができます。たとえば、 ON DELETE CASCADE句で定義された外部キーを含む表にトリガーが定義され 、親表の行が削除されると、親の子もすべて削除されます。削除が子テーブルのトリガイベントである場合、子を削除するとトリガが発生します。
4.2 トリガの種類
Advanced Server は、 行レベル 文レベルの トリガーの 両方をサポートし ます。行レベルのトリガーは、トリガー・イベントの影響を受ける行ごとに1回発生します。たとえば、削除が表のトリガー・イベントとして定義され、表から5つの行を削除する1つの DELETEコマンドが発行された場合、トリガーは各行に対して1回5回起動します。
対照的に、ステートメント・レベル・トリガーは、トリガー・イベントの影響を受ける行の数に関係なく、トリガー・ステートメントごとに1回起動します。以前の 5つの行を削除するDELETEコマンドの例では 、文レベルのトリガーは1回だけ起動します。
アクションのシーケンスは、トリガーコードブロックがトリガーステートメントの前または後に実行されるかどうか、ステートメントレベルトリガーの場合はそれ自体で定義できます。または各行の前後に、行レベルのトリガーの場合はトリガー文の影響を受けます。
トリガーアクションが影響を受ける各列に対して実行される前に、 前にロー・レベル・トリガ、トリガコードブロックが実行されます。 before文レベル・トリガーでは、トリガー・コード・ブロックは、トリガー・ステートメントのアクションが実行される前に実行されます。
トリガーアクションが影響を受ける各列に対して行われた後、行レベルのトリガ後に 、トリガコードブロックが実行されます。 afterステートメント・レベル・トリガーでは、トリガー・コード・ブロックは、トリガー・ステートメントのアクションが実行された後に実行されます。
4.3 トリガの作成
TRIGGER コマンド定義と名称データベースに格納されるトリガーを 作成
CREATE TRIGGER - 新しいトリガーを定義する
シノプシス
CREATE [OR REPLACE]トリガ
{BEFORE |アフター|の代わりに }
{INSERT |更新| DELETE}
[OR {INSERT |更新| DELETE}] [、...]
ON テーブル
[ 古いものとして古い { NEW AS new } ...]
[各行に対して]
[ 条件 ]
[DECLARE
[PRAGMA AUTONOMOUS_TRANSACTION; ]
宣言 ; [、...]]
ベギン
声明 ; [、...]
[例外
{ 例外 [OR 例外 ] [...] THEN
声明 ; [、...]} [、...]
]
終わり
説明
CREATE TRIGGERは新しいトリガーを定義します。 CREATE OR REPLACE TRIGGERは新しいトリガーを作成するか、既存の定義を置き換えます。
あなたが使用している場合、新しいトリガを作成するには、CREATE TRIGGERのキーワードを、新しいトリガの名前が同じテーブルに定義されている既存のトリガーと一致してはいけません。新しいトリガーは、トリガー・イベントが定義されている表と同じスキーマに作成されます。
既存のトリガーの定義を更新する場合は、 CREATE OR REPLACE TRIGGERキーワードを使用します。
Oracleデータベースと互換性のある構文を使用してトリガーを作成すると、トリガーは SECURITY DEFINER関数として実行されます。
 
 
パラメーター
作成するトリガーの名前。
前に|アフター
トリガーがトリガーイベントの前または後に発生するかどうかを決定します。
INSERT |更新|削除
トリガーイベントを定義します。
トリガイベントが発生するテーブルの名前。
調子
conditionはトリガーが実際に実行されるかどうかを決定するブール式です。 conditionTRUEと評価された場合、トリガが起動します。
トリガ定義に FOR EACH ROWキーワードが含まれている場合、 WHEN句はOLDを記述して古い行および/または新しい行の値の列を参照できます。 _ 名前またはNEW _ 名をそれぞれ指定します。 INSERTトリガーはOLDを参照できず、 DELETEトリガーはNEWを参照できません。
トリガーに INSTEAD OFキーワードが含まれている場合は、 WHEN句が含まれていない可能性があります。
WHEN句にサブクエリを含めることはできません。
古いものとして古いものを 参照する | NEW AS 新しいです } ...
REFERENCING節は古い行と新しい行を参照しますが、 oldoldやそれ以外のすべての小文字で保存された識別子で置き換えられます(たとえば、 REFERENCING OLD AS oldREFERENCING OLD AS OLDREFERENCING OLD AS "古い" )。また、 新しいだけ (例えば、NEW AS NEWを参照する新しいAS NEWを参照する、「新しい」としてNEWを参照新しい名前付き識別子またはすべて小文字に保存されている任意の等価に置き換えることができます。
OLD AS oldおよびNEW AS newの いずれか、または両方を REFERENCING節に指定することができます(たとえば、 REFERENCING NEW AS OLD AS NEWと同様にREFERENCING )。
これらの識別子が古い行と新しい行を参照するための疑似レコード名としてどのように使用されるかについては、 3.4 項を参照してください
それ以外の識別子でこの句は、Oracleデータベースと互換性がありません 新旧使用することはできません。
行ごとに
トリガイベントの影響を受けるすべての行に対してトリガを1回実行するか、 SQLごとに1回だけトリガするかを決定し ます 。指定すると、トリガーは影響を受けた各行(行レベルのトリガー)ごとに1回起動されます。それ以外の場合は、トリガーはステートメントレベルのトリガーです。
PRAGMA AUTONOMOUS_TRANSACTION
PRAGMA AUTONOMOUS_TRANSACTIONは、トリガーを自律型トランザクションとして設定するディレクティブです。
宣言
変数、型、 REF CURSOR 、またはサブプログラムの宣言。 サブプログラム宣言が含まれている場合は、他のすべての変数、型、および REF CURSOR 宣言の 後に宣言する必要があり ます
ステートメント
SPLプログラム文です。 DECLARE-BEGIN-ENDブロックはSPLステートメントとみなされます。したがって、トリガー本体にネストされたブロックが含まれることがあります。
例外
NO_DATA_FOUNDOTHERS などの例外条件名
4.4 トリガ変数
トリガコードブロックでは、いくつかの特殊変数を使用できます。
新しい
NEWは、疑似レコード名で、行レベルのトリガーでの挿入操作と更新操作の新​​しい表行を指します。この変数は、文レベルのトリガーおよび行レベルのトリガーの削除操作には適用されません。
その使用法は次の とおりです。 :NEWカラムは、トリガが定義されているテーブルの列の名前である
の最初の内容 :NEWは、挿入される新しい行の名前付き列の値です。行レベルの前のトリガーで使用された場合は、新しい行の名前が古い行を置き換えます。行レベルの後のトリガーで使用すると、影響を受けた行ですでにアクションが発生しているため、この値はすでに表に保管されています。
トリガコードブロックでは、 :NEW列は、他の変数と同様に使用することができます。値がNEWに割り当てられている場合。 列は 、前の行レベルトリガのコードブロックに、割り当てられた値は、新たな挿入または更新された行で使用されます。
古い
OLDは、行レベル・トリガーの更新および削除操作のために古い表の行を参照する擬似レコード名です。この変数は、文レベルのトリガーおよび行レベルのトリガーの挿入操作には適用されません。
その使用法は:: OLDカラムは、トリガが定義されているテーブルの列の名前である
初期の内容 :OLDcolumnは、削除される行の指定された列の値、または行レベルの前のトリガーで使用されたときに新しい行に置き換えられる古い行の値です。行レベル・トリガー後に使用すると、影響を受けた行ですでにアクションが発生しているため、この値は表に保管されなくなります。
トリガーコードブロックでは :OLD列は、他の変数と同様に使用することができます。値の割り当て:OLDは、トリガの動作に影響を与えません。
挿入
INSERTING は、 挿入操作によってトリガーが発生した場合 true を戻す条件式です それ以外の場合は falseを 戻し ます
更新
UPDATING は、 更新操作によってトリガが発生した場合 true を返す条件式です それ以外の場合は falseを 返し ます
削除中
DELETING は、 削除操作によってトリガーが発生した場合 true を戻す条件式で 、そうでない場合は falseを 戻し ます
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4.5 トランザクションと例外
トリガーは、トリガー・ステートメントが実行されている同じトランザクションの一部として常に実行されます。トリガー・コード・ブロック内で例外が発生しない場合、トリガー・ステートメントを含むトランザクションがコミットされている場合にのみ、トリガー内のDMLコマンドの影響がコミットされます。したがって、トランザクションがロールバックされると、トリガー内のDMLコマンドの影響もロールバックされます。
トリガ・コード・ブロック内で例外が発生したが例外セクションでキャッチされて処理された場合でも、トリガ内のDMLコマンドの影響は引き続きロールバックされます。ただし、トリガー・ステートメント自体は、アプリケーションがカプセル化トランザクションのロールバックを強制しない限り、ロールバックされません。
トリガーコードブロック内で未処理の例外が発生すると、トリガーをカプセル化するトランザクションは中止され、ロールバックされます。したがって、トリガー内のDMLコマンドおよびトリガー・ステートメント自体の影響は、すべてロールバックされます。
4.6 トリガの例
次のセクションでは、トリガの各タイプの例を示します。
4.6.1 ステートメント・レベル・トリガーの前
以下は、 emp への挿入操作の前にメッセージを表示する、単純なbeforeステートメント・レベル・トリガーの例です
CREATE OR REPLACE TRIGGER emp_alert_trig
BEFORE INSERT ON emp
BEGIN
DBMS_OUTPUT.PUT_LINE('New employees are about to be added');
END;
次の INSERT は、コマンドの1回の実行時にいくつかの新しい行が挿入されるように構成されています。従業員IDが7900〜7999の行ごとに、従業員IDを1000ずつ増やした新しい行が挿入されます。次に、3つの新しい行が挿入されたときにコマンドを実行した結果を示します。
INSERT INTO emp (empno, ename, deptno) SELECT empno + 1000, ename, 40
FROM emp WHERE empno BETWEEN 7900 AND 7999;
New employees are about to be added
 
SELECT empno, ename, deptno FROM emp WHERE empno BETWEEN 8900 AND 8999;
 
EMPNO ENAME DEPTNO
---------- ---------- ----------
8900 JAMES 40
8902 FORD 40
8934 MILLER 40
新規従業員を追加しようとしている というメッセージは 、結果が3つの新しい行 が追加され ているにも関わらず、トリガーの起動によって1回表示されます。
4.6.2 ステートメント・レベル・トリガーの後
以下は、ステートメント・レベルのトリガー後の例です。 emp に対して挿入操作、更新操作、または削除操作が行われるたびに、 日付、ユーザー、およびアクションを記録 する行が empauditlog 表に 追加され ます。
CREATE TABLE empauditlog (
audit_date DATE,
audit_user VARCHAR2(20),
audit_desc VARCHAR2(20)
);
CREATE OR REPLACE TRIGGER emp_audit_trig
AFTER INSERT OR UPDATE OR DELETE ON emp
DECLARE
v_action VARCHAR2(20);
BEGIN
IF INSERTING THEN
v_action := 'Added employee(s)';
ELSIF UPDATING THEN
v_action := 'Updated employee(s)';
ELSIF DELETING THEN
v_action := 'Deleted employee(s)';
END IF;
INSERT INTO empauditlog VALUES (SYSDATE, USER,
v_action);
END;
次の一連のコマンドでは、2 つの INSERT コマンド を使用 して emp テーブル に2つの行が挿入され ます。 両方の行 sal および comm 列は、1つの UPDATE コマンドで 更新され ます。最後に、両方の行が1つの DELETE コマンドで 削除され ます。
INSERT INTO emp VALUES (9001,'SMITH','ANALYST',7782,SYSDATE,NULL,NULL,10);
 
INSERT INTO emp VALUES (9002,'JONES','CLERK',7782,SYSDATE,NULL,NULL,10);
 
UPDATE emp SET sal = 4000.00, comm = 1200.00 WHERE empno IN (9001, 9002);
 
DELETE FROM emp WHERE empno IN (9001, 9002);
 
SELECT TO_CHAR(AUDIT_DATE,'DD-MON-YY HH24:MI:SS') AS "AUDIT DATE",
audit_user, audit_desc FROM empauditlog ORDER BY 1 ASC;
 
AUDIT DATE AUDIT_USER AUDIT_DESC
------------------ -------------------- --------------------
31-MAR-05 14:59:48 SYSTEM Added employee(s)
31-MAR-05 15:00:07 SYSTEM Added employee(s)
31-MAR-05 15:00:19 SYSTEM Updated employee(s)
31-MAR-05 15:00:34 SYSTEM Deleted employee(s)
empauditlog の内容には 、トリガーが2回挿入された回数、1回更新(2回の行が変更された場合でも)および削除の1回(2つの行が削除された場合でも)に発生した回数が示されます。
4.6.3 行レベル・トリガーの前
次の例は、 emp 表に 挿入された部門30に属するすべての新しい従業員の手数料を計算する前の行レベル・トリガーです
CREATE OR REPLACE TRIGGER emp_comm_trig
BEFORE INSERT ON emp
FOR EACH ROW
BEGIN
IF :NEW.deptno = 30 THEN
:NEW.comm := :NEW.sal * .4;
END IF;
END;
2人の従業員を追加した後のリスティングは、トリガーがそのコミッションを計算し、それを新しい従業員の行の一部として挿入したことを示しています。
INSERT INTO emp VALUES (9005,'ROBERS','SALESMAN',7782,SYSDATE,3000.00,NULL,30);
 
INSERT INTO emp VALUES (9006,'ALLEN','SALESMAN',7782,SYSDATE,4500.00,NULL,30);
 
SELECT * FROM emp WHERE empno IN (9005, 9006);
 
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
9005 ROBERS SALESMAN 7782 01-APR-05 3000 1200 30
9006 ALLEN SALESMAN 7782 01-APR-05 4500 1800 30
4.6.4 行レベル・トリガーの後
次の例は、行レベルの後のトリガーです。新しい従業員の行が挿入されると、 その従業員の 求職者 テーブルに 新しい行が追加され ます。既存の従業員が更新されると、トリガーは、 現在の日付に (ヌル 終了日 と1とする 最新の JOBHIST ENDDATE 設定 し、従業員の新しい情報で新しい JOBHIST行を挿入します。
最後に、triggerは empchglogテーブルにのアクションの説明を追加します
CREATE TABLE empchglog (
chg_date DATE,
chg_desc VARCHAR2(30)
);
CREATE OR REPLACE TRIGGER emp_chg_trig
AFTER INSERT OR UPDATE OR DELETE ON emp
FOR EACH ROW
DECLARE
v_empno emp.empno%TYPE;
v_deptno emp.deptno%TYPE;
v_dname dept.dname%TYPE;
v_action VARCHAR2(7);
v_chgdesc jobhist.chgdesc%TYPE;
BEGIN
IF INSERTING THEN
v_action := 'Added';
v_empno := :NEW.empno;
v_deptno := :NEW.deptno;
INSERT INTO jobhist VALUES (:NEW.empno, SYSDATE, NULL,
:NEW.job, :NEW.sal, :NEW.comm, :NEW.deptno, 'New Hire');
ELSIF UPDATING THEN
v_action := 'Updated';
v_empno := :NEW.empno;
v_deptno := :NEW.deptno;
v_chgdesc := '';
IF NVL(:OLD.ename, '-null-') != NVL(:NEW.ename, '-null-') THEN
v_chgdesc := v_chgdesc || 'name, ';
END IF;
IF NVL(:OLD.job, '-null-') != NVL(:NEW.job, '-null-') THEN
v_chgdesc := v_chgdesc || 'job, ';
END IF;
IF NVL(:OLD.sal, -1) != NVL(:NEW.sal, -1) THEN
v_chgdesc := v_chgdesc || 'salary, ';
END IF;
IF NVL(:OLD.comm, -1) != NVL(:NEW.comm, -1) THEN
v_chgdesc := v_chgdesc || 'commission, ';
END IF;
IF NVL(:OLD.deptno, -1) != NVL(:NEW.deptno, -1) THEN
v_chgdesc := v_chgdesc || 'department, ';
END IF;
v_chgdesc := 'Changed ' || RTRIM(v_chgdesc, ', ');
UPDATE jobhist SET enddate = SYSDATE WHERE empno = :OLD.empno
AND enddate IS NULL;
INSERT INTO jobhist VALUES (:NEW.empno, SYSDATE, NULL,
:NEW.job, :NEW.sal, :NEW.comm, :NEW.deptno, v_chgdesc);
ELSIF DELETING THEN
v_action := 'Deleted';
v_empno := :OLD.empno;
v_deptno := :OLD.deptno;
END IF;
 
INSERT INTO empchglog VALUES (SYSDATE,
v_action || ' employee # ' || v_empno);
END;
以下に示す最初のコマンドシーケンスでは、2人の従業員が2つの別々の INSERT コマンド を使用して追加され 、その後両方とも1つの UPDATE コマンド を使用して更新され ます。 求職者 テーブル の内容には、 影響を受けた各行のトリガーアクションが表示されます.2人の新しい従業員の2つの新しい雇用エントリと、2人の従業員の更新されたコミッションの2つの変更されたコミッションレコードです。また、 empchglog 表には、トリガーが合計で4回発射されたことが示されています。
INSERT INTO emp VALUES (9003,'PETERS','ANALYST',7782,SYSDATE,5000.00,NULL,40);
 
INSERT INTO emp VALUES (9004,'AIKENS','ANALYST',7782,SYSDATE,4500.00,NULL,40);
 
UPDATE emp SET comm = sal * 1.1 WHERE empno IN (9003, 9004);
 
SELECT * FROM jobhist WHERE empno IN (9003, 9004);
 
EMPNO STARTDATE ENDDATE JOB SAL COMM DEPTNO CHGDESC
---------- --------- --------- --------- ---------- ---------- ---------- -------------
9003 31-MAR-05 31-MAR-05 ANALYST 5000 40 New Hire
9004 31-MAR-05 31-MAR-05 ANALYST 4500 40 New Hire
9003 31-MAR-05 ANALYST 5000 5500 40 Changed commission
9004 31-MAR-05 ANALYST 4500 4950 40 Changed commission
 
SELECT * FROM empchglog;
 
CHG_DATE CHG_DESC
--------- ------------------------------
31-MAR-05 Added employee # 9003
31-MAR-05 Added employee # 9004
31-MAR-05 Updated employee # 9003
31-MAR-05 Updated employee # 9004
最後に、両方の従業員が1つの DELETE コマンドで 削除され ます。 empchglog テーブルは現在、トリガーが削除された各従業員のために1回、2回解雇された示しています。
DELETE FROM emp WHERE empno IN (9003, 9004);
 
SELECT * FROM empchglog;
 
CHG_DATE CHG_DESC
--------- ------------------------------
31-MAR-05 Added employee # 9003
31-MAR-05 Added employee # 9004
31-MAR-05 Updated employee # 9003
31-MAR-05 Updated employee # 9004
31-MAR-05 Deleted employee # 9003
31-MAR-05 Deleted employee # 9004
5 パッケージ
Advanced Serverは、Oracleパッケージとの互換性を提供するパッケージのコレクションを提供します
パッケージ識別子- パッケージは 一般的な修飾子を使用して参照されている関数、プロシージャ、変数、カーソル、ユーザー定義のレコードタイプ、およびレコードの名前付きコレクションです。 パッケージには次の特徴があります。
パッケージ内の特定の関数、プロシージャ、変数、型などは public として宣言できます 。パブリック・エンティティーは表示され、パッケージに対するEXECUTE特権が与えられている他のプログラムから参照できます。パブリック関数とプロシージャーの場合、プログラム名、パラメーター(存在する場合)、関数の戻り値のタイプのみが表示されます。これらのファンクションとプロシージャのSPLコードには他人からアクセスできないため、パッケージを利用するアプリケーションは、手続き型ロジック自体ではなく、シグネチャで利用可能な情報のみに依存します。
パッケージ内の他の関数、手続き、変数、型などは private として宣言することができます 。プライベートエンティティは、パッケージ内の関数とプロシージャによって参照され使用されますが、他の外部アプリケーションでは参照および使用されません。プライベートエンティティは、パッケージ内のプログラムによってのみ使用されます。
Advanced Serverによって提供されるパッケージのサポートの詳細については 、次のサイトにある「Oracle Developerのビルトインパッケージ データベース互換性」 を参照してください
https://www.enterprisedb.com/resources/product-documentation
組み込みパッケージのリストについては、「 Oracle Developerの組み込みパッケージのため データベース互換性 」の第3章「組み込みパッケージ」から始まる目次を参照してください
6 オブジェクトの種類とオブジェクト
この章では、オブジェクト指向プログラミング手法を SPLで どのように活用できるかについて説明します 。 JavaやC ++などのプログラミング言語に見られるオブジェクト指向プログラミングは、オブジェクトの概念を中心にしています。 オブジェクトは、人、場所、物などの実世界のエンティティの表現です。例えば、人物などの特定のオブジェクトの一般的な記述または定義は、 オブジェクトタイプと呼ばれる。 「ジョー」や「サリー」などの特定の人物は、オブジェクトタイプ 、人物、またはそれと同等にオブジェクトタイプ、人物、または単に人物オブジェクトのインスタンスであると言われています。
注:この時点までにこの文書で使用されていた「データベースオブジェクト」および「オブジェクト」という用語を、この章で使用されているオブジェクトタイプおよびオブジェクトと混同しないでください。これらの用語の以前の使用法は、表、ビュー、索引、ユーザーなどのデータベースに作成できるエンティティに関連しています。この章では、オブジェクト型およびオブジェクトは、 SPLプログラミングでサポートされる特定のデータ構造を参照しますオブジェクト指向の概念を実装するための言語です。
注意: Oracleでは、PL / SQLのオブジェクト型を記述するために抽象データ型 (ADT)という用語が使用されています。オブジェクト型のSPL実装は、Oracle抽象データ型との互換性を目的としています。
注: Advanced Serverは、オブジェクト指向プログラミング言語のいくつかの機能をまだサポートしていません。この章では、実装されている機能についてのみ説明します。
6.1 基本的なオブジェクトの概念
オブジェクト型は、あるエンティティの記述または定義です。このオブジェクト型の定義は、次の2つのコンポーネントによって特徴付けられます。
属性 - オブジェクトインスタンスの特定の特性を記述するフィールド。人物の場合、名前、住所、性別、生年月日、身長、体重、目の色、職業などがその例です。
メソッド - オブジェクトに対して何らかのタイプの機能または操作を実行するプログラム、またはオブジェクトに関連するプログラム。 personオブジェクトの場合、その例は、その人の年齢の計算、personの属性の表示、personの属性に割り当てられた値の変更などです。
以下のセクションでは、基本的なオブジェクトの概念について詳しく説明します。
6.1.1 属性
すべてのオブジェクトタイプには少なくとも1つの属性が含まれていなければなりません。属性のデータ型は、次のいずれかになります。
NUMBERVARCHAR2 などの基本データ型
ネストした表またはVARRAYなど、グローバルに定義されたコレクション型( CREATE TYPEコマンドで作成
オブジェクトインスタンスが最初に作成されるときに、属性はその初期値(nullの可能性があります)を取得します。各オブジェクトインスタンスには、独自の属性値セットがあります。
6.1.2 メソッド
メソッドは、オブジェクト・タイプ内で定義されたSPLプロシージャーまたは関数です。メソッドは、3つの一般的なタイプに分類できます。
メンバメソッド - オブジェクトインスタンスのコンテキスト内で動作するプロシージャまたは関数。メンバメソッドは、それらが動作しているオブジェクトインスタンスの属性にアクセスし、変更することができます。
静的メソッド - 特定のオブジェクトインスタンスとは独立して動作するプロシージャまたは関数。静的メソッドは、オブジェクトインスタンスの属性にアクセスすることはできず、オブジェクトインスタンスの属性を変更することもできません。
コンストラクタメソッド - オブジェクト型のインスタンスを作成するために使用される関数。オブジェクト型が定義されると、デフォルトのコンストラクタメソッドが常に提供されます。
6.1.3 オーバーロードメソッド
オブジェクト型では、同じ型(これはプロシージャーまたは関数のいずれか)の同じ名前のメソッドを2つ以上定義できますが、異なるシグニチャーを使用することは許されます。そのようなメソッドは、 オーバーロードされたメソッドと呼ばれます。
メソッドのシグネチャは、仮パラメータの数、仮パラメータのデータ型、およびその順序で構成されます。
6.2 オブジェクト型コンポーネント
オブジェクト型は、 SPL言語の次の2つの構文を使用して作成され、データベースに格納されます
オブジェクトタイプの仕様 -これは、オブジェクト・タイプの属性およびメソッドのシグネチャを特定するパブリックインターフェースです。
オブジェクト型体 -これオブジェクトタイプの仕様で指定されたメソッドの実装を含んでいます。
以下のセクションでは、オブジェクト型の指定およびオブジェクト型の本体の作成に使用されるコマンドについて説明します。
6.2.1 オブジェクト型の仕様構文
オブジェクト型指定の構文は次のとおりです。
CREATE [ OR REPLACE ] TYPE name
[ AUTHID { DEFINER | CURRENT_USER } ]
{ IS | AS } OBJECT
( { attribute { datatype | objtype | collecttype } }
[, ...]
[ method_spec ] [, ...]
[ constructor ] [, ...]
) [ [ NOT ] { FINAL | INSTANTIABLE } ] ...;
ここで、 method_specは次のとおりです。
[ [ NOT ] { FINAL | INSTANTIABLE } ] ...
[ OVERRIDING ]
subprogram_spec
ここで、 subprogram_specは次のとおりです。
{ MEMBER | STATIC }
{ PROCEDURE proc_name
[ ( [ SELF [ IN | IN OUT ] name ]
[, parm1 [ IN | IN OUT | OUT ] datatype1
[ DEFAULT value1 ] ]
[, parm2 [ IN | IN OUT | OUT ] datatype2
[ DEFAULT value2 ]
] ...)
]
|
FUNCTION func_name
[ ( [ SELF [ IN | IN OUT ] name ]
[, parm1 [ IN | IN OUT | OUT ] datatype1
[ DEFAULT value1 ] ]
[, parm2 [ IN | IN OUT | OUT ] datatype2
[ DEFAULT value2 ]
] ...)
]
RETURN return_type
}
ここで コンストラクタは次のとおりです。
 
CONSTRUCTOR func_name
[ ( [ SELF [ IN | IN OUT ] name ]
[, parm1 [ IN | IN OUT | OUT ] datatype1
[ DEFAULT value1 ] ]
[, parm2 [ IN | IN OUT | OUT ] datatype2
[ DEFAULT value2 ]
] ...)
]
RETURN self AS RESULT
 
注: 現在、 OR REPLACE オプションを使用して 、既存のオブジェクト型の属性を追加、削除、または変更することはできません 。既存のオブジェクトタイプを最初に削除するには、 DROP TYPEコマンドを使用します。 OR REPLACEオプションを使用すると、既存のオブジェクト型のメソッドを追加、削除、または変更できます。
注: PostgreSQL形式のALTER TYPE ALTER ATTRIBUTEコマンドを使用すると、既存のオブジェクト型の属性のデータ型を変更できます。ただし、 ALTER TYPEコマンドはオブジェクト型の属性を追加または削除できません。
nameは、オブジェクト型に割り当てられた識別子(オプションでスキーマ修飾名)です。
場合 AUTHID が省略されているか DEFINERが 指定されている、オブジェクト型の所有者の権利は、データベース・オブジェクトへのアクセス権限を決定するために使用されています。 CURRENT_USERが 指定されている 場合 、オブジェクトにメソッドを実行し、現在のユーザーの権限は、アクセス権限を決定するために使用されます
属性は、オブジェクト型の属性に割り当てられた識別子です。
datatypeは基本データ型です。
objtypeは、以前に定義されたオブジェクト型です。
collecttypeは、以前に定義されたコレクション型です。
CREATE TYPE定義の閉じ括弧に続いて[NOT] FINALは、このオブジェクト型からサブタイプを派生できるかどうかを指定します。デフォルトのFINALは、このオブジェクト型からサブタイプを派生できないことを意味します。このオブジェクト型でサブタイプを定義できるようにする場合は、 NOT FINALを指定します。
注: NOT FINALの指定がCREATE TYPEコマンドで受け入れられても、SPLは現時点ではサブタイプの作成をサポートしていません。
[NOT] INSTANTIABLE は、 CREATE TYPE定義の閉じ括弧の後に、このオブジェクト型のオブジェクトインスタンスを作成できるかどうかを指定します。 INSTANTIABLE (デフォルト)は、このオブジェクト型のインスタンスを作成できることを意味します。このオブジェクトタイプが、他の特殊なサブタイプを定義する親 "テンプレート"としてのみ使用される場合は、 NOT INSTANTIABLEを指定します。 NOT INSTANTIABLEが指定されている場合は、 NOT FINALも指定する必要があります。オブジェクト型のいずれかのメソッドにNOT INSTANTIABLE修飾子が含まれている場合、オブジェクト型自体はNOT INSTANTIABLEおよびNOT FINALで定義する必要があります。
注: NOT INSTANTIABLEの指定CREATE TYPEコマンドで受け入れられても、SPLは現時点ではサブタイプの作成をサポートしていません。
method_specは、メンバメソッドまたは静的メソッドの指定を示します。
メソッドの定義の前に、 [NOT] FINALは、そのメソッドがサブタイプでオーバーライドできるかどうかを指定します。 NOT FINALは、メソッドがサブタイプでオーバーライドできるデフォルトの意味です。
メソッドの定義の前に、メソッドがスーパータイプ内の同じ名前のメソッドをオーバーライドする場合は、 OVERRIDINGを 指定します 。オーバーライドするメソッドは、同一のデータ型とパラメーター・モードを持つ同名のメソッド・パラメーターと同じ数の同じ順序で、スーパー・タイプで定義されている同じ戻りタイプ(メソッドが関数の場合)を持たなければなりません。
メソッドの定義の前に、 [NOT] INSTANTIABLEは、オブジェクト型定義がメソッドの実装を提供するかどうかを指定します。 INSTANTIABLEが指定されている場合、オブジェクト型のCREATE TYPE BODYコマンドは、メソッドの実装を指定する必要があります。 NOT INSTANTIABLEが指定されている場合、オブジェクト型のCREATE TYPE BODYコマンドにメソッドの実装が含まれていてはなりません。後者の場合、このオブジェクト型のメソッドをオーバーライドして、サブタイプにメソッドの実装が含まれているとみなされます。オブジェクト型にNOT INSTANTIABLEメソッドがある場合、オブジェクト型定義自体は、オブジェクト型指定の終了括弧の後にNOT INSTANTIABLEおよびNOT FINALを指定する必要があります。デフォルトはINSTANTIABLEです。
subprogram_specは、手続きまたは関数の指定を表し、 MEMBERまたはSTATICのいずれかの指定で始まります。特定のオブジェクト・インスタンスに対してメンバ・サブプログラムを起動する必要がありますが、静的サブプログラムは任意のオブジェクト・インスタンスに対して起動しません。
proc_nameはプロシージャの識別子です。 SELFパラメーターが指定されている場合、 nameCREATE TYPEコマンドで指定されたオブジェクト・タイプ名です。指定すると、 parm1parm2 、...はプロシージャの仮パラメータです。 datatype1datatype2 、...はそれぞれparm1parm2 、...のデータ型です。 ININ OUT 、およびOUTは、各仮パラメータの可能なパラメータ・モードです。指定されていない場合、デフォルトはINです。 value1value2 、...はINパラメータに指定できるデフォルト値です。
コンストラクタ関数を定義するには CONSTRUCTOR キーワードと関数定義を 含めます
func_name は関数の識別子です。 SELF パラメーターが指定されている 場合 name CREATE TYPE コマンドで 指定され たオブジェクト・タイプ名 です。指定すると、 parm1 parm2 、...は関数の仮パラメータです。 datatype1datatype2 、...はそれぞれparm1parm2 、...のデータ型です。 ININ OUT 、およびOUTは、各仮パラメータの可能なパラメータ・モードです。指定されていない場合、デフォルトはINです。 value1value2 、...はINパラメータに指定できるデフォルト値です。 return_typeは、関数が返す値のデータ型です。
オブジェクトタイプの指定については、次の点に注意する必要があります。
各メンバメソッドには、暗黙の組み込みパラメータ SELFがあり 、そのデータ型は定義されているオブジェクト型のデータ型です。
SELFは、現在メソッドを呼び出すオブジェクトインスタンスを参照します。 SELFは、パラメータリスト内のINまたはIN OUTパラメータとして明示的に宣言できます(たとえば、 MEMBER FUNCTION(SELF IN OUT object_type ...)など)
場合 SELFは明示的に宣言され、SELFは、パラメータリストの最初のパラメータでなければなりません。 SELFが明示的に宣言されていない場合、そのパラメーター・モードのデフォルトはメンバー・プロシージャーの場合はIN OUT 、メンバー関数の場合はINになります。
静的メソッドは、(オーバーライドすることができない オーバーライドSTATICは method_specで一緒に指定することはできません)。
静的メソッドは、インスタンス化可能でなければならない( INSTANTIABLE NOT及びSTATICは method_specで一緒に指定することはできません)。
6.2.2 オブジェクト型の本体構文
以下はオブジェクト型本体の構文です:
CREATE [ OR REPLACE ] TYPE BODY name
{ IS | AS }
method_spec [...]
[ constructor ] [...]
END;
ここで、 method_specは次のとおりです。
subprogram_spec
そして subprogram_specは以下の通りであります:
{ MEMBER | STATIC }
{ PROCEDURE proc_name
[ ( [ SELF [ IN | IN OUT ] name ]
[, parm1 [ IN | IN OUT | OUT ] datatype1
[ DEFAULT value1 ] ]
[, parm2 [ IN | IN OUT | OUT ] datatype2
[ DEFAULT value2 ]
] ...)
]
{ IS | AS }
[ PRAGMA AUTONOMOUS_TRANSACTION; ]
[ declarations ]
BEGIN
statement ; ...
[ EXCEPTION
WHEN ... THEN
statement ; ...]
END;
|
FUNCTION func_name
[ ( [ SELF [ IN | IN OUT ] name ]
[, parm1 [ IN | IN OUT | OUT ] datatype1
[ DEFAULT value1 ] ]
[, parm2 [ IN | IN OUT | OUT ] datatype2
[ DEFAULT value2 ]
] ...)
]
RETURN return_type
{ IS | AS }
[ PRAGMA AUTONOMOUS_TRANSACTION; ]
[ declarations ]
BEGIN
statement ; ...
[ EXCEPTION
WHEN ... THEN
statement ; ...]
END;
どこ コンストラクタは次のとおりです。
CONSTRUCTOR func_name
[ ( [ SELF [ IN | IN OUT ] name ]
[, parm1 [ IN | IN OUT | OUT ] datatype1
[ DEFAULT value1 ] ]
[, parm2 [ IN | IN OUT | OUT ] datatype2
[ DEFAULT value2 ]
] ...)
]
RETURN self AS RESULT
{ IS | AS }
[ declarations ]
BEGIN
statement ; ...
[ EXCEPTION
WHEN ... THEN
statement ; ...]
END;
name は、オブジェクト型に割り当てられた識別子(オプションでスキーマ修飾名)です。
method_specは、 CREATE TYPEコマンドで指定されたインスタンス化可能なメソッドの実装を示します。
CREATE TYPEコマンドのmethod_specINSTANTIABLEが指定または省略された場合CREATE TYPE BODYコマンドにはこのメソッドのmethod_specが必要です。
場合は 、NOT INSTANTIABLEは 、CREATE TYPEコマンドmethod_specに指定されました、そしてTYPEをCREATE BODYコマンドで、この方法にはmethod_specがあってはなりません。
subprogram_specは、手続きまたは関数の指定を表し、 MEMBERまたはSTATICのいずれかの指定で始まります。 CREATE TYPEコマンドのsubprogram_specで指定されているのと同じ修飾子を使用する必要があります。
proc_nameは、 CREATE TYPEコマンドで指定されたプロシージャーのIDです。パラメータ宣言は、TYPEをCREATEコマンドについて説明したのと同様の意味を持ち、そしてTYPEのCREATE コマンド で指定したのと同じ方法、CREATE TYPEのBODYコマンドで指定する必要があります
コンストラクタ関数を定義するには CONSTRUCTOR キーワードと関数定義を 含めます
func_name は、 CREATE TYPE コマンドで 指定された関数のIDです 。パラメータ宣言は 、TYPEをCREATEコマンドについて説明したのと同様の意味を持ち 、そしてTYPEのCREATEコマンドで指定したのと同じ方法で、CREATE TYPEのBODYコマンドで指定する必要があります。 return_typeは、関数が返す値のデータ型であり、 CREATE TYPEコマンドで指定されたreturn_typeと一致する必要があります。
PRAGMA AUTONOMOUS_TRANSACTIONは、プロシージャまたはファンクションを自律型トランザクションとして設定するディレクティブです。
宣言 は、変数、カーソル、型、または副プログラムの宣言です。サブプログラム宣言が含まれている場合は、他のすべての変数宣言、カーソル宣言、および型宣言の後に宣言する必要があります。
statementはSPLプログラムのステートメントです。
6.3 オブジェクト型の作成
あなたは使用することができ 、オブジェクト型本体を作成するには 、オブジェクト型の仕様を作成するために、TYPEコマンド 作成し 、CREATE TYPEのBODY コマンド 。このセクションでは、 CREATE TYPE および CREATE タイプ BODY コマンド。
最初の例では、 属性のみを含みメソッドは含まない addr_object_type オブジェクト型を 作成し ます。
CREATE OR REPLACE TYPE addr_object_type AS OBJECT
(
street VARCHAR2(30),
city VARCHAR2(20),
state CHAR(2),
zip NUMBER(5)
);
このオブジェクト型にはメソッドが存在しないため、オブジェクト型の本体は必要ありません。この例では複合型を作成し、関連するオブジェクトを単一の属性として扱うことができます。
6.3.1 メンバーメソッド
メンバーメソッドは、オブジェクト型内で定義された関数またはプロシージャであり、その型のインスタンスを通じてのみ呼び出すことができます。メンバメソッドは、それらが動作しているオブジェクトインスタンスにアクセスし、それらの属性を変更することができます。
次のオブジェクト型の指定により、 emp_obj_typオブジェクト型が作成されます。
CREATE OR REPLACE TYPE emp_obj_typ AS OBJECT
(
empno NUMBER(4),
ename VARCHAR2(20),
addr ADDR_OBJ_TYP,
MEMBER PROCEDURE display_emp(SELF IN OUT emp_obj_typ)
);
オブジェクト型 emp_obj_typには、 display_empという名前のメンバ・メソッドが含まれています。 display _ empは、メソッドが呼び出されたオブジェクトインスタンスを渡すSELFパラメータを使用します。
SELFパラメータは、データ型が定義されているオブジェクトタイプのものであるパラメータです。 SELFは、常にメソッドを呼び出すインスタンスを参照します。 SELFパラメーターは、パラメーター・リストで明示的に宣言されているかどうかに関係なく 、メンバー・プロシージャーまたは関数の最初のパラメーターです。
次のコードスニペットは、 emp_obj_typの オブジェクト型本体を定義しています
CREATE OR REPLACE TYPE BODY emp_obj_typ AS
MEMBER PROCEDURE display_emp (SELF IN OUT emp_obj_typ)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Employee No  : ' || empno);
DBMS_OUTPUT.PUT_LINE('Name          : ' || ename);
DBMS_OUTPUT.PUT_LINE('Street        : ' || addr.street);
DBMS_OUTPUT.PUT_LINE('City/State/Zip: ' || addr.city || ', ' ||
addr.state || ' ' || LPAD(addr.zip,5,'0'));
END;
END;
オブジェクトタイプ本体でSELFパラメータを使用することもできます。 SELFパラメータがCREATE TYPE BODYコマンドでどのように使用されるかを説明するために、前のオブジェクト型本体を次のように記述することができます。
CREATE OR REPLACE TYPE BODY emp_obj_typ AS
MEMBER PROCEDURE display_emp (SELF IN OUT emp_obj_typ)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Employee No  : ' || SELF.empno);
DBMS_OUTPUT.PUT_LINE('Name          : ' || SELF.ename);
DBMS_OUTPUT.PUT_LINE('Street        : ' || SELF.addr.street);
DBMS_OUTPUT.PUT_LINE('City/State/Zip: ' || SELF.addr.city || ', ' ||
SELF.addr.state || ' ' || LPAD(SELF.addr.zip,5,'0'));
END;
END;
emp_obj_typ本体の両方のバージョンは完全に同等です。
6.3.2 静的メソッド
メンバメソッドと同様に、静的メソッドは型に属します。ただし、静的メソッドは、その型のインスタンスではなく 、その型の名前を使用して呼び出され ます 。例えば、emp_obj_typeタイプ内で定義されたget_countという名前の静的関数を呼び出すために、次のように記述します。
emp_obj_type.get_count();
Sの tatic方法はへのアクセス権を持たない、およびオブジェクト・インスタンスの属性を変更することができず、典型的にはタイプのインスタンスでは動作しません。
次のオブジェクト型の指定には、静的関数 get_dnameとメンバー・プロシージャdisplay_deptが 含まれます。
CREATE OR REPLACE TYPE dept_obj_typ AS OBJECT (
deptno NUMBER(2),
STATIC FUNCTION get_dname(p_deptno IN NUMBER) RETURN VARCHAR2,
MEMBER PROCEDURE display_dept
);
オブジェクト型本体 dept_obj_typは get_dnamedisplay_deptという名前のメンバ手順名前静的関数を定義します。
CREATE OR REPLACE TYPE BODY dept_obj_typ AS
STATIC FUNCTION get_dname(p_deptno IN NUMBER) RETURN VARCHAR2
IS
v_dname VARCHAR2(14);
BEGIN
CASE p_deptno
WHEN 10 THEN v_dname := 'ACCOUNTING';
WHEN 20 THEN v_dname := 'RESEARCH';
WHEN 30 THEN v_dname := 'SALES';
WHEN 40 THEN v_dname := 'OPERATIONS';
ELSE v_dname := 'UNKNOWN';
END CASE;
RETURN v_dname;
END;
MEMBER PROCEDURE display_dept
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Dept No : ' || SELF.deptno);
DBMS_OUTPUT.PUT_LINE('Dept Name : ' ||
dept_obj_typ.get_dname(SELF.deptno));
END;
END;
静的関数 get_dnameにはSELFへの参照はありません。静的関数は任意のオブジェクトインスタンスから独立して呼び出されるため、任意のオブジェクト属性への暗黙的なアクセスはありません。
メンバー・プロシージャーの display_deptは、 SELFパラメーターで渡されたオブジェクト・インスタンスのdeptno属性にアクセスできます。 display_deptパラメータリストでSELFパラメータを明示的に宣言する必要はありません。
display_deptプロシージャの最後の DBMS_OUTPUT.PUT_LINE文には、静的関数get_dname (オブジェクト型名dept_obj_typで修飾 )のコールが含まれています。
6.3.3 コンストラクタメソッド
コンストラクタメソッドは、通常、オブジェクトのメンバに値を割り当てることによって、オブジェクト型のインスタンスを作成する関数です。オブジェクトタイプは、異なるタスクを達成するためにいくつかのコンストラクタを定義することができる。コンストラクタメソッドは 、名前が型の名前と一致するメンバ関数( SELFパラメータで呼び出されます)です。
たとえば、 address という名前の型を定義すると 、各コンストラクタの名前はaddressになります 。同じ名前で異なる引数型を持つ1つ以上の異なるコンストラクタ関数を作成して、コンストラクタをオーバーロードすることができます。
SPLコンパイラは、オブジェクト型ごとにデフォルトのコンストラクタを提供します。デフォルトのコンストラクタは、名前が型の名前と一致し、引数リストが型メンバーと順番に一致するメンバ関数です。たとえば、次のようなオブジェクト型が指定されているとします。
CREATE TYPE address AS OBJECT
(
street_address VARCHAR2(40),
postal_code VARCHAR2(10),
city VARCHAR2(40),
state VARCHAR2(2)
)
SPLコンパイラは、次のシグネチャを持つデフォルトのコンストラクタを提供します。
CONSTRUCTOR FUNCTION address
(
street_address VARCHAR2(40),
postal_code VARCHAR2(10),
city VARCHAR2(40),
state VARCHAR2(2)
)
デフォルトのコンストラクタの本体は、単に各メンバを NULLに 設定し ます
カスタムコンストラクターを作成するには、 CREATE TYPEコマンドでコンストラクター関数(キーワードコンストラクターを使用)を宣言し、 CREATE TYPE BODYコマンドで構築関数を定義します。たとえば、 street _ addresspostal _ codeが 指定された都市と州を計算する住所タイプのカスタムコンストラクタを作成することができます
CREATE TYPE address AS OBJECT
(
street_address VARCHAR2(40),
postal_code VARCHAR2(10),
city VARCHAR2(40),
state VARCHAR2(2),

CONSTRUCTOR FUNCTION address
(
street_address VARCHAR2,
postal_code VARCHAR2
) RETURN self AS RESULT
)
CREATE TYPE BODY address AS
CONSTRUCTOR FUNCTION address
(
street_address VARCHAR2,
postal_code VARCHAR2
) RETURN self AS RESULT
IS
BEGIN
self.street_address := street_address;
self.postal_code := postal_code;
self.city := postal_code_to_city(postal_code);
self.state := postal_code_to_state(postal_code);
RETURN;
END;
END;
オブジェクト型のインスタンスを作成するには、その型のコンストラクタメソッドの1つを呼び出します。例えば:
DECLARE
cust_addr address := address('100 Main Street', 02203');
BEGIN
DBMS_OUTPUT.PUT_LINE(cust_addr.city); -- displays Boston
DBMS_OUTPUT.PUT_LINE(cust_addr.state); -- displays MA
END;
カスタムコンストラクタ関数は、不完全な情報が与えられたときにメンバ値を計算するために使われます。上記の例は 、郵便番号が与えられたときのcitystateの 値を計算します
カスタムコンストラクタ関数は、オブジェクトの状態を制限するビジネスルールを強制するためにも使用されます。たとえば、 支払 を表すオブジェクト型を定義する場合は、カスタムコンストラクタを使用して、 NULL 、負数、またはゼロの金額支払タイプのオブジェクトを作成できないようにすることができます。デフォルトのコンストラクタはpayment.amountNULLに設定するため、 NULLの量を禁止するカスタムコンストラクタ(デフォルトのコンストラクタと一致するシグネチャ)を作成する必要があります。
6.4 オブジェクトインスタンスの作成
オブジェクト型のインスタンスを作成するには、最初にオブジェクト型の変数宣言してから 、宣言されたオブジェクト変数を初期化する必要があります。オブジェクト変数を宣言する構文は次のとおりです。
object obj_type
object は、オブジェクト変数に割り当てられた識別子です。
obj_typeは、以前に定義されたオブジェクト型の識別子です。
オブジェクト変数を宣言したら、 コンストラクタ・ メソッド呼び出してオブジェクトを値で初期化する必要があります。コンストラクタメソッドを呼び出すには、次の構文を使用します。
[ 新規 ] obj_type ({expr1 | NULL} [、 {expr2 | NULL} ] [、...])
obj_typeは、オブジェクト型のコンストラクタメソッドの識別子です。コンストラクタ・メソッドは、以前に宣言されたオブジェクト型と同じ名前を持ちます。
expr1expr2 、...は、オブジェクト型の最初の属性、オブジェクト型の2番目の属性などと型互換性のある式です。属性がオブジェクト型の場合、対応する式はNULL 、オブジェクト初期化式、またはそのオブジェクト型を返す式。
次の無名ブロックは、変数を宣言して初期化します。
DECLARE
v_emp EMP_OBJ_TYP;
BEGIN
v_emp := emp_obj_typ (9001,'JONES',
addr_obj_typ('123 MAIN STREET','EDISON','NJ',08817));
END;
変数( v_emp )は、以前に定義されたEMP _ OBJ _ TYPEというオブジェクト型で宣言されます。ブロックの本体は、 emp_obj_typおよびaddr_obj_typeコンストラクタを使用して変数を初期化します。
ブロックの本文にオブジェクトの新しいインスタンスを作成する場合は、 NEWキーワードを含めることができますNEWキーワードは、指定された引数と一致するシグネチャを持つオブジェクトコンストラクタを呼び出します。
次の例では、 mgremp という2つの変数を宣言しています 。変数は両方ともEMP_OBJ_TYPEです。 mgrオブジェクトは宣言で初期化され、empオブジェクトは宣言でNULLに初期化され、本文に値が割り当てられます。
DECLARE
mgr EMP_OBJ_TYPE := (9002,'SMITH');
emp EMP_OBJ_TYPE;
BEGIN
emp := NEW EMP_OBJ_TYPE (9003,'RAY');
END;
注意: Advanced Serverでは、コンストラクタメソッドの代わりに次の代替構文を使用できます。
[ ROW ] ({ expr1 | NULL } [, { expr2 | NULL } ] [, ...])
ROWは、括弧で囲まれたカンマ区切りのリスト内に複数の用語が指定されている場合、オプションのキーワードです。用語が1つしか指定されていない場合、 ROWキーワードの指定は必須です。
6.5 オブジェクトの参照
オブジェクト変数を作成して初期化すると、フォームのドット表記を使用して個々の属性を参照できます。
object . attribute
objectは、オブジェクト変数に割り当てられた識別子です。 属性は、オブジェクト型属性の識別子です。
場合 属性は 、それ自体が、オブジェクト型である場合、参照は形を取る必要があります。
object . attribute.attribute_inner
attribute_innerは、 objectの定義における属性参照先のオブジェクト型に属する識別子です。
次の例では、前の無名ブロックを展開して、 emp_obj_typオブジェクトに割り当てられた値を表示します。
DECLARE
v_emp EMP_OBJ_TYP;
BEGIN
v_emp := emp_obj_typ(9001,'JONES',
addr_obj_typ('123 MAIN STREET','EDISON','NJ',08817));
DBMS_OUTPUT.PUT_LINE('Employee No  : ' || v_emp.empno);
DBMS_OUTPUT.PUT_LINE('Name          : ' || v_emp.ename);
DBMS_OUTPUT.PUT_LINE('Street        : ' || v_emp.addr.street);
DBMS_OUTPUT.PUT_LINE('City/State/Zip: ' || v_emp.addr.city || ', ' ||
v_emp.addr.state || ' ' || LPAD(v_emp.addr.zip,5,'0'));
END;
以下は、この無名ブロックからの出力です。
Employee No : 9001
Name : JONES
Street : 123 MAIN STREET
City/State/Zip: EDISON, NJ 08817
メソッドは属性と同様の方法で呼び出されます。
オブジェクト変数が作成されて初期化されると、メンバプロシージャまたは関数は次の形式のドット表記法を使用して呼び出されます。
object . prog_name
objectは、オブジェクト変数に割り当てられた識別子です。 prog_nameは、プロシージャーまたは関数のIDです。
静的プロシージャーまたは関数は、オブジェクト変数を使用して呼び出されません。代わりに、プロシージャまたはファンクションは、オブジェクト型名を使用して呼び出されます。
object_type . prog_name
object_typeは、オブジェクト型に割り当てられた識別子です。 prog_nameは、プロシージャーまたは関数のIDです。
前の無名ブロックの結果は、メンバー・プロシージャ display_empを コールすることによって複写できます
DECLARE
v_emp EMP_OBJ_TYP;
BEGIN
v_emp := emp_obj_typ(9001,'JONES',
addr_obj_typ('123 MAIN STREET','EDISON','NJ',08817));
v_emp.display_emp;
END;
以下は、この無名ブロックからの出力です。
Employee No : 9001
Name : JONES
Street : 123 MAIN STREET
City/State/Zip: EDISON, NJ 08817
次の匿名ブロックは、 dept_obj_typの インスタンスを作成し 、メンバー・プロシージャdisplay_deptを呼び出します。
DECLARE
v_dept DEPT_OBJ_TYP := dept_obj_typ (20);
BEGIN
v_dept.display_dept;
END;
以下は、この無名ブロックからの出力です。
Dept No : 20
Dept Name : RESEARCH
dept_obj_typで 定義された静的関数は、オブジェクト型名で次のよう 修飾することで直接呼び出すことができます。
BEGIN
DBMS_OUTPUT.PUT_LINE(dept_obj_typ.get_dname(20));
END;
 
RESEARCH
6.6 オブジェクト型の削除
オブジェクト型を削除する構文は次のとおりです。
DROP TYPE objtype ;
objtypeは、削除するオブジェクト型の識別子です。 objtypeの定義自体にオブジェクト型またはコレクション型の属性が含まれている場合、これらの入れ子になったオブジェクト型またはコレクション型を最後に削除する必要があります。
オブジェクト型本体がオブジェクト型に対して定義されている場合、 DROP TYPEコマンドは、オブジェクト型本体とオブジェクト型指定を削除します。完全なオブジェクト型を再作成するには、 CREATE TYPEコマンドとCREATE TYPE BODYコマンドの両方を再発行する必要があります。
次の例では、この章の前半で作成し emp_obj_typおよびaddr_obj_typオブジェクト型を削除します。 emp_obj_typは属性としてその定義内にaddr_obj_typを含むため、最初に削除する必要があります。
DROP TYPE emp_obj_typ;
DROP TYPE addr_obj_typ;
オブジェクト型本体を削除する構文はありますが、オブジェクト型指定は削除されません。
DROP TYPE BODY objtype ;
オブジェクト型本体は、 CREATE TYPE BODYコマンドを発行することによって再作成できます
次の例では、 dept_obj_typの オブジェクト型本体のみを削除します
DROP TYPE BODY dept_obj_typ;
7 Open Client Library
以前は今、アプリケーション・コードを変更せずに、最小限にEDBのPostgres Advanced ServerまたはOracleデータベースのいずれかで動作することができ、「固定」されたアプリケーション- オープンクライアントライブラリでは、Oracle Call Interfaceのでアプリケーションの相互運用性を提供します。 Open Client LibraryのEnterpriseDB実装はC言語で記述されています。
次の図は、 Open Client LibraryOracle Call Interfaceのアプリケーション・スタックを比較したものです。
Open Client Libraryおよびサポートされる機能の詳細な使用方法については、次のURLにある「EDB Postgres Advanced Server OCI Connector Guide」を参照してください。
https://www.enterprisedb.com/resources/product-documentation
注意:EnterpriseDBは、Oracle Real Application Clusters(RAC)およびOracle ExadataでのOpen Client Libraryの使用をサポートしていません。上記のOracle製品は、このEnterpriseDB製品で評価または認定されていません。
8 Oracleカタログ・ビュー
オラクル・カタログ・ビューは、Oracleデータ・ディクショナリ・ビューと互換性のある方法で、データベースオブジェクトに関する情報を提供します。サポートされているビューに関する情報は、 Oracle Developer's Reference GuideのDatabase Compatibilityで入手できます。
https://www.enterprisedb.com/resources/product-documentation
9 ツールとユーティリティ
互換性のあるツールとユーティリティプログラムにより、開発者は使い慣れた環境でAdvanced Serverを操作できます。 Advanced Serverでサポートされているツールは次のとおりです。
Advanced Serverでサポートされている機能の詳細については 、Oracle Developer's Tools and Utilities GuideのDatabase Compatibility を参照してください
https://www.enterprisedb.com/resources/product-documentation
10 テーブルパーティショニング
パーティション化されたテーブルでは、論理的に大きな1つのテーブルがより小さな物理的な部分に分割されます。パーティショニングにはいくつかの利点があります。
パーティション設計にその要件を計画する場合は、パーティションを追加または削除してバルクロード(またはアンロード)を実装できます。 ALTER TABLE は、一括操作よりはるかに高速です。また 、バルク DELETE によって引き起こされる VACUUM オーバーヘッドを 完全に回避し ます。
テーブル分割は、さもなければテーブルが非常に大きくなる場合にのみ価値があります。テーブルがパーティショニングの恩恵を受ける正確なポイントは、アプリケーションによって異なります。経験則として、テーブルのサイズがデータベースサーバーの物理メモリを超えている必要があります。
このドキュメントでは、Advanced ServerでサポートされているOracleデータベースと互換性のある表パーティション化の側面について説明します。
注意: この文書とこの章で説明特にパーティショニングは、PostgreSQL の宣言型のパーティショニングは、Oracleデータベースと互換性のある表のパーティション化に加えて、高度なサーバー10にサポートされていることをPostgreSQLバージョン10注意して導入された 宣言型のパーティショニング 機能を、 説明しません この章で説明します。宣言型パーティショニングの詳細については、次のURLにあるPostgreSQLのコアドキュメントを参照してください。
https://www.postgresql.org/docs/11/static/ddl-partitioning.html
PostgreSQL 9.6 INSERT ... ON CONFLICT DO NOTHING / UPDATE句(一般にUPSERTとして知られています)は、Oracleスタイルのパーティションテーブルではサポートされていません。パーティション表にデータを追加するためにINSERTコマンドを呼び出すときにON CONFLICT DO NOTHING / UPDATE文節を組み込むと、サーバーはエラーを戻します。
10.1 パーティションタイプの選択
パーティション表を作成するときは、 LISTRANGE 、またはHASHの区画化規則を指定します 。パーティション化ルールは、各パーティションに格納されているデータを定義する一連の制約を提供します。新しい行がパーティション表に追加されると、サーバーはパーティション化ルールを使用して、各行を含むパーティションを決定します。
Advanced Serverでは、パーティション・ルールを使用してパーティション・プルーニングを実施し、ユーザーの問合せに応答する際のパフォーマンスを向上させることもできます。表のパーティション・タイプおよびパーティション化キーを選択するときは、表内に保管されているデータを照会する方法と、頻繁に照会される列をパーティション化ルールに組み込む方法を考慮する必要があります。
リストのパーティション化
リスト・パーティション表を作成するときは、単一​​のパーティション・キー列を指定します。表に行を追加するときに、サーバーはパーティション化ルールで指定されたキー値を行内の対応する列と比較します。列の値がパーティション化ルールの値と一致する場合、その行はルールに指定されたパーティションに格納されます。
範囲パーティショニング
レンジ・パーティション表を作成するときは、1つ以上のパーティション・キー列を指定します。表に新しい行を追加すると、サーバーはパーティション化キー(または複数のキー)の値と、表項目内の対応する列(または複数の列)を比較します。列の値がパーティション化ルールで指定された条件を満たしている場合、その行はルールに指定されたパーティションに格納されます。
ハッシュパーティショニング
ハッシュ・パーティション表を作成するときは、1つ以上のパーティション・キー列を指定します。データは、指定されたパーティション間で(ほぼ)等しいサイズのパーティションに分割されます。ハッシュ・パーティション表に行を追加すると、サーバーは指定された列(または複数の列)のデータのハッシュ値を計算し、ハッシュ値に従ってその行をパーティションに格納します。
サブパーティション化
サブパーティション化は、分割されたテーブルをより小さなサブセットに分割します。すべてのサブセットは、同じデータベースサーバークラスタに格納する必要があります。表は通常、異なる列のセットによってサブパーティション化され、親パーティションとは異なるサブパーティション化タイプになる場合があります。 1つのパーティションがサブパーティション化されている場合、各パーティションには少なくとも1つのサブパーティションが存在します。
表がサブパーティション化されている場合、どのパーティション表にもデータは格納されません。データは代わりに対応するサブパーティションに格納されます。
10.2 パーティションプルーニングの使用
Advanced Serverのクエリプランナは、 パーティション プルーニングを使用して、 SELECT文のWHERE句で指定された条件に一致する行を特定する効率的な計画を計算します。 WHERE句は、実行計画からパーティションを正常にプルーニングするには、パーティション化された表の作成時に指定されたパーティション化キー列と比較される情報を制約する必要があります。 aを照会するとき:
WHERE句が等しい(=)またはANDのような演算子を使用してリテラル値をパーティション化キーと比較するときに、パーティション・プルーニングは有効です。
(=)、より小さい(<)、またはより大きい(>)などの演算子を使用して WHERE句がリテラル値をパーティション化キーと比較するときに、パーティション・プルーニングが有効です。
パーティション・プルーニングは、 WHERE句が等しい( = )などの演算子を使用してリテラル値をパーティション・キーと比較するときに有効です。
パーティションプルーニング・メカニズムは、2つの最適化手法を使用します。
パーティションプルーニング手法では、検索対象の値が存在する可能性があるパーティションのみにデータの検索を制限します。両方のプルーニング手法は、クエリの実行計画からパーティションを削除し、パフォーマンスを向上させます。
高速プルーニングと制約除外の違いは、高速プルーニングはOracleパーティション表のパーティション間の関係を理解し​​、制約除外はそうでないことです。たとえば、リスト・パーティション表内の特定の値を問合せで検索する場合、高速プルーニングは特定のパーティションのみがその値を保持し、制約除外では パーティションに対して定義された制約を調べる必要があります。高速プルーニングはプランニングプロセスの早期に行われ、プランナが考慮する必要があるパーティションの数を減らし、制約除外はプランニングプロセスの後半に発生します。
制約除外の使用
制約 _ 除外パラメータは、制約による除外を制御します。 制約 _ 除外パラメータは、 オンオフ 、またはパーティションの値を有することができます。制約除外を有効にするには、パラメータをpartitionまたはonの いずれかに設定する必要があります。デフォルトでは、パラメータはpartitionに設定されています。
制約の除外の詳細については、以下を参照してください。
https://www.postgresql.org/docs/11/static/ddl-partitioning.html
制約除外が有効になると、サーバーは各パーティションに対して定義された制約を調べて、そのパーティションがクエリを満たすことができるかどうかを判断します。
WHERE句を含まない SELECTを実行する場合 、クエリプランナはテーブル全体を検索する実行計画を推奨する必要があります。あなたがWHERE句を含まない SELECT文を実行すると、クエリプランナは、その行が格納されるであろうパーティションに決定し、実行計画からその行を含めることができませんでしたパーティションをプルーニング、そのパーティションにクエリフラグメントを送信します。パーティション表を使用していない場合、制約除外を使用不可にすると、パフォーマンスが向上する可能性があります。
高速プルーニング
制約の除外と同様に、高速プルーニングは WHERE (または結合)句を含む問合せを最適化するだけで、 WHERE句の修飾子が特定の形式と一致する場合にのみ最適化できます。いずれの場合も、問合せプランナは、問合せで必要なデータを保持できないパーティション内のデータの検索を避けます。
高速プルーニングは、 edb_enable_pruning という名前のブール型構成パラメーターによって制御されますedb_enable_pruningONの場合、Advanced Serverは特定のクエリを高速にプルーニングします。 edb_enable_pruningOFFの場合、サーバーは高速プルーニングを無効にします。
注意:高速プルーニングでは、サブパーティション化された表に対する問合せを最適化できません。また、複数の列にパーティション化されたレンジ・パーティション表に対する問合せを最適化することもできません。
LISTパーティション表の場合、Advanced Serverは 、パーティション化列をリテラル値に制限するWHERE句を含むクエリを高速でプルーニングできます。たとえば、次のようなLISTパーティション表があるとします。
CREATE TABLE sales_hist(...、国別テキスト、...)
PARTITION BY LIST(国)

PARTITIONアメリカのVALUES( 'US'、 'C​​A'、 'MX')、
PARTITION europe VALUES( 'BE'、 'NL'、 'FR')、
PARTITION asia VALUES( 'JP'、 'PK'、 'C​​N')、
PARTITIONその他の値VALUES(DEFAULT)
高速プルーニングは 、次のようなWHEREを理由に考えることができます
どこの国= 'US'
WHERE country is NULLです。
最初に与えられた 国=「米国」:これらのパーティションは、修飾子を満たす行を保持することはできませんので、WHERE句、高速の剪定は、パーティションヨーロッパアジア 、および他を排除するであろう。
第二与えられたこれらのパーティションは、 国が NULL ISの行を保持することはできませんので、WHERE句、高速の剪定は、パーティションの米州欧州アジアを排除するであろう。
WHERE節で指定された演算子は、等号( = )または分割列のデータ型に適した等価演算子でなければなりません。
レンジ・パーティション表の場合、Advanced Serverは 、パーティション化列をリテラル値に制限するWHERE句を含む照会を高速でプルーニングできますが、演算子は次のいずれかです。
>
> =
=
<=
<
高速プルーニングは、 AND演算子やBETWEEN演算子が関わる次のような複雑な式の原因にもなります
WHERE size> 100 AND size <= 200
100と200の間のどこのサイズ
しかし、 ORINを 含む式に基づいて整理することはできません
たとえば、次のようなRANGEパーティション表を問い合せる場合です。
CREATE TABLEボックス(ID int、サイズint、カラーテキスト)
範囲による区切り(サイズ)

区画小さな値より小さい(100)、
PARTITION medium VALUES LESS THAN(200)、
パーティション大きな値より小さい(300)
高速プルーニングは 、次のようなWHEREを理由に考えることができます
WHERE size> 100 - スキャンパーティション 'medium'と 'large'
WHERE size> = 100 - パーティション 'medium'と 'large'をスキャンします。
WHERE size = 100 - スキャンパーティション 'medium'
WHERE size <= 100 - スキャンパーティション 'small'と 'medium'
WHERE size <100 - スキャンパーティション 'small'
WHERE size> 100 AND size <199 - スキャンパーティション 'medium'
100と199の間のWHEREサイズ - スキャンパーティション 'medium'
WHERE color = 'red' AND size = 100 - 'medium'をスキャンします。
WHERE color = 'red' AND(サイズ> 100 ANDサイズ<199) - スキャン 'medium'
いずれの場合も、高速プルーニングでは、修飾子がパーティション化カラムとリテラル値(または IS NULL / IS NOT NULL )を参照する必要があり ます
高速プルーニングは、上記のフォームのWHERE句を含むDELETE文とUPDATE文を最適化することもできます。
 
10.2.1 例 - パーティションプルーニング
EXPLAIN文は、文の実行計画を表示します。 EXPLAIN文を使用すると、Advanced Serverがクエリの実行計画からパーティションをプルーニングすることを確認できます。
パーティションプルーニングの効率を実証するには、まず簡単なテーブルを作成します。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
PARTITION BY LIST(国)
PARTITION europe VALUES( 'フランス'、 'イタリア')、
PARTITION asia VALUES( 'インド'、 'パキスタン')、
PARTITIONアメリカの価値( 'US'、 'C​​ANADA')
);
次に、 EXPLAINを含む制約付き問合せを実行します
説明(オフ)SELECT * FROM sales WHERE country = 'INDIA';
結果のクエリプランは、サーバーが sales_asiaテーブル( インドの 国の値を持つ行が格納されるテーブル) のみをスキャンすることを示します
edb=# EXPLAIN (COSTS OFF) SELECT * FROM sales WHERE country = 'INDIA';
QUERY PLAN
---------------------------------------------------
Append
-> Seq Scan on sales_asia
Filter: ((country)::text = 'INDIA'::text)
(3 rows)
パーティション化キーに含まれていない値と一致する行を検索するクエリを実行すると、次のようになります。
説明する(オフにする)SELECT * FROM sales where dept_no = '30';
結果のクエリプランは、サーバーがクエリを満たす行を見つけるためにすべてのパーティションを検索する必要があることを示しています。
edb=# EXPLAIN (COSTS OFF) SELECT * FROM sales WHERE dept_no = '30';
QUERY PLAN
-------------------------------------------
Append
-> Seq Scan on sales_americas
Filter: (dept_no = '30'::numeric)
-> Seq Scan on sales_europe
Filter: (dept_no = '30'::numeric)
-> Seq Scan on sales_asia
Filter: (dept_no = '30'::numeric)
(7 rows)
制約除外は、サブパーティション化された表を問い合せるときにも適用されます。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
範囲による区画(日付)リストによる区画 (国)

PARTITION
"2011" VALUES LESS THAN('01 -JAN-2012' )
SUBPARTITION europe_2011 VALUES ( 'イタリア'、 'フランス')、
SUBPARTITION asia_2011 VALUES ( 'パキスタン'、 'インド')、
SUBPARTITION americas_2011 VALUES ( 'US'、 'CANADA')
)、
PARTITION "2012" VALUES LESS THAN('01 -JAN-2013' )
SUBPARTITION europe_2012 VALUES ( 'イタリア'、 'フランス')、
SUBPARTITION asia_2012 VALUES ( 'パキスタン'、 'インド')、
SUBPARTITION americas_2012 VALUES ( 'US'、 'CANADA')
)、
PARTITION
"2013" VALUES LESS THAN('01 -JAN-2015' )
SUBPARTITION europe_2013 VALUES ( 'イタリア'、 'フランス')、
SUBPARTITION asia_2013 VALUES ( 'パキスタン'、 'インド')、
SUBPARTITION americas_2013 VALUES ( 'US'、 'CANADA')
);
表を問い合せると、問合せプランナは、必要な結果セットを含むことのできない検索パスからパーティションまたはサブパーティションをプルーニングします。
edb=# EXPLAIN (COSTS OFF) SELECT * FROM sales WHERE country = 'US' AND date = 'Dec 12, 2012';
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------
Append
-> Seq Scan on sales_americas_2012
Filter: (((country)::text = 'US'::text) AND (date = '12-DEC-12 00:00:00'::timestamp without time zone))
(3 rows)
10.3 Oracleデータベースと互換性のあるパーティション化コマンド
次のセクションでは、Advanced ServerでサポートされているOracleデータベースと互換性のある表パーティション構文の使用方法について説明します。
10.3.1 CREATE TABLE ... PARTITION BY
CREATE TABLEコマンド PARTITION BY句を使用して、 1つ以上のパーティション(およびサブパーティション)に分散されたデータを含むパーティション表を作成します。コマンド構文は次の形式で提供されます。
リストのパーティション化構文
最初の形式を使用して、リスト・パーティション表を作成します。
CREATE TABLE [スキーマ。 ] テーブル名
table_definition
PARTITION BY LIST(
[SUBPARTITION BY {RANGE | LIST | HASH}( [、 ] ...)]
list_partition_definition [、list_partition_definition] ... );
where list_partition_definition 次のとおりです。
PARTITION [ パーティション名 ]
VALUES( [、 ] ...)
[TABLESPACE tablespace_name ]
[( サブパーティション 、...)]
範囲パーティショニング構文
2番目の形式を使用してレンジ・パーティション表を作成します。
CREATE TABLE [ スキーマ 。 ] テーブル名
table_definition
PARTITION BY RANGE(
[、 ] ...)
[SUBPARTITION BY {RANGE | LIST | HASH}( [、 ] ...)]
range_partition_definition [、range_partition_definition] ... );
どこ range_partition_definitionは以下とおりです。
PARTITION [ パーティション名 ]
VALUES LESS THAN( [、 ] ...)
[TABLESPACE tablespace_name ]
[( サブパーティション 、...)]
ハッシュパーティショニングの構文
3番目の形式を使用して、ハッシュ・パーティション表を作成します。
CREATE TABLE [ スキーマ 。 ] テーブル名
table_definition
PARTITION BY HASH( [、 ] ...)
[SUBPARTITION BY {RANGE | LIST | HASH}(
[、 ] ...)]
hash_partition_definition [、 hash_partition_definition ] ...);
どこで hash_partition_definitionは次のとおりです。
[PARTITION partition_name ]
[TABLESPACE tablespace_name ]
[(
サブパーティション 、...)]
サブパーティション化の構文
サブパーティションは次のいずれかになります。
{ list _ subpartition | 範囲 _ サブパーティション | hash_subpartition }
ここで、 list _ サブパーティションは次のとおりです。
SUBPARTITION [ subpartition_name ]
VALUES( [、 ] ...)
[TABLESPACE tablespace_name ]
どこ 範囲 _ サブパーティションはのようになります。
SUBPARTITION [ subpartition_name ]
VALUES LESS THAN( [、 ] ...)
[TABLESPACE tablespace_name ]
ここで、 hash_subpartitionは次のとおりです。
[SUBPARTITION subpartition_name]
[TABLESPACE tablespace_name]
説明
コマンドBY CREATE TABLE ... PARTITIONは、1つ以上のパーティションを持つ表を作成します。各パーティションは1つ以上のサブパーティションを持つことができます。定義されたパーティションの数に上限はありませんが、 PARTITION BY句を含める場合は、少なくとも1つのパーティション化ルールを指定する必要があります。結果として得られるテーブルは、それを作成するユーザが所有します。
指定された列に入力された値に基づいて、表を区画に分割するには、 PARTITION BY LIST節を使用します。各パーティション化ルールでは、少なくとも1つのリテラル値を指定する必要がありますが、指定可能な値の数に上限はありません。指定されていない行を指定されたパーティションに送るDEFAULTという一致する値を指定するルールを組み込みます。 DEFAULTキーワードの使用方法の詳細は、第10.4項を参照してください。
パーティションを作成する境界ルールを指定するには、 PARTITION BY RANGE句を使用します。各パーティション化ルールには、2つの演算子(つまり、より大きいまたは等しい演算子、およびより小さい演算子)を持つデータ型の列が少なくとも1つ含まれている必要があります。範囲境界は、 LESS THAN節に対して評価され、非包含的である。 2013年1月1日の日付の境界には、2012年12月31日以前の日付の値のみが含まれます。
範囲パーティションのルールは、昇順で指定する必要があります。パーティション分割ルールにMAXVALUEの値を指定する境界ルールが含まれていない限り、範囲パーティション化テーブルの最上位境界を超える値を持つ行を格納するINSERTコマンドは失敗します MAXVALUEパーティション化ルールを含めない場合、境界ルールで指定された最大限度を超える行はエラーになります。
MAXVALUEキーワードの使用方法の詳細は、 10.4項を参照してください。
PARTITIONを 使用する によって HASH 句を使用してハッシュ・パーティション表を作成します。 ハッシュ ・パーティション表 では 、データは、分割構文で指定された列のハッシュ値に基づいて、同じサイズのパーティション間で分割されています。 HASH パーティションを 指定するとき は、できるだけ一意に近い列(または列の組み合わせ)を選択して、データがパーティション間で均等に分散されるようにします。パーティション化列(または列の組み合わせ)を選択するときは、パフォーマンスを最大限にするために頻繁に一致するものを頻繁に検索する列を選択します。
TABLESPACEキーワードを使用して、パーティションまたはサブパーティションが存在する表スペースの名前を指定します。表領域を指定しないと、パーティションまたはサブパーティションはデフォルト表領域に常駐します。
表定義に SUBPARTITION BY句が含まれている場合、その表内の各パーティションには少なくとも1つのサブパーティションが存在します。各サブパーティションは、明示的に定義することも、システム定義することもできます。
サブパーティションがシステム定義の場合、サーバー生成のサブパーティションはデフォルトの表領域にあり、サブパーティションの名前はサーバーによって割り当てられます。サーバーは次を作成します。
SUBPARTITION 場合 、デフォルトの サブパーティション BY 節は LISTを 指定します
SUBPARTITION であれば MAXVALUE サブ パーティション BY 節は RANGEを 指定します
サーバーは、パーティションテーブル名と一意の識別子の組み合わせであるサブパーティション名を生成します。 ALL _ TAB _ SUBPARTITIONS 表を 問い合せて 、サブパーティション名の完全なリストを確認 でき ます。
パラメーター
テーブル名
作成するテーブルの名前(スキーマ修飾名でも可)。
table_definition
CREATE TABLEステートメントのPostgreSQLコア文書で説明されているカラム名、データタイプ、および制約情報
https://www.postgresql.org/docs/11/static/sql-createtable.html
partition_name
作成するパーティションの名前。パーティション名は、すべてのパーティションとサブパーティションで一意でなければならず、オブジェクト識別子の命名規則に従わなければなりません。
サブパーティション名
作成するサブパーティションの名前。サブパーティション名は、すべてのパーティションとサブパーティションで一意でなければならず、オブジェクト識別子の命名規則に従わなければなりません。
カラム
パーティション化ルールの基になる列の名前。各行は 、指定された列の対応するパーティションに格納されます。
[、 ] ...)
使用して、表エントリをパーティションにグループ化する引用符付きリテラル値(またはリテラル値のコンマ区切りリスト)を指定します。各パーティション化ルールは少なくとも1つの値を指定する必要がありますが、ルール内で指定された値の数に制限はありません。 NULLDEFAULTLISTパーティションを指定する場合)、またはMAXVALUERANGEパーティションを指定する場合)です。
リスト・パーティション表のルールを指定するときは、最後のパーティション・ルールにDEFAULTキーワードを組み込んで 不一致の行を指定されたパーティションに転送します。 DEFAULTの値を含むルールを含めない場合、少なくとも1つのパーティションの指定されたルールと一致しない行を追加しようとするINSERTステートメントは失敗し、エラーを返します。
リスト・パーティション表のルールを指定するときは、最後のパーティション・ルールにMAXVALUEキーワードを組み込んで、分類されていない行を指定されたパーティションに誘導してください。 MAXVALUE区画を含めない場合、区画キーが指定された最大値より大きい行を追加しようとするINSERT文は失敗し、エラーが戻されます。
tablespace_name
パーティションまたはサブパーティションが存在する表領域の名前。
10.3.1.1 例 - PARTITION BY LIST
次の例ではPARTITION BY LIST句を使用してパーティション表( sales )を作成しますsales表は、3つのパーティション( ヨーロッパアジア南北アメリカ )で情報を格納します。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
PARTITION BY LIST(国)
PARTITION europe VALUES( 'フランス'、 'イタリア')、
PARTITION asia VALUES( 'インド'、 'パキスタン')、
PARTITIONアメリカの価値( 'US'、 'C​​ANADA')
);
結果の表は、 国の列で指定された値で区切られます。
acctg=# SELECT partition_name, high_value from ALL_TAB_PARTITIONS;
partition_name | high_value
----------------+-------------------------------------
EUROPE | FOR VALUES IN ('FRANCE', 'ITALY')
ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN')
AMERICAS | FOR VALUES IN ('US', 'CANADA')
(3 rows)
値を持つ行 の国の欄で、米国カナダは アメリカのパーティションに格納されています。
国の列にあるINDIAまたはPAKISTANの 値を持つ行は、 asiaパーティションに格納されます。
国の FRANCEまたはITALYの 値を持つ行は、 ヨーロッパの区画に格納されます。
サーバーは、パーティション化ルールに対して次のステートメントを評価し、行を ヨーロッパの区画に保管します
INSERT INTO sales VALUES(10、 '9519a'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ');
10.3.1.2 例 - PARTITION BY RANGE
次の例ではPARTITION BY RANGE句を使用してパーティション表( sales )を作成しますsalesテーブルは、4つのパーティション( q1_2012q2_2012q3_2012 、およびq4_2012 )に情報を格納します。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
範囲による区切り(日付)
分割q1_2012
VALUES LESS THAN( '2012-Apr-01')、
パーティションq2_2012
VALUES LESS THAN( '2012-Jul-01')、
パーティションq3_2012
VALUES LESS THAN( '2012-Oct-01')、
パーティションq4_2012
VALUES LESS THAN( '2013-Jan-01')
);
結果の表は、 日付列で指定された値で区切られます。
acctg=# SELECT partition_name, high_value from ALL_TAB_PARTITIONS;
partition_name | high_value
----------------+------------------------------------------------------------
Q1_2012 | FOR VALUES FROM (MINVALUE) TO ('01-APR-12 00:00:00')
Q2_2012 | FOR VALUES FROM ('01-APR-12 00:00:00') TO ('01-JUL-12 00:00:00')
Q3_2012 | FOR VALUES FROM ('01-JUL-12 00:00:00') TO ('01-OCT-12 00:00:00')
Q4_2012 | FOR VALUES FROM ('01-OCT-12 00:00:00') TO ('01-JAN-13 00:00:00')
(4 rows)
2012年4月1日より前 日付列の値を持つ行は、 q1_ 2012という名前のパーティションに格納されます。
2012年7月1日より前 日付列の値を持つ行は、 q2_ 2012という名前のパーティションに格納されます。
2012年10月1日より前 日付列の値を持つ行は、 q3_ 2012という名前のパーティションに格納されます。
2013年1月1日より前 日付列の値を持つ行は、 q4_ 2012という名前のパーティションに格納されます。
サーバーは、次の文をパーティション化ルールに対して評価し、その行を q3_2012パーティションに格納します
INSERT INTO sales VALUES(10、 '9519a'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ');
10.3.1.3 例 - ハッシュ分割
次の例ではPARTITION BY HASH節を使用してパーティション表( sales )を作成しますsalesテーブルは、3つのパーティション( p1p2 、およびp3
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
分割によるハッシュ(part_no)
パーティションp1、
パーティションp2、
パーティションp3
);
表は、 part_no列に指定された値のハッシュ値によってパーティション化されます。
acctg=# SELECT partition_name, high_value from ALL_TAB_PARTITIONS;
partition_name | high_value
----------------+------------------------------------------
P1 | FOR VALUES WITH (modulus 3, remainder 0)
P2 | FOR VALUES WITH (modulus 3, remainder 1)
P3 | FOR VALUES WITH (modulus 3, remainder 2)
(3 rows)
サーバーは part_no列のハッシュ値を評価し 、行をほぼ等しいパーティションに分散します。
10.3.1.4 例 - PARTITION BY RANGE、LIST別のサブパティション
次の例では 、トランザクション日によって最初にパーティション化されたパーティション表( sales )を作成します。範囲q1_2012q2_2012、q3_2012 、およびq4_2012 )は、 国の列の値を使用してリストサブパーティション化されます。
CREATE TABLEの売上

dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額

範囲による区切り(日付)
SUBPARTITION BY LIST(国)

分割q1_2012
VALUES LESS THAN( '2012-Apr-01')

SUBPARTITION q1_europe VALUES( 'フランス'、 'イタリア')、
SUBPARTITION q1_asia VALUES( 'インド'、 'パキスタン')、
SUBPARTITION q1_americas VALUES( 'US'、 'C​​ANADA')
)、
パーティションq2_2012
VALUES LESS THAN( '2012-Jul-01')

SUBPARTITION q2_europe VALUES( 'フランス'、 'イタリア')、
SUBPARTITION q2_asia VALUES( 'インド'、 'パキスタン')、
SUBPARTITION q2_americas VALUES( 'US'、 'C​​ANADA')
)、
パーティションq3_2012
VALUES LESS THAN( '2012-Oct-01')

SUBPARTITION q3_europe VALUES( 'フランス'、 'イタリア')、
SUBPARTITION q3_asia VALUES( 'インド'、 'パキスタン')、
SUBPARTITION q3_americas VALUES( 'US'、 'C​​ANADA')
)、
パーティションq4_2012
VALUES LESS THAN( '2013-Jan-01')

SUBPARTITION q4_europe VALUES( 'フランス'、 'イタリア')、
副題q4_asia VALUES( 'インド'、 'パキスタン')、
SUBPARTITION q4_americas VALUES( 'US'、 'C​​ANADA')

);
この文は、4つのパーティションを持つテーブルを作成します。各パーティションには3つのサブパーティションがあります。
acctg=# SELECT subpartition_name, high_value, partition_name FROM ALL_TAB_SUBPARTITIONS;
subpartition_name | high_value | partition_name
-------------------+-------------------------------------+----------------
Q1_AMERICAS | FOR VALUES IN ('US', 'CANADA') | Q1_2012
Q1_ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN') | Q1_2012
Q1_EUROPE | FOR VALUES IN ('FRANCE', 'ITALY') | Q1_2012
Q2_AMERICAS | FOR VALUES IN ('US', 'CANADA') | Q2_2012
Q2_ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN') | Q2_2012
Q2_EUROPE | FOR VALUES IN ('FRANCE', 'ITALY') | Q2_2012
Q3_AMERICAS | FOR VALUES IN ('US', 'CANADA') | Q3_2012
Q3_ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN') | Q3_2012
Q3_EUROPE | FOR VALUES IN ('FRANCE', 'ITALY') | Q3_2012
Q4_AMERICAS | FOR VALUES IN ('US', 'CANADA') | Q4_2012
Q4_ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN') | Q4_2012
Q4_EUROPE | FOR VALUES IN ('FRANCE', 'ITALY') | Q4_2012
(12 rows)
行がこの表に追加されると、 日付列の値が範囲区画化規則で指定された値と比較され、サーバーは行が常駐すべき区画を選択します。 国の列の値は、リストのサブパーティション化ルールで指定された値と比較されます。サーバーが値の一致を検出すると、行は対応するサブパーティションに保管されます。
テーブルに追加された行はサブパーティションに格納されるため、パーティションにはデータは含まれません。
サーバーは、次の文をパーティションおよびサブパーティション化ルールに対して評価し、その行を q3_europeパーティションに格納します
INSERT INTO sales VALUES(10、 '9519a'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ');
 
10.3.2 ALTER TABLE ... ADD PARTITION
既存のパーティション表にパーティションを追加するには、 ALTER TABLE ... ADD PARTITIONコマンドを使用します。構文は次のとおりです。
ALTER TABLE table _ name ADD PARTITION パーティション _ 定義 ;
ここで、 partition_definitionは次のとおりです。
{ list_partition | range_partition }
そして リスト _ パーティションは次のとおりです。
PARTITION [ パーティション名 ]
VALUES( [、 ] ...)
[TABLESPACE tablespace_name ]
[( サブパーティション 、...)]
そして range_partitionは以下とおりです。
PARTITION [ パーティション名 ]
VALUES LESS THAN( [、 ] ...)
[TABLESPACE tablespace_name ]
[( サブパーティション 、...)]
サブパーティションの 場所は次のとおりです。
{ list _ subpartition | 範囲 _ サブパーティション| hash_subpartition }
そして リスト _ サブパーティションは以下とおりです。
SUBPARTITION [ subpartition_name ]
VALUES( [、 ] ...)
[TABLESPACE tablespace_name ]
そして 範囲 _ サブパーティションはのようになります。
SUBPARTITION [ subpartition_name ]
VALUES LESS THAN( [、 ] ...)
[TABLESPACE tablespace_name ]
説明
ALTER TABLEは... PARTITIONコマンド追加し、既存のパーティション表にパーティションを追加します。パーティション化された表には、定義された区画の数に上限はありません。
新しいパーティションは 、既存のパーティションと同じタイプ( LISTRANGEまたはHASH )でなければなりません 。新しいパーティションルールは、既存のパーティションを定義するパーティションルールで指定された同じ列を参照する必要があります。
ALTER TABLE ... ADD PARTITIONステートメントを使用して、表の既存の行と追加する区画の値との間に競合する値がない限り、 DEFAULT規則を持つ表に区画を追加することができます
ALTER TABLE ... ADD PARTITIONステートメントを使用して、 MAXVALUEルールを持つ表にパーティションを追加することはできません
または、 ALTER TABLE ... SPLIT PARTITIONステートメントを使用して既存のパーティションを分割し、効果的にテーブル内のパーティション数を増やすことができます。
RANGEパーティションは昇順で指定する必要があります。 RANGEパーティション表の既存のパーティションに先行する新しいパーティションを追加することはできません。
新しいパーティションが存在するテーブルスペースを指定するには TABLESPACE句を含めます。表領域を指定しない場合、そのパーティションはデフォルトの表領域に常駐します。
表が索引付けされている場合、新しいパーティションに索引が作成されます。
ALTER TABLE ... ADD PARTITIONコマンドを使用するには 、表の所有者であるか、スーパーユーザー(または管理者)権限が必要です。
パラメーター
テーブル名
パーティション化された表の名前(スキーマ修飾名でも可)。
partition_name
作成するパーティションの名前。パーティション名は、すべてのパーティションとサブパーティションで一意でなければならず、オブジェクト識別子の命名規則に従わなければなりません。
サブパーティション名
作成するサブパーティションの名前。サブパーティション名は、すべてのパーティションとサブパーティションで一意でなければならず、オブジェクト識別子の命名規則に従わなければなりません。
[、 ] ...)
使用して、行がパーティションに分散される引用符付きリテラル値(またはリテラル値のカンマ区切りリスト)を指定します。各パーティション化ルールは少なくとも1つの値を指定する必要がありますが、ルール内で指定された値の数に制限はありません。 NULLDEFAULTLISTパーティションを指定する場合)、またはMAXVALUERANGEパーティションを指定する場合)でもかまいません。
DEFAULTまたはMAXVALUEパーティションの作成については10.4項を参照してください。
tablespace_name
パーティションまたはサブパーティションが存在する表領域の名前。
10.3.2.1 例 - LISTパーティション表へのパーティションの追加
以下の例では、パーティションをリストパーティション 販売テーブルに追加しています。表は次のコマンドを使用して作成されました。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
PARTITION BY LIST(国)
PARTITION europe VALUES( 'フランス'、 'イタリア')、
PARTITION asia VALUES( 'インド'、 'パキスタン')、
PARTITIONアメリカの価値( 'US'、 'C​​ANADA')
);
テーブルには、3つのパーティション(含まれている アメリカアジア 、およびヨーロッパ ):
acctg=# SELECT partition_name, high_value FROM ALL_TAB_PARTITIONS;
partition_name | high_value
----------------+-------------------------------------
EUROPE | FOR VALUES IN ('FRANCE', 'ITALY')
ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN')
AMERICAS | FOR VALUES IN ('US', 'CANADA')
(3 rows)
次のコマンドは、 east_asia という名前のパーティションを salesテーブルに追加します。
ALTER TABLE sales ADD PARTITION east_asia
VALUES( '中国'、 '韓国');
コマンドを呼び出した後、テーブルには east _ asiaパーティションが含まれます
acctg=# SELECT partition_name, high_value FROM ALL_TAB_PARTITIONS;
partition_name | high_value
----------------+-------------------------------------
EUROPE | FOR VALUES IN ('FRANCE', 'ITALY')
ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN')
AMERICAS | FOR VALUES IN ('US', 'CANADA')
EAST_ASIA | FOR VALUES IN ('CHINA', 'KOREA')
(4 rows)
10.3.2.2 例 - RANGEパーティション表へのパーティションの追加
次の例では、 sales という名前のレンジ・パーティション表にパーティションを追加します
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
範囲による区切り(日付)
分割q1_2012
VALUES LESS THAN( '2012-Apr-01')、
パーティションq2_2012
VALUES LESS THAN( '2012-Jul-01')、
パーティションq3_2012
VALUES LESS THAN( '2012-Oct-01')、
パーティションq4_2012
VALUES LESS THAN( '2013-Jan-01')
);
この表には、4つのパーティション( q1_2012q2_2012、q3_2012 、およびq4_2012が含まれています
acctg=# SELECT partition_name, high_value FROM ALL_TAB_PARTITIONS;
partition_name | high_value
----------------+------------------------------------------------------------------
Q1_2012 | FOR VALUES FROM (MINVALUE) TO ('01-APR-12 00:00:00')
Q2_2012 | FOR VALUES FROM ('01-APR-12 00:00:00') TO ('01-JUL-12 00:00:00')
Q3_2012 | FOR VALUES FROM ('01-JUL-12 00:00:00') TO ('01-OCT-12 00:00:00')
Q4_2012 | FOR VALUES FROM ('01-OCT-12 00:00:00') TO ('01-JAN-13 00:00:00')
(4 rows)
次のコマンドは、 q1_2013 という名前のパーティションを salesテーブルに追加します。
ALTER TABLE sales ADD PARTITION q1_2013
VALUES LESS THAN('01-APR-2013 ');
コマンドを呼び出した後、表には q1_2013パーティションが含まれています
acctg=# SELECT partition_name, high_value FROM ALL_TAB_PARTITIONS;
partition_name | high_value
----------------+------------------------------------------------------------------
Q1_2012 | FOR VALUES FROM (MINVALUE) TO ('01-APR-12 00:00:00')
Q2_2012 | FOR VALUES FROM ('01-APR-12 00:00:00') TO ('01-JUL-12 00:00:00')
Q3_2012 | FOR VALUES FROM ('01-JUL-12 00:00:00') TO ('01-OCT-12 00:00:00')
Q4_2012 | FOR VALUES FROM ('01-OCT-12 00:00:00') TO ('01-JAN-13 00:00:00')
Q1_2013 | FOR VALUES FROM ('01-JAN-13 00:00:00') TO ('01-APR-13 00:00:00')
(5 rows)
 
10.3.3 ALTER TABLE ... ADD SUBPARTITION
ALTER TABLEは... SUBPARTITIONコマンド追加し、既存のサブパーティションのパーティションにサブパーティションを追加します。構文は次のとおりです。
ALTER TABLE table _ name MODIFY PARTITION パーティション _ name
ADD SUBPARTITION
サブパーティション _ 定義;
ここで、 subpartition_definitionは次のとおりです。
{ list_subpartition | range_subpartition }
そして リスト _ サブパーティションは以下とおりです。
SUBPARTITION [ subpartition_name ]
VALUES( [、 ] ...)
[TABLESPACE tablespace_name ]
そして range_subpartitionは以下とおりです。
SUBPARTITION [ subpartition_name ]
VALUES LESS THAN( [、 ] ...)
[TABLESPACE tablespace_name ]
説明
ALTER TABLEは... SUBPARTITIONコマンド追加し、既存のパーティションにサブパーティションを追加します。パーティションはすでにサブパーティション化されている必要があります。定義されたサブパーティションの数に上限はありません。
新しいサブパーティションは 、既存のサブパーティションと同じタイプ( LISTRANGEまたはHASHである必要があります 。新しいサブパーティション・ルールは、既存のサブパーティションを定義するサブパーティション化ルールで指定されているのと同じ列を参照する必要があります。
あなたは使用することができます ALTER TABLEを ...限り、追加する既存のテーブルの行とサブパーティションの値の間に矛盾する値が存在しないように、デフォルトのルールを持つテーブルにサブパーティションを追加するSUBPARTITION文追加します
MAXVALUEルールを持つ表にサブパーティションを追加するには、 ALTER TABLE ... ADD SUBPARTITIONステートメントを使用することはできません
ALTER TABLE ... SPLIT SUBPARTITION文を使用して既存のサブパーティションを分割し 、事実上表にサブパーティションを追加することができます。
範囲のサブパーティション化された表の既存のサブパーティションに先行する新しいサブパーティションを追加することはできません。範囲のサブパーティションは昇順で指定する必要があります。
サブパーティションが存在する表領域を指定するには TABLESPACE句を含めます。表領域を指定しないと、サブパーティションはデフォルトの表領域に作成されます。
表が索引付けされている場合、新しいサブパーティションに索引が作成されます。
ALTER TABLE ... ADD SUBPARTITIONコマンドを使用するには 、テーブル所有者であるか、スーパーユーザー(または管理者)権限を持っている必要があります。
パラメーター
テーブル名
サブパーティションが存在するパーティション表の名前(スキーマ修飾名も可)。
partition_name
新しいサブパーティションが存在するパーティションの名前。
サブパーティション名
作成するサブパーティションの名前。サブパーティション名は、すべてのパーティションとサブパーティションで一意でなければならず、オブジェクト識別子の命名規則に従わなければなりません。
[、 ] ...)
使用して、表エントリをパーティションにグループ化する引用符付きリテラル値(またはリテラル値のコンマ区切りリスト)を指定します。各パーティション化ルールは少なくとも1つの値を指定する必要がありますが、ルール内で指定された値の数に制限はありません。 NULLDEFAULTLISTパーティションを指定する場合)、またはMAXVALUERANGEパーティションを指定する場合)でもかまいません。
DEFAULTまたはMAXVALUEパーティションの作成については10.4項を参照してください。
tablespace_name
サブパーティションが存在する表領域の名前。
 
10.3.3.1 例 - LIST-RANGEパーティション表にサブパーティションを追加する
次の例では、 RANGEサブパーティションをリスト分割されたsales表に追加します。 salesテーブルは次のコマンドで作成されました。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
PARTITION BY LIST(国)
範囲によるサブパラメータ(日付)
PARTITION europe VALUES( 'FRANCE'、 'ITALY')
SUBPARTITION europe_2011
VALUES LESS THAN( '2012-Jan-01')、
SUBPARTITION europe_2012
VALUES LESS THAN( '2013-Jan-01')
)、
PARTITIONアジアバリュー( 'インド'、 'パキスタン')
サブセクションasia_2011
VALUES LESS THAN( '2012-Jan-01')、
SUBPARTITION asia_2012
VALUES LESS THAN( '2013-Jan-01')
)、
PARTITIONアメリカの価値( 'US'、 'C​​ANADA')
SUBPARTITION americas_2011
VALUES LESS THAN( '2012-Jan-01')、
SUBPARTITION americas_2012
VALUES LESS THAN( '2013-Jan-01')
);
sales表には3つのパーティション、名前のヨーロッパ、アジア、 南北アメリカを持っています。各パーティションには、2つの範囲定義されたサブパーティションがあります。
acctg=# SELECT partition_name, subpartition_name, high_value FROM ALL_TAB_SUBPARTITIONS;
partition_name | subpartition_name | high_value
----------------+-------------------+-------------------------------------------------
EUROPE | EUROPE_2011 | FOR VALUES FROM (MINVALUE) TO ('01-JAN-12 00:00:00')
EUROPE | EUROPE_2012 | FOR VALUES FROM ('01-JAN-12 00:00:00') TO ('01-JAN-13 00:00:00')
ASIA | ASIA_2011 | FOR VALUES FROM (MINVALUE) TO ('01-JAN-12 00:00:00')
ASIA | ASIA_2012 | FOR VALUES FROM ('01-JAN-12 00:00:00') TO ('01-JAN-13 00:00:00')
AMERICAS | AMERICAS_2011 | FOR VALUES FROM (MINVALUE) TO ('01-JAN-12 00:00:00')
AMERICAS | AMERICAS_2012 | FOR VALUES FROM ('01-JAN-12 00:00:00') TO ('01-JAN-13 00:00:00')
(6 rows)
次のコマンドは、 europe_2013 という名前のサブパーティションを追加します
ALTER TABLEの販売変更パーティションヨーロッパ
追加情報europe_2013
VALUES LESS THAN( '2015-Jan-01');
コマンドを呼び出すと、表には europe_2013 という名前のサブパーティションが含まれ ます
acctg=# SELECT partition_name, subpartition_name, high_value FROM ALL_TAB_SUBPARTITIONS;
partition_name | subpartition_name | high_value
----------------+-------------------+--------------------------------------------------
EUROPE | EUROPE_2011 | FOR VALUES FROM (MINVALUE) TO ('01-JAN-12 00:00:00')
EUROPE | EUROPE_2012 | FOR VALUES FROM ('01-JAN-12 00:00:00') TO ('01-JAN-13 00:00:00')
EUROPE | EUROPE_2013 | FOR VALUES FROM ('01-JAN-13 00:00:00') TO ('01-JAN-15 00:00:00')
ASIA | ASIA_2011 | FOR VALUES FROM (MINVALUE) TO ('01-JAN-12 00:00:00')
ASIA | ASIA_2012 | FOR VALUES FROM ('01-JAN-12 00:00:00') TO ('01-JAN-13 00:00:00')
AMERICAS | AMERICAS_2011 | FOR VALUES FROM (MINVALUE) TO ('01-JAN-12 00:00:00')
AMERICAS | AMERICAS_2012 | FOR VALUES FROM ('01-JAN-12 00:00:00') TO ('01-JAN-13 00:00:00')
(7 rows)
新しい範囲サブパーティションを追加する場合、サブパーティション化ルールは既存のサブパーティションの後ろに ある範囲を指定する必要があることに注意してください
10.3.3.2 例 - RANGE-LISTのパーティション表にサブパーティションを追加する
次の例では、 LISTサブパーティションをRANGEパーティション化されたsales表に追加します。 salesテーブルは次のコマンドで作成されました。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
範囲による区切り(日付)
SUBPARTITION BY LIST
(国)

PARTITION first_half_2012 VALUES LESS THAN('01 -JUL-2012 ')
SUBPARTITIONヨーロッパの 価値 ( 'イタリア'、 'フランス')、
SUBPARTITION アメリカの バリュー ( 'US'、 'CANADA')
)、
PARTITION second_half_2012 VALUES LESS THAN('01-JAN-2013 ')
SUBPARTITIONアジア バリュー ( 'インド'、 'パキスタン')

);
上記のコマンドを実行すると、 salesテーブルにはfirst_half_2012second_half_2012の 2つのパーティションがありますfirst_half_2012パーティションは、 ヨーロッパアメリカという名前の2つのサブパーティションを、有し、 第2 _ _ 半分 2012パーティションは、 アジアという名前の、一つのパーティションがあります。
acctg=# SELECT partition_name, subpartition_name, high_value FROM ALL_TAB_SUBPARTITIONS;
partition_name | subpartition_name | high_value
------------------+-------------------+-------------------------------------
FIRST_HALF_2012 | AMERICAS | FOR VALUES IN ('US', 'CANADA')
FIRST_HALF_2012 | EUROPE | FOR VALUES IN ('ITALY', 'FRANCE')
SECOND_HALF_2012 | ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN')
(3 rows)
次のコマンドは、サブパーティションに追加します _ アジア 東アジアという名前second_half_2012パーティションを、:
ALTER TABLE sales MODIFY PARTITION second_half_2012
追加サブパラメータeast_asia VALUES( 'CHINA')
;
コマンドを呼び出すと、表には east_asia という名前のサブパーティションが含まれ ます
acctg=# SELECT partition_name, subpartition_name, high_value FROM ALL_TAB_SUBPARTITIONS;
partition_name | subpartition_name | high_value
------------------+-------------------+-------------------------------------
FIRST_HALF_2012 | AMERICAS | FOR VALUES IN ('US', 'CANADA')
FIRST_HALF_2012 | EUROPE | FOR VALUES IN ('ITALY', 'FRANCE')
SECOND_HALF_2012 | EAST_ASIA | FOR VALUES IN ('CHINA')
SECOND_HALF_2012 | ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN')
(4 rows)
 
10.3.4 ALTER TABLE ... SPLIT PARTITION
ALTER TABLE ... SPLIT PARTITIONコマンドを使用して 、1つのパーティションを2つのパーティションに分割し、新しいパーティション間でパーティションの内容を再配布します。コマンド構文には2つの形式があります。
最初の形式は、 RANGEパーティションを2つのパーティションに分割します。
ALTER TABLE table _ name SPLIT PARTITION パーティション _ name
AT( 範囲 _ 部分 _


PARTITION
new_part1
[TABLESPACE tablespace_name ]
PARTITION new_part2
[TABLESPACE tablespace_name ]
);
2番目の形式は、 LISTパーティションを2つのパーティションに分割します。
ALTER TABLE table _ name SPLIT PARTITION パーティション _ name
VALUES( [、 ] ...)


PARTITION
new_part1
[TABLESPACE tablespace_name ]
PARTITION new_part2
[TABLESPACE tablespace_name ]
);
説明
ALTER TABLE ... SPLIT PARTITION コマンドは、既存のリストまたは範囲パーティション表にパーティションを追加します。 ALTER TABLE ... SPLIT PARTITIONコマンドは、パーティションをHASHパーティション表に追加できないことに注意してください。表が持つ可能性があるパーティションの数に上限はありません。
ALTER TABLE ... SPLIT PARTITIONコマンドを実行すると 、Advanced Serverは2つの新しいパーティションを作成し、それらの間に古いパーティションの内容を再分配します(パーティション化ルールによって制約されます)。
パーティションが存在する表領域を指定するには TABLESPACE句を含めます。表領域を指定しない場合、そのパーティションはデフォルトの表領域に常駐します。
表が索引付けされている場合、新しいパーティションに索引が作成されます。
ALTER TABLE ... SPLIT PARTITIONコマンドを使用するには 、テーブル所有者であるか、スーパーユーザー(または管理者)権限を持っている必要があります。
パラメーター
テーブル名
パーティション化された表の名前(スキーマ修飾名でも可)。
partition_name
分割されているパーティションの名前。
new_part1
作成する最初の新しいパーティションの名前。パーティション名は、すべてのパーティションとサブパーティションで一意でなければならず、オブジェクト識別子の命名規則に従わなければなりません。
new_part1は、 ALTER TABLE ... SPLIT PARTITIONコマンドで指定されたパーティション制約を満たす行を受け取ります。
new_part2
作成される2番目の新しいパーティションの名前。パーティション名は、すべてのパーティションとサブパーティションで一意でなければならず、オブジェクト識別子の命名規則に従わなければなりません。
new_part2は、 ALTER TABLE ... SPLIT PARTITIONコマンドで指定されたパーティション化制約によってnew_part1に行が送られることはありません。
range_part_value
range_part_value使用して、新しいパーティションを作成する境界の規則を指定します。パーティション化ルールには、2つの演算子(つまり、より大きいか等しい演算子、およびより小さい演算子)を持つデータ型の列が少なくとも1つ含まれている必要があります。範囲境界は、 LESS THAN節に対して評価され、非包含的である。 2010年1月1日の日付境界には、2009年12月31日以前の日付値のみが含まれます。
[、 ] ...)
使用して、行がパーティションに分散される引用符付きリテラル値(またはリテラル値のカンマ区切りリスト)を指定します。各パーティション化ルールは少なくとも1つの値を指定する必要がありますが、ルール内で指定された値の数に制限はありません。
DEFAULTまたはMAXVALUEパーティションの作成については10.4項を参照してください。
tablespace_name
パーティションまたはサブパーティションが存在する表領域の名前。
10.3.4.1 例 - LISTパーティションの分割
この例では、リストパーティション 販売テーブルのパーティションの1つを2つの新しいパーティションに分割し、それらの間にパーティションの内容を再配布します。 salesテーブルは、次の文で作成されます。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
PARTITION BY LIST(国)
PARTITION europe VALUES( 'フランス'、 'イタリア')、
PARTITION asia VALUES( 'インド'、 'パキスタン')、
PARTITIONアメリカの価値( 'US'、 'C​​ANADA')
);
テーブル定義は、3つのパーティション(作成 ヨーロッパアジア南北アメリカを )。次のコマンドは、各パーティションに行を追加します。
INSERT INTO sales VALUES
(10、 '4519b'、 'FRANCE'、'17-Jan-2012 '、' 45000 ')、
(20、 '3788a'、 'INDIA'、'01-Mar-2012 '、' 75000 ')、
(40、'9519b '、' US '、'12-apr-2012'、 '145000')、
(20、 '3788a'、 'PAKISTAN'、'04-Jun-2012 '、' 37500 ')、
(40、 '4577b'、 'US'、'11-Nov-2012 '、' 25000 ')、
(30、 '7588b'、 'C​​ANADA'、'14 -Dec-2012 '、' 50000 ')、
(30、 '9519b'、 'C​​ANADA'、'01 -Feb-2012 '、' 75000 ')、
(30、 '4519b'、 'C​​ANADA'、'08-Apr-2012 '、' 120000 ')、
(40、 '3788a'、 'US'、'12-May-2012 '、' 4950 ')、
(10、'9519b '、' ITALY '、'07-Jan-2012'、 '15000')、
(10、 '9519a'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ')、
(10、 '9519b'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ')、
(20、 '3788b'、 'INDIA'、'21 -ept-2012 '、' 5090 ')、
(40、 '4788a'、 'US'、 '23 -ept-2012'、 '4950')、
(40、 '4788b'、 'US'、'09 -Oct-2012 '、' 15000 ')、
(20、 '4519a'、 'INDIA'、'18-Oct-2012 '、' 650000 ')、
(20、 '4519b'、 'INDIA'、 '2-Dec-2012'、 '5090');
行はパーティション間で分散されます。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date | amount
----------------+---------+---------+----------+--------------------+--------
sales_americas | 40 | 9519b | US | 12-APR-12 00:00:00 | 145000
sales_americas | 40 | 4577b | US | 11-NOV-12 00:00:00 | 25000
sales_americas | 30 | 7588b | CANADA | 14-DEC-12 00:00:00 | 50000
sales_americas | 30 | 9519b | CANADA | 01-FEB-12 00:00:00 | 75000
sales_americas | 30 | 4519b | CANADA | 08-APR-12 00:00:00 | 120000
sales_americas | 40 | 3788a | US | 12-MAY-12 00:00:00 | 4950
sales_americas | 40 | 4788a | US | 23-SEP-12 00:00:00 | 4950
sales_americas | 40 | 4788b | US | 09-OCT-12 00:00:00 | 15000
sales_europe | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_europe | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_europe | 10 | 9519a | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_europe | 10 | 9519b | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_asia | 20 | 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_asia | 20 | 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_asia | 20 | 3788b | INDIA | 21-SEP-12 00:00:00 | 5090
sales_asia | 20 | 4519a | INDIA | 18-OCT-12 00:00:00 | 650000
sales_asia | 20 | 4519b | INDIA | 02-DEC-12 00:00:00 | 5090
(17 rows)
次のコマンドは、 americasパーティションをuscanadaという2つのパーティションに分割します。
ALTER TABLE sales SPLIT PARTITIONアメリカ
VALUES( 'US')
INTO(PARTITION、PARTITION、カナダ);
SELECT文では、行が再配布されていることを確認しました。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date | amount
--------------+---------+---------+----------+--------------------+--------
sales_canada | 30 | 7588b | CANADA | 14-DEC-12 00:00:00 | 50000
sales_canada | 30 | 9519b | CANADA | 01-FEB-12 00:00:00 | 75000
sales_canada | 30 | 4519b | CANADA | 08-APR-12 00:00:00 | 120000
sales_europe | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_europe | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_europe | 10 | 9519a | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_europe | 10 | 9519b | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_asia | 20 | 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_asia | 20 | 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_asia | 20 | 3788b | INDIA | 21-SEP-12 00:00:00 | 5090
sales_asia | 20 | 4519a | INDIA | 18-OCT-12 00:00:00 | 650000
sales_asia | 20 | 4519b | INDIA | 02-DEC-12 00:00:00 | 5090
sales_us | 40 | 9519b | US | 12-APR-12 00:00:00 | 145000
sales_us | 40 | 4577b | US | 11-NOV-12 00:00:00 | 25000
sales_us | 40 | 3788a | US | 12-MAY-12 00:00:00 | 4950
sales_us | 40 | 4788a | US | 23-SEP-12 00:00:00 | 4950
sales_us | 40 | 4788b | US | 09-OCT-12 00:00:00 | 15000
(17 rows)
10.3.4.2 例 - RANGEパーティションの分割
この例では、レンジ・パーティション化されたsales q4_2012パーティションを2つのパーティションに分割し、パーティションの内容を再配布します。 salesテーブルを作成するには、次のコマンドを使用します。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
範囲による区切り(日付)
分割q1_2012
VALUES LESS THAN( '2012-Apr-01')、
パーティションq2_2012
VALUES LESS THAN( '2012-Jul-01')、
パーティションq3_2012
VALUES LESS THAN( '2012-Oct-01')、
パーティションq4_2012
VALUES LESS THAN( '2013-Jan-01')
);
テーブル定義は、4つのパーティション( q1_2012q2_2012、 q3_2012 、およびq4_2012 )を作成します。次のコマンドは、各パーティションに行を追加します。
INSERT INTO sales VALUES
(10、 '4519b'、 'FRANCE'、'17-Jan-2012 '、' 45000 ')、
(20、 '3788a'、 'INDIA'、'01-Mar-2012 '、' 75000 ')、
(40、'9519b '、' US '、'12-apr-2012'、 '145000')、
(20、 '3788a'、 'PAKISTAN'、'04-Jun-2012 '、' 37500 ')、
(40、 '4577b'、 'US'、'11-Nov-2012 '、' 25000 ')、
(30、 '7588b'、 'C​​ANADA'、'14 -Dec-2012 '、' 50000 ')、
(30、 '9519b'、 'C​​ANADA'、'01 -Feb-2012 '、' 75000 ')、
(30、 '4519b'、 'C​​ANADA'、'08-Apr-2012 '、' 120000 ')、
(40、 '3788a'、 'US'、'12-May-2012 '、' 4950 ')、
(10、'9519b '、' ITALY '、'07-Jan-2012'、 '15000')、
(10、 '9519a'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ')、
(10、 '9519b'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ')、
(20、 '3788b'、 'INDIA'、'21 -ept-2012 '、' 5090 ')、
(40、 '4788a'、 'US'、 '23 -ept-2012'、 '4950')、
(40、 '4788b'、 'US'、'09 -Oct-2012 '、' 15000 ')、
(20、 '4519a'、 'INDIA'、'18-Oct-2012 '、' 650000 ')、
(20、 '4519b'、 'INDIA'、 '2-Dec-2012'、 '5090');
SELECT文では、期待通りに行がパーティション間で分散されていることを確認しました。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date | amount
---------------+---------+---------+----------+--------------------+--------
sales_q1_2012 | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_q1_2012 | 20 | 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_q1_2012 | 30 | 9519b | CANADA | 01-FEB-12 00:00:00 | 75000
sales_q2_2012 | 40 | 9519b | US | 12-APR-12 00:00:00 | 145000
sales_q2_2012 | 20 | 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_q2_2012 | 30 | 4519b | CANADA | 08-APR-12 00:00:00 | 120000
sales_q2_2012 | 40 | 3788a | US | 12-MAY-12 00:00:00 | 4950
sales_q3_2012 | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_q3_2012 | 10 | 9519a | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_q3_2012 | 10 | 9519b | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_q3_2012 | 20 | 3788b | INDIA | 21-SEP-12 00:00:00 | 5090
sales_q3_2012 | 40 | 4788a | US | 23-SEP-12 00:00:00 | 4950
sales_q4_2012 | 40 | 4577b | US | 11-NOV-12 00:00:00 | 25000
sales_q4_2012 | 30 | 7588b | CANADA | 14-DEC-12 00:00:00 | 50000
sales_q4_2012 | 40 | 4788b | US | 09-OCT-12 00:00:00 | 15000
sales_q4_2012 | 20 | 4519a | INDIA | 18-OCT-12 00:00:00 | 650000
sales_q4_2012 | 20 | 4519b | INDIA | 02-DEC-12 00:00:00 | 5090
(17 rows)
次のコマンドは、 q4_2012パーティションをq4_2012_p1q4_2012_p2の 2つのパーティションに分割します
ALTER TABLE sales SPLIT PARTITION q4_2012
AT('15-Nov-2012 ')


パーティションq4_2012_p1、
パーティションq4_2012_p2
);
SELECT文では、行が新しいパーティションに再分散されていることを確認しました。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date |amount
------------------+---------+---------+----------+--------------------+------
sales_q1_2012 | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_q1_2012 | 20 | 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_q1_2012 | 30 | 9519b | CANADA | 01-FEB-12 00:00:00 | 75000
sales_q2_2012 | 40 | 9519b | US | 12-APR-12 00:00:00 |145000
sales_q2_2012 | 20 | 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_q2_2012 | 30 | 4519b | CANADA | 08-APR-12 00:00:00 |120000
sales_q2_2012 | 40 | 3788a | US | 12-MAY-12 00:00:00 | 4950
sales_q3_2012 | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_q3_2012 | 10 | 9519a | FRANCE | 18-AUG-12 00:00:00 |650000
sales_q3_2012 | 10 | 9519b | FRANCE | 18-AUG-12 00:00:00 |650000
sales_q3_2012 | 20 | 3788b | INDIA | 21-SEP-12 00:00:00 | 5090
sales_q3_2012 | 40 | 4788a | US | 23-SEP-12 00:00:00 | 4950
sales_q4_2012_p1 | 40 | 4577b | US | 11-NOV-12 00:00:00 | 25000
sales_q4_2012_p1 | 40 | 4788b | US | 09-OCT-12 00:00:00 | 15000
sales_q4_2012_p1 | 20 | 4519a | INDIA | 18-OCT-12 00:00:00 |650000
sales_q4_2012_p2 | 30 | 7588b | CANADA | 14-DEC-12 00:00:00 | 50000
sales_q4_2012_p2 | 20 | 4519b | INDIA | 02-DEC-12 00:00:00 | 5090
(17 rows)
 
10.3.5 ALTER TABLE ... SPLIT SUBPARTITION
ALTER TABLE ... SPLIT SUBPARTITIONコマンドを使用して 、単一のサブパーティションを2つのサブパーティションに分割し、サブパーティションの内容を再配布します。コマンドには2つのバリエーションがあります。
最初のバリエーションでは、範囲のサブパーティションを2つのサブパーティションに分割します。
ALTER TABLE table _ name SPLIT SUBPARTITION サブパーティション _ name
AT(
範囲 _ 部分 _


SUBPARTITION
new _ subpart1
[TABLESPACE
表スペース _ 名前 ]、
SUBPARTITION
new _ subpart2
[TABLESPACE
tablespace _ name ]
);
2番目のバリエーションでは、リストのサブパーティションを2つのサブパーティションに分割します。
ALTER TABLE table _ name SPLIT SUBPARTITION サブパーティション _ name
VALUES( [、 ] ...)


SUBPARTITION
new _ subpart1
[TABLESPACE
表スペース _ 名前 ]、
SUBPARTITION
new _ subpart2
[TABLESPACE
tablespace _ name ]
);
説明
ALTER TABLE ... SPLITの SUBPARTITIONコマンドは、既存のサブパーティションテーブルにサブパーティションを追加します。定義されたサブパーティションの数に上限はありません。 ALTER TABLE ... SPLIT SUBPARTITIONコマンドを実行すると、Advanced Serverは2つの新しいサブパーティションを作成し、指定されたサブパーティション・ルールによって制約された値を含む行をnew_subpart1に 、残りの行をnew_subpart2に移動します。
新しいサブパーティション・ルールは、既存のサブパーティションを定義するルールで指定された列を参照する必要があります。
新しいサブパーティションが存在する表領域を指定するには TABLESPACE句を含めます。表領域を指定しないと、サブパーティションはデフォルトの表領域に作成されます。
表が索引付けされている場合、新しいサブパーティションに索引が作成されます。
ALTER TABLE ... SPLIT SUBPARTITIONコマンドを使用するには 、テーブル所有者であるか、スーパーユーザー(または管理者)権限を持っている必要があります。
パラメーター
テーブル名
パーティション化された表の名前(スキーマ修飾名でも可)。
サブパーティション名
分割されているサブパーティションの名前。
new_subpart1
作成される最初の新しいサブパーティションの名前。サブパーティション名は、すべてのパーティションとサブパーティションで一意でなければならず、オブジェクト識別子の命名規則に従わなければなりません。
new_subpart1は、 ALTER TABLE ... SPLIT SUBPARTITIONコマンドで指定されたサブパーティション化制約を満たす行を受け取ります
new_subpart2
作成する2番目の新しいサブパーティションの名前。サブパーティション名は、すべてのパーティションとサブパーティションで一意でなければならず、オブジェクト識別子の命名規則に従わなければなりません。
new_subpart2は、行が、ALTER TABLE ... SPLIT SUBPARTITIONコマンドで指定されたサブパーティションの制約によりnew_subpart1するように指示されていない受信します。
[、 ] ...)
使用して、表エントリをパーティションにグループ化する引用符付きリテラル値(またはリテラル値のコンマ区切りリスト)を指定します。各パーティション化ルールは少なくとも1つの値を指定する必要がありますが、ルール内で指定された値の数に制限はありません。 は、 NULLDEFAULTLISTサブパーティションを指定する場合)、またはMAXVALUERANGEサブパーティションを指定する場合)でもかまいません。
DEFAULTまたはMAXVALUEパーティションの作成については10.4項を参照してください。
tablespace_name
パーティションまたはサブパーティションが存在する表領域の名前。
10.3.5.1 例 - LISTサブパーティションの分割
次の例では、2つの新しいサブパーティション間でサブパーティションの内容を再配布するリストのサブパーティションを分割します。サンプル・テーブル( sales )は、次のコマンドで作成されました。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
範囲による区切り(日付)
SUBPARTITION BY LIST
(国)

PARTITION
first_half_2012 VALUES LESS THAN('01 -JUL-2012 ')
SUBPARTITION p1_europe VALUES ( 'イタリア'、 'フランス')、
SUBPARTITION p1_americas VALUES ( 'US'、 'CANADA')
)、
PARTITION second_half_2012 VALUES LESS THAN('01-JAN-2013 ')
SUBPARTITION p2_europe VALUES ( 'イタリア'、 'フランス')、
SUBPARTITION p2_americas VALUES ( 'US'、 'CANADA')

);
sales表には2つのパーティション、名前のfirst_half_2012、およびsecond_half_2012を持っています。各パーティションには、 国の列の値に基づいてパーティションの内容をサブパーティションに配布する2つの範囲定義されたサブパーティションがあります。
acctg=# SELECT partition_name, subpartition_name, high_value FROM ALL_TAB_SUBPARTITIONS;
partition_name | subpartition_name | high_value
------------------+-------------------+-----------------------------------
FIRST_HALF_2012 | P1_AMERICAS | FOR VALUES IN ('US', 'CANADA')
FIRST_HALF_2012 | P1_EUROPE | FOR VALUES IN ('ITALY', 'FRANCE')
SECOND_HALF_2012 | P2_AMERICAS | FOR VALUES IN ('US', 'CANADA')
SECOND_HALF_2012 | P2_EUROPE | FOR VALUES IN ('ITALY', 'FRANCE')
(4 rows)
次のコマンドは、各サブパーティションに行を追加します。
INSERT INTO sales VALUES
(10、 '4519b'、 'FRANCE'、'17-Jan-2012 '、' 45000 ')、
(40、'9519b '、' US '、'12-apr-2012'、 '145000')、
(40、 '4577b'、 'US'、'11-Nov-2012 '、' 25000 ')、
(30、 '7588b'、 'C​​ANADA'、'14 -Dec-2012 '、' 50000 ')、
(30、 '9519b'、 'C​​ANADA'、'01 -Feb-2012 '、' 75000 ')、
(30、 '4519b'、 'C​​ANADA'、'08-Apr-2012 '、' 120000 ')、
(40、 '3788a'、 'US'、'12-May-2012 '、' 4950 ')、
(10、'9519b '、' ITALY '、'07-Jan-2012'、 '15000')、
(10、 '9519a'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ')、
(10、 '9519b'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ')、
(40、 '4788a'、 'US'、 '23 -ept-2012'、 '4950')、
(40、 '4788b'、 'US'、'09 -Oct-2012 '、' 15000 ');
SELECT文では、行が正しくサブパーティション間で分散されていることを確認しました。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date | amount
-------------------+---------+---------+---------+--------------------+--------
sales_p1_americas | 40 | 9519b | US | 12-APR-12 00:00:00 | 145000
sales_p1_americas | 30 | 9519b | CANADA | 01-FEB-12 00:00:00 | 75000
sales_p1_americas | 30 | 4519b | CANADA | 08-APR-12 00:00:00 | 120000
sales_p1_americas | 40 | 3788a | US | 12-MAY-12 00:00:00 | 4950
sales_p1_europe | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_p2_americas | 40 | 4577b | US | 11-NOV-12 00:00:00 | 25000
sales_p2_americas | 30 | 7588b | CANADA | 14-DEC-12 00:00:00 | 50000
sales_p2_americas | 40 | 4788a | US | 23-SEP-12 00:00:00 | 4950
sales_p2_americas | 40 | 4788b | US | 09-OCT-12 00:00:00 | 15000
sales_p2_europe | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_p2_europe | 10 | 9519a | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_p2_europe | 10 | 9519b | FRANCE | 18-AUG-12 00:00:00 | 650000
(12 rows)
次のコマンドは、 p2_americasサブパーティションを2つの新しいサブパーティションに分割し 、内容を再配布します。
ALTER TABLE sales SPLIT SUBPARTITION p2_americas
VALUES ( 'US')


サブパラメータp2_us、
SUBPARTITION p2_canada
);
コマンドを呼び出した後、 p2_americasサブパーティションが削除されました。その代わりに、サーバーは2つの新しいサブパーティション( p2_usp2_canada )を作成しました。
acctg=# SELECT partition_name, subpartition_name, high_value FROM ALL_TAB_SUBPARTITIONS;
partition_name | subpartition_name | high_value
------------------+-------------------+-----------------------------------
FIRST_HALF_2012 | P1_AMERICAS | FOR VALUES IN ('US', 'CANADA')
FIRST_HALF_2012 | P1_EUROPE | FOR VALUES IN ('ITALY', 'FRANCE')
SECOND_HALF_2012 | P2_CANADA | FOR VALUES IN ('CANADA')
SECOND_HALF_2012 | P2_US | FOR VALUES IN ('US')
SECOND_HALF_2012 | P2_EUROPE | FOR VALUES IN ('ITALY', 'FRANCE')
(5 rows)
照会 売上テーブルはp2_americasサブパーティションの内容が再配布されていることを示しています。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date |amount
-------------------+---------+---------+---------+--------------------+------
sales_p1_americas | 40 | 9519b | US | 12-APR-12 00:00:00 |145000
sales_p1_americas | 30 | 9519b | CANADA | 01-FEB-12 00:00:00 | 75000
sales_p1_americas | 30 | 4519b | CANADA | 08-APR-12 00:00:00 |120000
sales_p1_americas | 40 | 3788a | US | 12-MAY-12 00:00:00 | 4950
sales_p1_europe | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_p2_canada | 30 | 7588b | CANADA | 14-DEC-12 00:00:00 | 50000
sales_p2_europe | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_p2_europe | 10 | 9519a | FRANCE | 18-AUG-12 00:00:00 |650000
sales_p2_europe | 10 | 9519b | FRANCE | 18-AUG-12 00:00:00 |650000
sales_p2_us | 40 | 4577b | US | 11-NOV-12 00:00:00 | 25000
sales_p2_us | 40 | 4788a | US | 23-SEP-12 00:00:00 | 4950
sales_p2_us | 40 | 4788b | US | 09-OCT-12 00:00:00 | 15000
(12 rows)
10.3.5.2 例 - RANGEサブパーティションの分割
次の例では、範囲サブパーティションを分割し、2つの新しいサブパーティション間でサブパーティションの内容を再配布します。サンプル・テーブル( sales )は、次のコマンドで作成されました。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
PARTITION BY LIST(国)
範囲によるサブパラメータ(日付)
PARTITION europe VALUES( 'FRANCE'、 'ITALY')
SUBPARTITION europe_2011
VALUES LESS THAN( '2012-Jan-01')、
SUBPARTITION europe_2012
VALUES LESS THAN( '2013-Jan-01')
)、
PARTITIONアジアバリュー( 'インド'、 'パキスタン')
サブセクションasia_2011
VALUES LESS THAN( '2012-Jan-01')、
SUBPARTITION asia_2012
VALUES LESS THAN( '2013-Jan-01')
)、
PARTITIONアメリカの価値( 'US'、 'C​​ANADA')
SUBPARTITION americas_2011
VALUES LESS THAN( '2012-Jan-01')、
SUBPARTITION americas_2012
VALUES LESS THAN( '2013-Jan-01')
);
sales表は、3つのパーティション( ヨーロッパ、アジア、 南北アメリカを )持っています。各パーティションには、 日付の列の値によってパーティションの内容をサブパーティションにソートする2つの範囲定義されたサブパーティションがあります。
acctg=# SELECT partition_name, subpartition_name, high_value FROM ALL_TAB_SUBPARTITIONS;
partition_name | subpartition_name | high_value
----------------+-------------------+------------------------------------------------
EUROPE | EUROPE_2012 | FOR VALUES FROM ('01-JAN-12 00:00:00') TO ('01-JAN-13 00:00:00')
EUROPE | EUROPE_2011 | FOR VALUES FROM (MINVALUE) TO ('01-JAN-12 00:00:00')
ASIA | ASIA_2012 | FOR VALUES FROM ('01-JAN-12 00:00:00') TO ('01-JAN-13 00:00:00')
ASIA | ASIA_2011 | FOR VALUES FROM (MINVALUE) TO ('01-JAN-12 00:00:00')
AMERICAS | AMERICAS_2012 | FOR VALUES FROM ('01-JAN-12 00:00:00') TO ('01-JAN-13 00:00:00')
AMERICAS | AMERICAS_2011 | FOR VALUES FROM (MINVALUE) TO ('01-JAN-12 00:00:00')
(6 rows)
次のコマンドは、各サブパーティションに行を追加します。
INSERT INTO sales VALUES
(10、 '4519b'、 'FRANCE'、'17-Jan-2012 '、' 45000 ')、
(20、 '3788a'、 'INDIA'、'01-Mar-2012 '、' 75000 ')、
(40、'9519b '、' US '、'12-apr-2012'、 '145000')、
(20、 '3788a'、 'PAKISTAN'、'04-Jun-2012 '、' 37500 ')、
(40、 '4577b'、 'US'、'11-Nov-2012 '、' 25000 ')、
(30、 '7588b'、 'C​​ANADA'、'14 -Dec-2012 '、' 50000 ')、
(30、 '9519b'、 'C​​ANADA'、'01 -Feb-2012 '、' 75000 ')、
(30、 '4519b'、 'C​​ANADA'、'08-Apr-2012 '、' 120000 ')、
(40、 '3788a'、 'US'、'12-May-2012 '、' 4950 ')、
(10、'9519b '、' ITALY '、'07-Jan-2012'、 '15000')、
(10、 '9519a'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ')、
(10、 '9519b'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ')、
(20、 '3788b'、 'INDIA'、'21 -ept-2012 '、' 5090 ')、
(40、 '4788a'、 'US'、 '23 -ept-2012'、 '4950')、
(40、 '4788b'、 'US'、'09 -Oct-2012 '、' 15000 ')、
(20、 '4519a'、 'INDIA'、'18-Oct-2012 '、' 650000 ')、
(20、 '4519b'、 'INDIA'、 '2-Dec-2012'、 '5090');
SELECT文では、行がサブパーティション間で分散されていることを確認しました。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date | amount
---------------------+---------+---------+----------+--------------------+--------
sales_americas_2012 | 40 | 9519b | US | 12-APR-12 00:00:00 | 145000
sales_americas_2012 | 40 | 4577b | US | 11-NOV-12 00:00:00 | 25000
sales_americas_2012 | 30 | 7588b | CANADA | 14-DEC-12 00:00:00 | 50000
sales_americas_2012 | 30 | 9519b | CANADA | 01-FEB-12 00:00:00 | 75000
sales_americas_2012 | 30 | 4519b | CANADA | 08-APR-12 00:00:00 | 120000
sales_americas_2012 | 40 | 3788a | US | 12-MAY-12 00:00:00 | 4950
sales_americas_2012 | 40 | 4788a | US | 23-SEP-12 00:00:00 | 4950
sales_americas_2012 | 40 | 4788b | US | 09-OCT-12 00:00:00 | 15000
sales_europe_2012 | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_europe_2012 | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_europe_2012 | 10 | 9519a | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_europe_2012 | 10 | 9519b | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_asia_2012 | 20 | 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_asia_2012 | 20 | 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_asia_2012 | 20 | 3788b | INDIA | 21-SEP-12 00:00:00 | 5090
sales_asia_2012 | 20 | 4519a | INDIA | 18-OCT-12 00:00:00 | 650000
sales_asia_2012 | 20 | 4519b | INDIA | 02-DEC-12 00:00:00 | 5090
(17 rows)
次のコマンドは、 americas_2012サブパーティションを2つの新しいサブパーティションに分割し 、内容を再配布します。
ALTER TABLEの売上
americas_2012を分割する
AT( '2012-Jun-01')

SUBPARTITION americas_p1_2012、
SUBPARTITION americas_p2_2012
);
コマンドを呼び出した後、 americas_2012サブパーティションが削除されました。その代わりに、サーバーは2つの新しいサブパーティション( americas_p1_2012およびamericas_p2_2012 )を作成しました。
acctg=# SELECT partition_name, subpartition_name, high_value FROM ALL_TAB_SUBPARTITIONS;
partition_name | subpartition_name | high_value
----------------+-------------------+--------------------------------------------------
EUROPE | EUROPE_2011 | FOR VALUES FROM (MINVALUE) TO ('01-JAN-12 00:00:00')
EUROPE | EUROPE_2012 | FOR VALUES FROM ('01-JAN-12 00:00:00') TO ('01-JAN-13 00:00:00')
ASIA | ASIA_2011 | FOR VALUES FROM (MINVALUE) TO ('01-JAN-12 00:00:00')
ASIA | ASIA_2012 | FOR VALUES FROM ('01-JAN-12 00:00:00') TO ('01-JAN-13 00:00:00')
AMERICAS | AMERICAS_2011 | FOR VALUES FROM (MINVALUE) TO ('01-JAN-12 00:00:00')
AMERICAS | AMERICAS_P1_2012 | FOR VALUES FROM ('01-JAN-12 00:00:00') TO ('01-JUN-12 00:00:00')
AMERICAS | AMERICAS_P2_2012 | FOR VALUES FROM ('01-JUN-12 00:00:00') TO ('01-JAN-13 00:00:00')
(7 rows)
sales表の問合せは 、サブパーティションの内容が再配布されていることを示しています。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date | amount
------------------------+---------+---------+----------+--------------------+--------
sales_americas_p1_2012 | 40 | 9519b | US | 12-APR-12 00:00:00 | 145000
sales_americas_p1_2012 | 30 | 9519b | CANADA | 01-FEB-12 00:00:00 | 75000
sales_americas_p1_2012 | 30 | 4519b | CANADA | 08-APR-12 00:00:00 | 120000
sales_americas_p1_2012 | 40 | 3788a | US | 12-MAY-12 00:00:00 | 4950
sales_americas_p2_2012 | 40 | 4577b | US | 11-NOV-12 00:00:00 | 25000
sales_americas_p2_2012 | 30 | 7588b | CANADA | 14-DEC-12 00:00:00 | 50000
sales_americas_p2_2012 | 40 | 4788a | US | 23-SEP-12 00:00:00 | 4950
sales_americas_p2_2012 | 40 | 4788b | US | 09-OCT-12 00:00:00 | 15000
sales_europe_2012 | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_europe_2012 | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_europe_2012 | 10 | 9519a | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_europe_2012 | 10 | 9519b | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_asia_2012 | 20 | 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_asia_2012 | 20 | 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_asia_2012 | 20 | 3788b | INDIA | 21-SEP-12 00:00:00 | 5090
sales_asia_2012 | 20 | 4519a | INDIA | 18-OCT-12 00:00:00 | 650000
sales_asia_2012 | 20 | 4519b | INDIA | 02-DEC-12 00:00:00 | 5090
(17 rows)
 
10.3.6 ALTER TABLE ... EXCHANGE PARTITION
ALTER TABLEは... EXCHANGE PARTITIONのコマンド は、パーティションを既存のテーブルを交換します。 パーティション化された表に大量のデータを追加する場合は、 ALTER テーブル ... エクスチェンジ PARTITION コマンドを使用してバルクロードを実装します。 ALTERを 使用することもできます テーブル ... エクスチェンジ PARTITION コマンドを使用して、古いデータまたは不要なデータを保存用に削除します。
コマンド構文には2つの形式があります。
最初の形式は、パーティションのテーブルを交換します。
ALTER TABLE target_table
EXCHANGE PARTITION
target_partition
WITH TABLE
source_table
[(含む|除外する)インデクス]
[(WITH | WITHOUT)VALIDATION];
2番目の形式では、サブパーティションの表がスワップされます。
ALTER TABLE target_table
交換
サブジェクトtarget_subpartition
WITH TABLE
source_table
[(含む|除外する)インデクス]
[(WITH | WITHOUT)VALIDATION];
説明
ときに ALTER TABLE ... EXCHANGE PARTITION コマンドが完了し、元々 target_partitionに配置されたデータは、SOURCE_TABLEに配置され、元々 SOURCE_TABLEに配置されたデータはtarget_partitionに配置されます。
ALTER TABLE ... EXCHANGE PARTITION コマンド、LIST、RANGEまたはHASHパーティション表にパーティションを交換することができます。 source_tableの構造はtarget_tableの構造と一致していなければなりません(両方のテーブルが一致する列とデータ型を持たなければなりません)。また、テーブルに含まれるデータはパーティション制約に従わなければなりません。
場合 INCLUDING INDEXES句交換PARTITIONで指定され、その後、target_partitionSOURCE_TABLEで一致するインデックスがスワップされます。 source_tableに一致のないtarget_partition内のインデックスは再構築され、その逆も同様です(つまり、 target_partitionに一致しないsource_tableのインデックスも再構築されます)。
EXCHUDGE PARTITIONを指定し EXCLUDING INDEXES句を指定すると、 target_partitionsource_tableの一致する索引がスワップされますが、 source_tableで一致しないtarget_partition索引は無効として、逆も同様です( source_tableの索引は一致しませんtarget_partitionの中にも無効としてマークされています)。
以前に使用された 照合索引用語は、照合順序、昇順または降順方向、最初のNULLの順序付けまたは最後のNULLの順序付けなど、 CREATE INDEXコマンドによって決定される同じ属性を持つ索引を指します。
INCLUDING INDEXESEXCLUDING INDEXの 両方が省略されている場合、デフォルトアクションは除外索引の動作です。
EXCHANGE SUBPARTITION句で使用されるtarget_subpartitionに は、前に説明したのと同じ動作が適用され ます
そのテーブルに対して ALTER TABLE ... EXCHANGE PARTITIONまたはALTER TABLE ... EXCHANGE SUBPARTITION を呼び出すには、テーブルを所有している必要があります。
パラメーター:
target_table
パーティションまたはサブパーティションが存在する表の名前(スキーマ修飾名も可)。
target_partition
置き換えられるパーティションの名前。
target_subpartition
置き換えられるサブパーティションの名前。
source_table
target_partitionまたはtarget_subpartition を置き換えるテーブルの名前
10.3.6.1 例 - パーティションのテーブルの交換
次の例では、パーティション(のテーブルを交換する実証 売上テーブルのアメリカ大陸 )。 salesテーブルは、次のコマンドで作成できます。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
PARTITION BY LIST(国)
PARTITION europe VALUES( 'フランス'、 'イタリア')、
PARTITION asia VALUES( 'インド'、 'パキスタン')、
PARTITIONアメリカの価値( 'US'、 'C​​ANADA')
);
salesテーブルにサンプルデータを追加するには、次のコマンドを使用します。
INSERT INTO sales VALUES
(40、'9519b '、' US '、'12-apr-2012'、 '145000')、
(10、 '4519b'、 'FRANCE'、'17-Jan-2012 '、' 45000 ')、
(20、 '3788a'、 'INDIA'、'01-Mar-2012 '、' 75000 ')、
(20、 '3788a'、 'PAKISTAN'、'04-Jun-2012 '、' 37500 ')、
(10、'9519b '、' ITALY '、'07-Jan-2012'、 '15000')、
(10、 '9519a'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ')、
(10、 '9519b'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ')、
(20、 '3788b'、 'INDIA'、'21 -ept-2012 '、' 5090 ')、
(20、 '4519a'、 'INDIA'、'18-Oct-2012 '、' 650000 ')、
(20、 '4519b'、 'INDIA'、 '2-Dec-2012'、 '5090');
照会 販売テーブルは1行のみアメリカパーティションに存在することを示しています。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date | amount
----------------+---------+---------+----------+--------------------+--------
sales_americas | 40 | 9519b | US | 12-APR-12 00:00:00 | 145000
sales_europe | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_europe | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_europe | 10 | 9519a | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_europe | 10 | 9519b | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_asia | 20 | 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_asia | 20 | 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_asia | 20 | 3788b | INDIA | 21-SEP-12 00:00:00 | 5090
sales_asia | 20 | 4519a | INDIA | 18-OCT-12 00:00:00 | 650000
sales_asia | 20 | 4519b | INDIA | 02-DEC-12 00:00:00 | 5090
(10 rows)
次のコマンドは、 salesテーブルの定義に一致するテーブル( n_america )を作成します。
CREATE TABLE n_america
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
);
次のコマンドは、 n_americaテーブルにデータを追加します。データは、 アメリカ大陸のパーティションの分割規則に準拠しています。
INSERT INTO n_america VALUES
(40、'9519b '、' US '、'12-apr-2012'、 '145000')、
(40、 '4577b'、 'US'、'11-Nov-2012 '、' 25000 ')、
(30、 '7588b'、 'C​​ANADA'、'14 -Dec-2012 '、' 50000 ')、
(30、 '9519b'、 'C​​ANADA'、'01 -Feb-2012 '、' 75000 ')、
(30、 '4519b'、 'C​​ANADA'、'08-Apr-2012 '、' 120000 ')、
(40、 '3788a'、 'US'、'12-May-2012 '、' 4950 ')、
(40、 '4788a'、 'US'、 '23 -ept-2012'、 '4950')、
(40、 '4788b'、 'US'、'09 -Oct-2012 '、' 15000 ');
次のコマンドは、テーブルをパーティションテーブルにスワップします。
ALTER TABLEの売上
交換区画アメリカ
WITH TABLE n_america;
照会 売上テーブルはn_americaテーブルの内容は、 アメリカのパーティションの内容のために交換されたことを示しています。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date | amount
----------------+---------+---------+----------+--------------------+--------
sales_americas | 40 | 9519b | US | 12-APR-12 00:00:00 | 145000
sales_americas | 40 | 4577b | US | 11-NOV-12 00:00:00 | 25000
sales_americas | 30 | 7588b | CANADA | 14-DEC-12 00:00:00 | 50000
sales_americas | 30 | 9519b | CANADA | 01-FEB-12 00:00:00 | 75000
sales_americas | 30 | 4519b | CANADA | 08-APR-12 00:00:00 | 120000
sales_americas | 40 | 3788a | US | 12-MAY-12 00:00:00 | 4950
sales_americas | 40 | 4788a | US | 23-SEP-12 00:00:00 | 4950
sales_americas | 40 | 4788b | US | 09-OCT-12 00:00:00 | 15000
sales_europe | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_europe | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_europe | 10 | 9519a | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_europe | 10 | 9519b | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_asia | 20 | 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_asia | 20 | 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_asia | 20 | 3788b | INDIA | 21-SEP-12 00:00:00 | 5090
sales_asia | 20 | 4519a | INDIA | 18-OCT-12 00:00:00 | 650000
sales_asia | 20 | 4519b | INDIA | 02-DEC-12 00:00:00 | 5090
(17 rows)
照会 n_americaテーブルは、以前アメリカパーティションに格納された行がn_americaテーブルに移動されたことを示しています。
acctg=# SELECT tableoid::regclass, * FROM n_america;
tableoid | dept_no | part_no | country | date | amount
-----------+---------+---------+---------+--------------------+--------
n_america | 40 | 9519b | US | 12-APR-12 00:00:00 | 145000
(1 row)
 
10.3.7 ALTER TABLE ... MOVE PARTITION
パーティションを別の表スペースに移動するには、 ALTER TABLE ... MOVE PARTITIONコマンドを使用します。このコマンドには2つの形式があります。
最初の形式では、パーティションを新しい表スペースに移動します。
ALTER TABLE テーブル _ 名前
MOVE PARTITION
パーティション _ 名前
TABLESPACE
表スペース _ 名前 ;
2番目の形式では、サブパーティションを新しい表領域に移動します。
ALTER TABLE テーブル _ 名前
MOVE SUBPARTITION
サブパーティション _ name
TABLESPACE
表スペース _ 名前 ;
説明
ALTER TABLE ... MOVE PARTITION コマンドは、パーティションを現在の表領域から別の表領域に移動します。 ALTER TABLE ... MOVE PARTITION コマンドは、 LIST RANGE または HASH パーティション表の パーティションを移動でき ます。
MOVE SUBPARTITION句で使用されるsubpartition_nameに は、前述の同じ動作が適用され ます
ALTER TABLE ... MOVE を呼び出すには、テーブルを所有している必要があり ます PARTITION または ALTER TABLE ... MOVE SUBPARTITION
パラメーター
テーブル名
パーティションまたはサブパーティションが存在する表の名前(スキーマ修飾名も可)。
partition_name
移動するパーティションの名前。
サブパーティション名
移動されるサブパーティションの名前。
tablespace_name
パーティションまたはサブパーティションを移動する表領域の名前。
 
10.3.7.1 例 - 異なる表領域へのパーティションの移動
次の例では、 sales表のパーティションをある表領域から別の表領域に移動します。まず、次のコマンドでsalesテーブルを作成します。
CREATE TABLEの売上

dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額

範囲による区切り(日付)

PARTITION
q1_2012 VALUES LESS THAN ( '2012-Apr-01')、
PARTITION
q2_2012 VALUES LESS THAN ( '2012-Jul-01')、
PARTITION
q3_2012 VALUES LESS THAN ( '2012-Oct-01')、
パーティション
q4_2012 VALUES LESS THAN ( '2013-Jan-01') TABLESPACE ts_1、
PARTITION
q1_2013 VALUES LESS THAN ( '2013-Mar-01') TABLESPACE ts_2
);
照会 ALL _ _ TAB パーティションビューは、パーティションが期待されるサーバおよび表領域に常駐していることを確認します:
acctg=# SELECT partition_name, tablespace_name FROM ALL_TAB_PARTITIONS;
partition_name | tablespace_name
----------------+-----------------
Q1_2012 |
Q2_2012 |
Q3_2012 |
Q4_2012 | TS_1
Q1_2013 | TS_2
(5 rows)
ターゲット表領域を準備した後、起動 ts_3という表領域にTS_2という名前の表領域からq1_2013パーティションを移動するには、ALTER TABLE ... MOVE PARTITION コマンドを:
ALTER TABLE セールス MOVE PARTITION q1_2013 TABLESPACE ts_3;
照会 ALL _ _ TAB パーティションビューは、移動が成功したことを示しています。
acctg=# SELECT partition_name, tablespace_name FROM ALL_TAB_PARTITIONS;
partition_name | tablespace_name
----------------+-----------------
Q1_2012 |
Q2_2012 |
Q3_2012 |
Q4_2012 | TS_1
Q1_2013 | TS_3
(5 rows)
 
10.3.8 ALTER TABLE ... RENAME PARTITION
ALTER TABLE ... RENAME PARTITIONコマンドを使用して 、表パーティションの名前を変更します。構文には2つの形式があります。
最初の形式はパーティションの名前を変更します:
ALTER TABLE テーブル _ 名前
RENAME PARTITION パーティション _ 名前
TO new _ name ;
2番目の形式はサブパーティションの名前を変更します。
ALTER TABLE テーブル _ 名前
RENAME SUBPARTITION サブパーティション _ name
TO new _ name ;
説明
ALTER TABLE ... PARTITIONコマンド名前変更するには、パーティションの名前を変更します。
前述の同じ動作が、 RENAME SUBPARTITION句で使用されるsubpartition_nameに 適用され ます
ALTER TABLE ... RENAME PARTITIONまたはALTER TABLE ... RENAME SUBPARTITION を呼び出すには、指定した表を所有していなければなりません
パラメーター
テーブル名
パーティションまたはサブパーティションが存在する表の名前(スキーマ修飾名も可)。
partition_name
名前を変更するパーティションの名前。
サブパーティション名
名前を変更するサブパーティションの名前。
新しい名前
パーティションまたはサブパーティションの新しい名前。
 
10.3.8.1 例 - パーティションの名前の変更
次のコマンドは、 sales という名前のリストパーティション表を作成します
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
PARTITION BY LIST(国)
PARTITION europe VALUES( 'フランス'、 'イタリア')、
PARTITION asia VALUES( 'インド'、 'パキスタン')、
PARTITIONアメリカの価値( 'US'、 'C​​ANADA')
);
照会パーティション名を表示するにはALL _ _ TAB パーティションビューを:
acctg=# SELECT partition_name, high_value FROM ALL_TAB_PARTITIONS;
partition_name | high_value
----------------+-------------------------------------
EUROPE | FOR VALUES IN ('FRANCE', 'ITALY')
ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN')
AMERICAS | FOR VALUES IN ('US', 'CANADA')
(3 rows)
次のコマンドは、 americasパーティションの名前n_americaに 変更ます
ALTER TABLEの 売上
n_america TO PARTITIONの アメリカの 名前 変更 します
照会 ALL _ _ TAB パーティションビューは、パーティションが正常に名前が変更されていることを示しています。
acctg=# SELECT partition_name, high_value FROM ALL_TAB_PARTITIONS;
partition_name | high_value
----------------+-------------------------------------
EUROPE | FOR VALUES IN ('FRANCE', 'ITALY')
ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN')
N_AMERICA | FOR VALUES IN ('US', 'CANADA')
(3 rows)
 
10.3.9 DROP TABLE
PostgreSQLの DROP TABLEコマンドを使用して 、パーティションテーブル定義、パーティションとサブパーティションを削除し、テーブルの内容を削除します。構文は次のとおりです。
DROP TABLE テーブル _ 名前
パラメーター
テーブル名
パーティション化された表の名前(スキーマ修飾名でも可)。
説明
DROP TABLEコマンドは、テーブル全体を削除し、そのテーブルに存在するデータ。表を削除すると、その表のパーティションまたはサブパーティションも削除されます。
DROP TABLEコマンドを使用するには、パーティション・ルートの所有者、表を所有するグループのメンバー、スキーマ所有者、またはデータベース・スーパーユーザーである必要があります。
表を削除するには、コントローラー・ノード(パーティション・ルートのホスト)に接続し、 DROP TABLEコマンドを呼び出します。たとえば、 salesテーブルを削除するには、次のコマンドを呼び出します。
DROP TABLEの売上。
サーバーは、テーブルが削除されたことを確認します。
acctg=# drop table sales;
DROP TABLE
acctg=#
詳細については DROP TABLE コマンド 、でPostgreSQLのコアのドキュメントを参照してください。
https://www.postgresql.org/docs/11/static/sql-droptable.html
 
 
 
 
10.3.10 ALTER TABLE ... DROP PARTITION
パーティション定義とそのパーティションに格納されているデータを削除するには、 ALTER TABLE ... DROP PARTITIONコマンドを使用します。構文は次のとおりです。
ALTER TABLE table _ name DROP PARTITION パーティション _ 名前;
パラメーター
テーブル名
パーティション化された表の名前(スキーマ修飾名でも可)。
partition_name
削除するパーティションの名前。
説明
ALTER TABLE ... DROP PARTITIONのコマンドは、パーティションとそのパーティションに保存されているすべてのデータが削除されます。 ALTER TABLE ... DROP PARTITIONコマンドは、 LISTまたはRANGEパーティション表のパーティションを削除できます。このコマンドはHASHパーティションテーブルでは機能しません。パーティションを削除すると、そのパーティションのサブパーティションも削除されます。
DROP PARTITIONを使用するには、パーティショニング・ルートの所有者であるか、テーブルを所有するグループのメンバーであるか、データベースのスーパーユーザー権限または管理者権限が必要です。
10.3.10.1 例 - パーティションの削除
次の例では、 salesテーブルのパーティションを削除します。 salesテーブルを作成するには、次のコマンドを使用します。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
PARTITION BY LIST(国)
PARTITION europe VALUES( 'フランス'、 'イタリア')、
PARTITION asia VALUES( 'インド'、 'パキスタン')、
PARTITIONアメリカの価値( 'US'、 'C​​ANADA')
);
照会 ALL _ _ TAB パーティションビューはパーティション名が表示されます。
acctg=# SELECT partition_name, high_value FROM ALL_TAB_PARTITIONS;
partition_name | high_value
----------------+-------------------------------------
EUROPE | FOR VALUES IN ('FRANCE', 'ITALY')
ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN')
AMERICAS | FOR VALUES IN ('US', 'CANADA')
(3 rows)
salesテーブルからamericasパーティションを削除するには 、次のコマンドを呼び出します。
ALTER TABLEの売上DROP PARTITIONアメリカ。
照会 ALL _ _ TAB パーティションビューは、パーティションが正常に削除されたことを示しています。
acctg=# SELECT partition_name, high_value FROM ALL_TAB_PARTITIONS;
partition_name | high_value
----------------+-------------------------------------
EUROPE | FOR VALUES IN ('FRANCE', 'ITALY')
ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN')
(2 rows)
 
10.3.11 ALTER TABLE ... DROP SUBPARTITION
サブパーティション定義とそのサブパーティションに格納されているデータを削除するには、 ALTER TABLE ... DROP SUBPARTITIONコマンドを使用し ます 。構文は次のとおりです。
ALTER TABLE table _ name DROP SUBPARTITION サブパーティション _ name;
パラメーター
テーブル名
パーティション化された表の名前(スキーマ修飾名でも可)。
サブパーティション名
削除するサブパーティションの名前。
説明
ALTER TABLE ... DROP SUBPARTITIONのコマンドは、サブパーティション、およびそのサブパーティションに格納されたデータを削除します。 DROP SUBPARTITION句を使用するには、パーティショニング・ルートの所有者であるか、テーブルを所有するグループのメンバーであるか、スーパーユーザー権限または管理者権限が必要です。
10.3.11.1 例 - サブパーティションの 削除
次の例では、 sales表のサブパーティションを削除します。 salesテーブルを作成するには、次のコマンドを使用します。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額

範囲による区切り(日付)
SUBPARTITION BY LIST
(国)

PARTITION
first_half_2012 VALUES LESS THAN('01 -JUL-2012 ')
SUBPARTITIONヨーロッパの 価値 ( 'イタリア'、 'フランス')、
アメリカSUBPARTITION VALUES( 'カナダ'、 'アメリカ')、
SUBPARTITIONアジア バリュー ( 'パキスタン'、 'インド')
)、
PARTITION second_half_2012 VALUES LESS THAN('01-JAN-2013 ')
);
照会 ALL _ _ TAB SUBPARTITIONSビューは、サブパーティション名が表示されます。
acctg=# SELECT subpartition_name, high_value FROM ALL_TAB_SUBPARTITIONS;
subpartition_name | high_value
-------------------+-------------------------------------
ASIA | FOR VALUES IN ('PAKISTAN', 'INDIA')
AMERICAS | FOR VALUES IN ('CANADA', 'US')
EUROPE | FOR VALUES IN ('ITALY', 'FRANCE')
SYS0101 | DEFAULT
(4 rows)
sales表からamericasサブパーティションを削除するには 、次のコマンドを実行します。
ALTER TABLEの売上DROP SUBPARTITIONアメリカ。
照会 ALL _ _ TAB SUBPARTITIONSビューは、サブパーティションが正常に削除されていることを示しています。
acctg=# SELECT subpartition_name, high_value FROM ALL_TAB_SUBPARTITIONS;
subpartition_name | high_value
-------------------+-------------------------------------
ASIA | FOR VALUES IN ('PAKISTAN', 'INDIA')
EUROPE | FOR VALUES IN ('ITALY', 'FRANCE')
SYS0101 | DEFAULT
(3 rows)
 
10.3.12 TRUNCATE TABLE
TRUNCATE TABLEコマンドを使用して 、テーブル定義を保持したままテーブルの内容を削除します。表を切り捨てると、その表のパーティションまたはサブパーティションも切り捨てられます。構文は次のとおりです。
TRUNCATE TABLE テーブル _ 名前
説明
TRUNCATE TABLEコマンドは、テーブル全体を削除し、そのテーブルに存在するデータ。表を削除すると、その表のパーティションまたはサブパーティションも削除されます。
TRUNCATE TABLEコマンドを使用するには、パーティション・ルートの所有者、表を所有するグループのメンバー、スキーマ所有者、またはデータベース・スーパーユーザーである必要があります。
パラメーター
テーブル名
パーティション化された表の名前(スキーマ修飾名でも可)。
10.3.12.1 例 - テーブルを空にする
次の例では、 salesからデータを削除します。 salesテーブルを作成するには、次のコマンドを使用します。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
PARTITION BY LIST(国)
PARTITION europe VALUES( 'フランス'、 'イタリア')、
PARTITION asia VALUES( 'インド'、 'パキスタン')、
PARTITIONアメリカの価値( 'US'、 'C​​ANADA')
);
移入のコマンドを使用して、sales表を:
INSERT INTO sales VALUES
(10、 '4519b'、 'FRANCE'、'17-Jan-2012 '、' 45000 ')、
(20、 '3788a'、 'INDIA'、'01-Mar-2012 '、' 75000 ')、
(40、'9519b '、' US '、'12-apr-2012'、 '145000')、
(20、 '3788a'、 'PAKISTAN'、'04-Jun-2012 '、' 37500 ')、
(40、 '4577b'、 'US'、'11-Nov-2012 '、' 25000 ')、
(30、 '7588b'、 'C​​ANADA'、'14 -Dec-2012 '、' 50000 ')、
(30、 '9519b'、 'C​​ANADA'、'01 -Feb-2012 '、' 75000 ')、
(30、 '4519b'、 'C​​ANADA'、'08-Apr-2012 '、' 120000 ')、
(40、 '3788a'、 'US'、'12-May-2012 '、' 4950 ')、
(10、'9519b '、' ITALY '、'07-Jan-2012'、 '15000')、
(10、 '9519a'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ')、
(10、 '9519b'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ')、
(20、 '3788b'、 'INDIA'、'21 -ept-2012 '、' 5090 ')、
(40、 '4788a'、 'US'、 '23 -ept-2012'、 '4950')、
(40、 '4788b'、 'US'、'09 -Oct-2012 '、' 15000 ')、
(20、 '4519a'、 'INDIA'、'18-Oct-2012 '、' 650000 ')、
(20、 '4519b'、 'INDIA'、 '2-Dec-2012'、 '5090');
sales表を照会すると、パーティションにデータが移入されたことが示されます。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date | amount
----------------+---------+---------+----------+--------------------+--------
sales_americas | 40 | 9519b | US | 12-APR-12 00:00:00 | 145000
sales_americas | 40 | 4577b | US | 11-NOV-12 00:00:00 | 25000
sales_americas | 30 | 7588b | CANADA | 14-DEC-12 00:00:00 | 50000
sales_americas | 30 | 9519b | CANADA | 01-FEB-12 00:00:00 | 75000
sales_americas | 30 | 4519b | CANADA | 08-APR-12 00:00:00 | 120000
sales_americas | 40 | 3788a | US | 12-MAY-12 00:00:00 | 4950
sales_americas | 40 | 4788a | US | 23-SEP-12 00:00:00 | 4950
sales_americas | 40 | 4788b | US | 09-OCT-12 00:00:00 | 15000
sales_europe | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_europe | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_europe | 10 | 9519a | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_europe | 10 | 9519b | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_asia | 20 | 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_asia | 20 | 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_asia | 20 | 3788b | INDIA | 21-SEP-12 00:00:00 | 5090
sales_asia | 20 | 4519a | INDIA | 18-OCT-12 00:00:00 | 650000
sales_asia | 20 | 4519b | INDIA | 02-DEC-12 00:00:00 | 5090
(17 rows)
salesテーブルの内容を削除するには 、次のコマンドを呼び出します。
TRUNCATE TABLEの売上。
さて、 salesテーブルを照会すると、データは削除されていますが、構造は損なわれていないことがわかります:
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date | amount
----------+---------+---------+---------+------+--------
(0 rows)
詳細については TRUNCATE TABLE コマンドにてPostgreSQLのドキュメントを参照してください。
https://www.postgresql.org/docs/11/static/sql-truncate.html
 
10.3.13 ALTER TABLE ... TRUNCATE PARTITION
ALTER TABLE ... TRUNCATE PARTITIONコマンドを使用して 、指定されたパーティションからデータを削除し、パーティション構造はそのまま残します。構文は次のとおりです。
ALTER TABLE table_name TRUNCATE PARTITION partition_name
[{DROP | REUSE} STORAGE]
説明
ALTER TABLE ... TRUNCATE PARTITIONコマンドを使用して 、指定されたパーティションからデータを削除し、パーティション構造はそのまま残します。パーティションを切り捨てると、そのパーティションのサブパーティションも切り捨てられます。
ALTER TABLEを ... TRUNCATE PARTITION 発射するテーブルのために存在する可能性がありますON DELETEトリガ発生しませんが、それが引き金TRUNCATE 火災ます。パーティションに対してON TRUNCATEトリガーが定義されている場合は、すべてのBEFORE TRUNCATEトリガーが切断される前に起動され、最後の切り捨て後にすべてのAFTER TRUNCATEトリガーが起動されます。
ALTER TABLE ... TRUNCATE PARTITIONを呼び出すには、表に対してTRUNCATE特権が必要です。
パラメーター
テーブル名
パーティション化された表の名前(スキーマ修飾名でも可)。
partition_name
削除するパーティションの名前。
DROP STORAGEREUSE STORAGEは互換性のためにのみ含まれています。句は解析され無視されます。
10.3.13.1 例 - パーティションを空にする
次の例では、 sales表のパーティションからデータを削除します。 salesテーブルを作成するには、次のコマンドを使用します。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
PARTITION BY LIST(国)
PARTITION europe VALUES( 'フランス'、 'イタリア')、
PARTITION asia VALUES( 'インド'、 'パキスタン')、
PARTITIONアメリカの価値( 'US'、 'C​​ANADA')
);
移入のコマンドを使用して、sales表を:
INSERT INTO sales VALUES
(10、 '4519b'、 'FRANCE'、'17-Jan-2012 '、' 45000 ')、
(20、 '3788a'、 'INDIA'、'01-Mar-2012 '、' 75000 ')、
(40、'9519b '、' US '、'12-apr-2012'、 '145000')、
(20、 '3788a'、 'PAKISTAN'、'04-Jun-2012 '、' 37500 ')、
(40、 '4577b'、 'US'、'11-Nov-2012 '、' 25000 ')、
(30、 '7588b'、 'C​​ANADA'、'14 -Dec-2012 '、' 50000 ')、
(30、 '9519b'、 'C​​ANADA'、'01 -Feb-2012 '、' 75000 ')、
(30、 '4519b'、 'C​​ANADA'、'08-Apr-2012 '、' 120000 ')、
(40、 '3788a'、 'US'、'12-May-2012 '、' 4950 ')、
(10、'9519b '、' ITALY '、'07-Jan-2012'、 '15000')、
(10、 '9519a'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ')、
(10、 '9519b'、 'FRANCE'、'18 -Aug-2012 '、' 650000 ')、
(20、 '3788b'、 'INDIA'、'21 -ept-2012 '、' 5090 ')、
(40、 '4788a'、 'US'、 '23 -ept-2012'、 '4950')、
(40、 '4788b'、 'US'、'09 -Oct-2012 '、' 15000 ')、
(20、 '4519a'、 'INDIA'、'18-Oct-2012 '、' 650000 ')、
(20、 '4519b'、 'INDIA'、 '2-Dec-2012'、 '5090');
sales表を照会すると、パーティションにデータが移入されたことが示されます。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date | amount
----------------+---------+---------+----------+--------------------+--------
sales_americas | 40 | 9519b | US | 12-APR-12 00:00:00 | 145000
sales_americas | 40 | 4577b | US | 11-NOV-12 00:00:00 | 25000
sales_americas | 30 | 7588b | CANADA | 14-DEC-12 00:00:00 | 50000
sales_americas | 30 | 9519b | CANADA | 01-FEB-12 00:00:00 | 75000
sales_americas | 30 | 4519b | CANADA | 08-APR-12 00:00:00 | 120000
sales_americas | 40 | 3788a | US | 12-MAY-12 00:00:00 | 4950
sales_americas | 40 | 4788a | US | 23-SEP-12 00:00:00 | 4950
sales_americas | 40 | 4788b | US | 09-OCT-12 00:00:00 | 15000
sales_europe | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_europe | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_europe | 10 | 9519a | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_europe | 10 | 9519b | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_asia | 20 | 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_asia | 20 | 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_asia | 20 | 3788b | INDIA | 21-SEP-12 00:00:00 | 5090
sales_asia | 20 | 4519a | INDIA | 18-OCT-12 00:00:00 | 650000
sales_asia | 20 | 4519b | INDIA | 02-DEC-12 00:00:00 | 5090
(17 rows)
americasパーティションの内容を削除するには 、次のコマンドを呼び出します。
ALTER TABLEの売上はTRUNCATE PARTITIONアメリカです。
次に、 salesテーブルを照会すると、 americasパーティションの内容が削除されたことが示されます。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date | amount
--------------+---------+---------+----------+--------------------+--------
sales_europe | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_europe | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_europe | 10 | 9519a | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_europe | 10 | 9519b | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_asia | 20 | 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_asia | 20 | 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_asia | 20 | 3788b | INDIA | 21-SEP-12 00:00:00 | 5090
sales_asia | 20 | 4519a | INDIA | 18-OCT-12 00:00:00 | 650000
sales_asia | 20 | 4519b | INDIA | 02-DEC-12 00:00:00 | 5090
(9 rows)
行が削除されているが、構造の 米州パーティションは無傷のままです。
acctg=# SELECT partition_name, high_value FROM ALL_TAB_PARTITIONS;
partition_name | high_value
----------------+-------------------------------------
EUROPE | FOR VALUES IN ('FRANCE', 'ITALY')
ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN')
AMERICAS | FOR VALUES IN ('US', 'CANADA')
(3 rows)
 
10.3.14 ALTER TABLE ... TRUNCATE SUBPARTITION
ALTER TABLE ... TRUNCATE SUBPARTITIONコマンドを使用して 、指定されたサブパーティションからすべてのデータを削除し、サブパーティション構造をそのまま残します。構文は次のとおりです。
ALTER TABLE table_name
TRUNCATE SUBPARTITION
subpartition_name
[{DROP | REUSE} STORAGE]
説明
ALTER TABLE ... TRUNCATE SUBPARTITION コマンドは、完全なサブパーティションの構造を残して、指定されたサブパーティションからすべてのデータを削除します。
ALTER TABLEを ... TRUNCATE SUBPARTITIONを発射するテーブルのために存在する可能性がありますON DELETEトリガ発生しませんが、それが引き金TRUNCATE 火災ます。サブパーティションに対してON TRUNCATEトリガーが定義されている場合は、すべてのBEFORE TRUNCATEトリガーがトリガーされる前にトリガーされ、すべてのAFTER TRUNCATEトリガーは最後のトランケーションが発生した後にトリガーされます。
ALTER TABLE ... TRUNCATE SUBPARTITIONを呼び出すには、表に対するTRUNCATE権限が必要です。
パラメーター
テーブル名
パーティション化された表の名前(スキーマ修飾名でも可)。
サブパーティション名
切り捨てられるサブパーティションの名前。
DROP ストレージ REUSE STORAGE句は、互換性のためだけに含まれています。句は解析され無視されます。
10.3.14.1 例 - サブパーティションを空にする
次の例では、 sales表のサブパーティションからデータを削除します。 salesテーブルを作成するには、次のコマンドを使用します。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
範囲による区画(日付)リストによる区画 (国)

PARTITION
"2011" VALUES LESS THAN('01 -JAN-2012' )
SUBPARTITION europe_2011 VALUES ( 'イタリア'、 'フランス')、
SUBPARTITION asia_2011 VALUES ( 'パキスタン'、 'インド')、
SUBPARTITION americas_2011 VALUES ( 'US'、 'CANADA')
)、
PARTITION "2012" VALUES LESS THAN('01 -JAN-2013' )
SUBPARTITION europe_2012 VALUES ( 'イタリア'、 'フランス')、
SUBPARTITION asia_2012 VALUES ( 'パキスタン'、 'インド')、
SUBPARTITION americas_2012 VALUES ( 'US'、 'CANADA')
)、
PARTITION
"2013" VALUES LESS THAN('01 -JAN-2015' )
SUBPARTITION europe_2013 VALUES ( 'イタリア'、 'フランス')、
SUBPARTITION asia_2013 VALUES ( 'パキスタン'、 'インド')、
SUBPARTITION americas_2013 VALUES ( 'US'、 'CANADA')
);
移入のコマンドを使用して、sales表を:
INSERT INTO sales VALUES
(10、 '4519b'、 'FRANCE'、'17-Jan-2011 '、' 45000 ')、
(20、 '3788a'、 'INDIA'、'01-Mar-2012 '、' 75000 ')、
(40、'9519b '、' US '、'12-apr-2012'、 '145000')、
(20、 '3788a'、 'PAKISTAN'、'04-Jun-2012 '、' 37500 ')、
(40、 '4577b'、 'US'、'11-Nov-2012 '、' 25000 ')、
(30、 '7588b'、 'C​​ANADA'、'14 -Dec-2011 '、' 50000 ')、
(30、 '4519b'、 'C​​ANADA'、'08-Apr-2012 '、' 120000 ')、
(40、 '3788a'、 'US'、'12-May-2011 '、' 4950 ')、
(20、 '3788a'、 'US'、'04-Apr-2012 '、' 37500 ')、
(40、 '4577b'、 'INDIA'、'11-Jun-2011 '、' 25000 ')、
(10、'9519b '、' ITALY '、'07-Jan-2012'、 '15000')、
(20、 '4519b'、 'INDIA'、 '2-Dec-2012'、 '5090');
sales表を照会すると、行がサブパーティションに分散されていることが示されます。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country| date | amount
-------------------+---------+---------+--------+--------------------+------
sales_americas_2011 | 30| 7588b | CANADA | 14-DEC-11 00:00:00 | 50000
sales_americas_2011 | 40| 3788a | US | 12-MAY-11 00:00:00 | 4950
sales_europe_2011 | 10| 4519b | FRANCE | 17-JAN-11 00:00:00 | 45000
sales_asia_2011 | 40| 4577b | INDIA | 11-JUN-11 00:00:00 | 25000
sales_americas_2012 | 40| 9519b | US | 12-APR-12 00:00:00 | 145000
sales_americas_2012| 40| 4577b | US | 11-NOV-12 00:00:00 | 25000
sales_americas_2012| 30| 4519b | CANADA | 08-APR-12 00:00:00 | 120000
sales_americas_2012| 20| 3788a | US | 04-APR-12 00:00:00 | 37500
sales_europe_2012 | 10| 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_asia_2012 | 20| 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_asia_2012 | 20| 3788a |PAKISTAN| 04-JUN-12 00:00:00 | 37500
sales_asia_2012 | 20| 4519b | INDIA | 02-DEC-12 00:00:00 | 5090
(12 rows)
2012_americasパーティションの内容を削除するには 、次のコマンドを呼び出します。
ALTER TABLEの 販売 TRUNCATE SUBPARTITION "americas_2012";
次に、 salesテーブルを照会すると、 americas_2012パーティションの内容が削除されたことが示されます。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no| part_no | country | date |amount
-------------------+--------+---------+----------+--------------------+------
sales_americas_2011| 30| 7588b | CANADA | 14-DEC-11 00:00:00 | 50000
sales_americas_2011| 40| 3788a | US | 12-MAY-11 00:00:00 | 4950
sales_europe_2011 | 10| 4519b | FRANCE | 17-JAN-11 00:00:00 | 45000
sales_asia_2011 | 40| 4577b | INDIA | 11-JUN-11 00:00:00 | 25000
sales_europe_2012 | 10| 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_asia_2012 | 20| 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_asia_2012 | 20| 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_asia_2012 | 20| 4519b | INDIA | 02-DEC-12 00:00:00 | 5090
(8 rows)
行が削除されている間は、 2012_americasパーティションの構造は変更されません。
acctg=# SELECT subpartition_name, high_value FROM ALL_TAB_SUBPARTITIONS;
subpartition_name | high_value
-------------------+-------------------------------------
AMERICAS_2011 | FOR VALUES IN ('US', 'CANADA')
ASIA_2011 | FOR VALUES IN ('PAKISTAN', 'INDIA')
EUROPE_2011 | FOR VALUES IN ('ITALY', 'FRANCE')
AMERICAS_2012 | FOR VALUES IN ('US', 'CANADA')
ASIA_2012 | FOR VALUES IN ('PAKISTAN', 'INDIA')
EUROPE_2012 | FOR VALUES IN ('ITALY', 'FRANCE')
AMERICAS_2013 | FOR VALUES IN ('US', 'CANADA')
ASIA_2013 | FOR VALUES IN ('PAKISTAN', 'INDIA')
EUROPE_2013 | FOR VALUES IN ('ITALY', 'FRANCE')
(9 rows)
10.4 LISTまたはRANGEパーティション表のストレイ値の処理
DEFAULTまたはMAXVALUEパーティションまたはサブパーティションには、テーブルに定義された他のパーティショニングのルールを満たしていない任意の行をキャプチャします。
DEFAULTパーティションの定義
DEFAULTパーティションLISTパーティション(またはサブパーティション)表内の他のパーティションに適合していない任意の行をキャプチャします。 DEFAULTルールを含まない場合、パーティション制約内の値の1つに一致しない行はエラーになります。各LISTパーティションまたはサブパーティションには、独自のDEFAULTルールが設定されている場合があります。
DEFAULTルールの構文は次のとおりです。
PARTITION [ パーティション _ 名前 ] VALUES(DEFAULT)
どこ PARTITION_NAMEは、他のパーティションに指定したルールに一致しないすべての行を格納するパーティションまたはサブパーティションの名前を指定します。
最後の例では、サーバーが 国の列の値に基づいてデータを格納するパーティションを決定するリスト・パーティション表を作成しましたcountry列の値にルールにリストされていない値が含まれている行を追加しようとすると、Advanced Serverはエラーを報告します。
acctg=# INSERT INTO sales VALUES
acctg-# (40, '3000x', 'IRELAND', '01-Mar-2012', '45000');
ERROR: no partition of relation "sales_2012" found for row
DETAIL: Partition key of the failing row contains (country) = (IRELAND).
次の例では、同じテーブルを作成しますが、 DEFAULTパーティションを追加します 。サーバーは、 ヨーロッパアジア 、または他のパーティション内のアメリカのパーティションの分割ルールで指定された値と一致しないすべての行を格納します。
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額
PARTITION BY LIST(国)
PARTITION europe VALUES( 'フランス'、 'イタリア')、
PARTITION asia VALUES( 'インド'、 'パキスタン')、
PARTITIONアメリカのVALUES( 'US'、 'C​​ANADA')、
PARTITIONその他の値VALUES(DEFAULT)
);
DEFAULTパーティションをテストするには、パーティション制約で指定されている国のいずれかと一致しない国の列に値を含む行を追加します。
INSERT INTO sales VALUES
(40、 '3000x'、 'IRELAND'、'01-Mar-2012 '、' 45000 ');
sales表の内容を 照会すると、以前に拒否された行がsales_others区画に保管されていることが確認されます。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date | amount
----------------+---------+---------+----------+--------------------+--------
sales_americas | 40 | 9519b | US | 12-APR-12 00:00:00 | 145000
sales_americas | 40 | 4577b | US | 11-NOV-12 00:00:00 | 25000
sales_americas | 30 | 7588b | CANADA | 14-DEC-12 00:00:00 | 50000
sales_americas | 30 | 9519b | CANADA | 01-FEB-12 00:00:00 | 75000
sales_americas | 30 | 4519b | CANADA | 08-APR-12 00:00:00 | 120000
sales_americas | 40 | 3788a | US | 12-MAY-12 00:00:00 | 4950
sales_americas | 40 | 4788a | US | 23-SEP-12 00:00:00 | 4950
sales_americas | 40 | 4788b | US | 09-OCT-12 00:00:00 | 15000
sales_europe | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_europe | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_europe | 10 | 9519a | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_europe | 10 | 9519b | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_asia | 20 | 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_asia | 20 | 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_asia | 20 | 3788b | INDIA | 21-SEP-12 00:00:00 | 5090
sales_asia | 20 | 4519a | INDIA | 18-OCT-12 00:00:00 | 650000
sales_asia | 20 | 4519b | INDIA | 02-DEC-12 00:00:00 | 5090
sales_others | 40 | 3000x | IRELAND | 01-MAR-12 00:00:00 | 45000
(18 rows)
Advanced Serverには、 DEFAULTパーティションまたはサブパーティションの内容を再割り当てするための次のメソッドがあります
ALTER TABLE ... ADD PARTITIONコマンドを使用して、テーブル内の既存の行と追加するパーティションの値との間に競合する値がない限り、 DEFAULTルールを持つテーブルにパーティションを追加できます。代わりに、 ALTER TABLE ... SPLIT PARTITIONコマンドを使用して、既存のパーティションを分割することもできます。例は、この箇条書きリストの後に示されています。
ALTER TABLE ... ADD SUBPARTITIONコマンドを使用して、表の既存の行と追加するサブパーティションの値との間に競合する値がない限り、 DEFAULT規則を持つ表にサブパーティションを追加できます 。あるいは、 ALTER TABLE ... SPLIT SUBPARTITIONコマンドを使用して、既存のサブパーティションを分割することができます
DEFAULTパーティションを持つテーブルへのパーティションの追加
このセクションの冒頭に示されている CREATE TABLE salesコマンドで作成されたテーブルを使用して 、次の例では、 ALTER TABLE ... ADD PARTITIONコマンドを使用して、テーブル内の既存の行と追加するパーティションの値:
edb=# ALTER TABLE sales ADD PARTITION africa values ('SOUTH AFRICA', 'KENYA');
ALTER TABLE
ただし、次の行がテーブルに挿入されたときに競合する値がある場合のエラーを次に示します。
edb=# INSERT INTO sales (dept_no, country) VALUES (1,'FRANCE'),(2,'INDIA'),(3,'US'),(4,'SOUTH AFRICA'),(5,'NEPAL');
INSERT 0 5
Row (4、 'SOFTH AFRICA')は、 ALTER TABLE ... ADD PARTITIONステートメントのVALUESリストと競合し、エラーが発生します。
edb=# ALTER TABLE sales ADD PARTITION africa values ('SOUTH AFRICA', 'KENYA');
ERROR: updated partition constraint for default partition "sales_others" would be violated by some row
DEFAULTパーティションの分割
次の例では、 DEFAULTパーティションを分割し、2つの新しいパーティション間でパーティションの内容を再配布します。このセクションの冒頭に示すCREATE TABLE salesコマンドを使用してテーブルを作成しました。
次の例では、 DEFAULTパーティションに行を含めてテーブルに行を挿入します
INSERT INTO sales VALUES
(10、 '4519b'、 'FRANCE'、'17-Jan-2012 '、' 45000 ')、
(10、'9519b '、' ITALY '、'07-Jan-2012'、 '15000')、
(20、 '3788a'、 'INDIA'、'01-Mar-2012 '、' 75000 ')、
(20、 '3788a'、 'PAKISTAN'、'04-Jun-2012 '、' 37500 ')、
(30、'9519b '、' US '、'12-Apr-2012'、 '145000')、
(30、 '7588b'、 'C​​ANADA'、'14 -Dec-2012 '、' 50000 ')、
(40、 '4519b'、 '南アフリカ'、'08-apr-2012 '、' 120000 ')、
(40、 '4519b'、 'KENYA'、'08-Apr-2012 '、' 120000 ')、
(50、 '3788a'、 'C​​HINA'、'12-May-2012 '、' 4950 ');
パーティションには、 DEFAULT その他 のパーティションが含まれます
edb=# SELECT partition_name, high_value FROM all_tab_partitions;
partition_name | high_value
----------------+-------------------------------------
EUROPE | FOR VALUES IN ('FRANCE', 'ITALY')
ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN')
AMERICAS | FOR VALUES IN ('US', 'CANADA')
OTHERS | DEFAULT
(4 rows)
以下は、パーティション間で分散された行を示しています。
edb=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date | amount
--------------+--------+---------+--------------+--------------------+--------
sales_americas| 30 | 9519b | US | 12-APR-12 00:00:00 | 145000
sales_americas| 30 | 7588b | CANADA | 14-DEC-12 00:00:00 | 50000
sales_europe | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_europe | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_asia | 20 | 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_asia | 20 | 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_others | 40 | 4519b | SOUTH AFRICA | 08-APR-12 00:00:00 | 120000
sales_others | 40 | 4519b | KENYA | 08-APR-12 00:00:00 | 120000
sales_others | 50 | 3788a | CHINA | 12-MAY-12 00:00:00 | 4950
(9 rows)
次のコマンドは、 DEFAULT その他のパーティションをafricaなどの2つのパーティションに分割します
ALTER TABLE sales SPLIT PARTITIONその他の値VALUES
( '南アフリカ'、 'ケニア')
INTO(PARTITION africa、PARTITIONその他);
パーティションには アフリカのパーティションとDEFAULT その他のパーティションが含まれています:
edb=# SELECT partition_name, high_value FROM all_tab_partitions;
partition_name | high_value
----------------+-----------------------------------------
EUROPE | FOR VALUES IN ('FRANCE', 'ITALY')
ASIA | FOR VALUES IN ('INDIA', 'PAKISTAN')
AMERICAS | FOR VALUES IN ('US', 'CANADA')
AFRICA | FOR VALUES IN ('SOUTH AFRICA', 'KENYA')
OTHERS | DEFAULT
(5 rows)
次の例は、新しいパーティション間で行が再配布されたことを示しています。
edb=# SELECT tableoid::regclass, * FROM sales;
tableoid |dept_no | part_no | country | date | amount
---------------+--------+---------+-------------+--------------------+--------
sales_americas | 30 | 9519b | US | 12-APR-12 00:00:00 | 145000
sales_americas | 30 | 7588b | CANADA | 14-DEC-12 00:00:00 | 50000
sales_europe | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_europe | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_asia | 20 | 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_asia | 20 | 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_africa | 40 | 4519b | SOUTH AFRICA| 08-APR-12 00:00:00 | 120000
sales_africa | 40 | 4519b | KENYA | 08-APR-12 00:00:00 | 120000
sales_others_1 | 50 | 3788a | CHINA | 12-MAY-12 00:00:00 | 4950
(9 rows)
MAXVALUEパーティションの定義
MAXVALUEパーティション (またはサブパーティション)は、レンジ・パーティション(またはサブパーティション)の表に、他のパーティションに適合していない任意の行をキャプチャします。 MAXVALUEルールを含まない場合、パーティション化ルールで指定された最大限度を超える行はエラーになります。各パーティションまたはサブパーティションには、それぞれ独自のMAXVALUEパーティションがあります。
MAXVALUEルールの構文は次のとおりです。
PARTITION [ パーティション _ ] VALUES LESS THAN(MAXVALUE)
どこ PARTITION_NAMEは、他のパーティションに指定したルールに一致しないすべての行を格納するパーティションの名前を指定します。
最後の例は、 日付列の値に基づいてデータが分割されたレンジ・パーティション表を作成したものです 。パーティション制約に記載されている日付を超える日付の行を追加しようとすると、Advanced Serverはエラーを報告します。
acctg=# INSERT INTO sales VALUES
acctg-# (40, '3000x', 'IRELAND', '01-Mar-2013', '45000');
ERROR: no partition of relation "sales" found for row
DETAIL: Partition key of the failing row contains (date) = (01-MAR-13 00:00:00).
次の CREATE TABLEコマンドは同じテーブルを作成しますが、パーティションはMAXVALUEです。エラーをスローするのではなく、サーバーは以前のパーティション制約と一致しない行を他のパーティションに格納します。
CREATE TABLEの売上

dept_no番号、
part_no varchar2、
国varchar2(20)、
日付の日付、
金額

範囲による区切り(日付)

PARTITION q1_2012 VALUES LESS THAN( '2012-Apr-01')、
PARTITION q2_2012 VALUES LESS THAN( '2012-Jul-01')、
PARTITION q3_2012 VALUES LESS THAN( '2012-Oct-01')、
パーティションq4_2012 VALUES LESS THAN( '2013-Jan-01')、
PARTITIONその他VALUES LESS THAN(MAXVALUE)
);
MAXVALUEパーティションをテストするには、パーティション化ルールにリストされている最後の日付値を超える日付列に値を含む行を追加します。サーバーは、 他のパーティションに行を格納します。
INSERT INTO sales VALUES
(40、 '3000x'、 'IRELAND'、'01 -Mar-2013 '、' 45000 ');
sales表の内容を 照会すると、以前に拒否された行がsales_others区画に保管されていることが確認されます。
acctg=# SELECT tableoid::regclass, * FROM sales;
tableoid | dept_no | part_no | country | date | amount
---------------+---------+---------+----------+--------------------+--------
sales_q1_2012 | 10 | 4519b | FRANCE | 17-JAN-12 00:00:00 | 45000
sales_q1_2012 | 20 | 3788a | INDIA | 01-MAR-12 00:00:00 | 75000
sales_q1_2012 | 30 | 9519b | CANADA | 01-FEB-12 00:00:00 | 75000
sales_q2_2012 | 40 | 9519b | US | 12-APR-12 00:00:00 | 145000
sales_q2_2012 | 20 | 3788a | PAKISTAN | 04-JUN-12 00:00:00 | 37500
sales_q2_2012 | 30 | 4519b | CANADA | 08-APR-12 00:00:00 | 120000
sales_q2_2012 | 40 | 3788a | US | 12-MAY-12 00:00:00 | 4950
sales_q3_2012 | 10 | 9519b | ITALY | 07-JUL-12 00:00:00 | 15000
sales_q3_2012 | 10 | 9519a | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_q3_2012 | 10 | 9519b | FRANCE | 18-AUG-12 00:00:00 | 650000
sales_q3_2012 | 20 | 3788b | INDIA | 21-SEP-12 00:00:00 | 5090
sales_q3_2012 | 40 | 4788a | US | 23-SEP-12 00:00:00 | 4950
sales_q4_2012 | 40 | 4577b | US | 11-NOV-12 00:00:00 | 25000
sales_q4_2012 | 30 | 7588b | CANADA | 14-DEC-12 00:00:00 | 50000
sales_q4_2012 | 40 | 4788b | US | 09-OCT-12 00:00:00 | 15000
sales_q4_2012 | 20 | 4519a | INDIA | 18-OCT-12 00:00:00 | 650000
sales_q4_2012 | 20 | 4519b | INDIA | 02-DEC-12 00:00:00 | 5090
sales_others | 40 | 3000x | IRELAND | 01-MAR-13 00:00:00 | 45000
(18 rows)
Advanced Serverには、 MAXVALUEパーティションまたはサブパーティションの内容を再割り当てする方法はありません
あなたは使用することはできません MAXVALUEルールを表にパーティションを追加するためにPARTITION文追加 ... ALTER TABLE していますが、既存のパーティションを分割するには、ALTER TABLE ... SPLIT PARTITION を使用することができます。
ALTER TABLE ... ADD SUBPARTITION文を使用して、 MAXVALUEルールを持つ表にサブパーティションを追加することはできませんが、既存のサブパーティションをALTER TABLE ... SPLIT SUBPARTITION文で分割できます
10.5 RANGEパーティション表の複数のパーティション化キーの指定
RANGEパーティション表に複数のキー列を指定することによって、パフォーマンスを向上させることができます。少数の列に対して比較演算子(より大きいまたはより小さい値に基づく)を使用して行を選択することが多い場合は、これらの列をRANGEパーティション化ルールで使用することを検討してください。
レンジ・パーティション表に複数のキーを指定する
レンジ・パーティション表定義には、パーティション化キー内の複数の列が含まれる場合があります。レンジ・パーティション表の複数のパーティション化キーを指定するには、 PARTITION BY RANGE句の後にコンマ区切りリストで列名を含めます
CREATE TABLEの売上
dept_no番号、
part_no varchar2、
国varchar2(20)、
販売年数、
sale_month番号、
販売日番号、
金額
範囲による区切り(sale_year、sale_month)
分割q1_2012
VALUES LESS THAN(2012、4)、
パーティションq2_2012
VALUES LESS THAN(2012、7)、
パーティションq3_2012
VALUES LESS THAN(2012、10)、
パーティションq4_2012
VALUES LESS THAN(2013、1)
);
複数のパーティション化キーを使用してテーブルを作成する場合は、パーティションプルーニングを最大限に活用するためにテーブルをクエリするときに、複数のキー値を指定する必要があります。
acctg=# EXPLAIN SELECT * FROM sales WHERE sale_year = 2012 AND sale_month = 8;
QUERY PLAN
----------------------------------------------------------------------------
Append (cost=0.00..14.35 rows=1 width=250)
-> Seq Scan on sales_q3_2012 (cost=0.00..14.35 rows=1 width=250)
Filter: ((sale_year = '2012'::numeric) AND (sale_month = '8'::numeric))
(3 rows)
sale_month列の値が 8で、 sales_year列の値が2012であるすべてq3_2012パーティションに格納されるため、Advanced Serverはそのパーティションのみを検索します。
10.6 パーティション表に関する情報の取得
Advanced Serverには、パーティション表の構造に関する情報を表示するために使用できる5つのシステム・カタログ・ビューがあります。
パーティションビューのクエリ
次のビューを問い合せて、パーティション表およびサブパーティション表に関する情報を検索できます。
各ビューの構造は、第 10.6.1 表のパーティション化のビュー」で 説明しています。 EDB-PSQLクライアントを使用している場合は、次のように入力してビューの構造を検出することもできます。
\ d ビュー _ 名前
ここで、 view_nameは、表パーティション・ビューの名前を指定します。
ビューの問合せは、パーティション表またはサブパーティション表の構造に関する情報を提供できます。たとえば、次のコードスニペットでは、サブパーティション化されたテーブルの名前が表示されます。
acctg=# SELECT subpartition_name, partition_name FROM ALL_TAB_SUBPARTITIONS;
subpartition_name | partition_name
-------------------+----------------
EUROPE_2011 | EUROPE
EUROPE_2012 | EUROPE
ASIA_2011 | ASIA
ASIA_2012 | ASIA
AMERICAS_2011 | AMERICAS
AMERICAS_2012 | AMERICAS
(6 rows)
 
 
 
10.6.1 テーブル・パーティション・ビュー - リファレンス
パーティション化された表の詳細情報を確認するには、Oracleデータベースと互換性のある次のカタログ・ビューを問い合せます。
10.6.1.1 ALL_PART_TABLES
次の表に、 ALL_PART_TABLESビューで使用可能な情報を示します
10.6.1.2 ALL_TAB_PARTITIONS
次の表に、 ALL_TAB_PARTITIONSビューで使用可能な情報を示します
10.6.1.3 ALL_TAB_SUBPARTITIONS
次の表に、 ALL_TAB_SUBPARTITIONSビューで使用可能な情報を示します
10.6.1.4 ALL_PART_KEY_COLUMNS
次の表は、 ALL_PART_KEY_COLUMNSビューで使用可能な情報を示しています。
10.6.1.5 ALL_SUBPART_KEY_COLUMNS
次の表は、 ALL_SUBPART_KEY_COLUMNSビューで使用可能な情報を示しています。
11 ECPGPlus
EnterpriseDBは、ECPG(PostgreSQLプリコンパイラ)を拡張してECPGPlusを作成しました。 ECPGPlusを使用すると、Cアプリケーションに埋め込みSQLコマンドを含めることができます。 ECPGPlusを使用して埋め込みSQLコマンドを含むアプリケーションをコンパイルすると、SQLコードは構文チェックされ、C言語に変換されます。
Advanced Serverデータベースに接続すると、 ECPGPlus はCプログラムでPro * C互換構文をサポートします 。 ECPGPlusは次をサポートします:
Oracleデータベースと互換性 のある CALL 文。
ECPGPlusのPro * C互換性の一部として、 BEGIN を含める必要はありません 宣言 SECTION END 宣言 SECTION 指令。
ECPGPlusの使用の詳細については、次のEnterpriseDB Webサイトから入手可能なEDB Postgres Advanced Server ECPG Connector Guideを参照してください。
https://www.enterprisedb.com/resources/product-documentation
12 dblink_ora
dblink_oraは、 Advanced Server内からOracleシステムに格納されたデータ SELECTINSERTUPDATEまたはDELETE できるOCIベースのデータベース・リンクを提供します。
Oracleデータベースへの接続
Oracleとの接続を可能にするには、現在入手可能なOCIドライバをWebサイトからダウンロードしてください。
http://www.oracle.com/technetwork/database/database-technologies/instant-client/overview/index.html
Linuxの場合、ダウンロードしたOracleインスタント・クライアントに libclntshが 含まれていない 場合 その ライブラリは、あなたが libclntsh という名前のシンボリックリンクを作成する必要があります そのため には、ダウンロードしたバージョンを指します。インスタントクライアントディレクトリに移動し、次のコマンドを実行します。
ln -s libclntsh.so。 バージョン libclntsh.so
どこ バージョンは libclntsh のバージョン番号です そう ライブラリ。例えば:
ln -s libclntsh.so.12.1 libclntsh.so
Oracleサーバーへのリンクを作成する前に、Advanced ServerにOCIドライバの検索場所を指定する必要があります。
Linux(またはWindowsの場合はPATH LD_LIBRARY_PATH環境変数をOracleクライアントのインストールディレクトリのlibディレクトリに設定します。
Windowsの場合のみ、 oracle_home構成パラメータの値を postgresql.confファイルに設定できます。 oracle_home構成パラメーターで指定された値は、Windows PATH環境変数よりも優先されます。
Advanced Serverを起動するたびに、Linux LD_LIBRARY_PATH環境変数( PATH環境変数またはWindowsのoracle_home構成パラメータ)を正しく設定する必要があります。
Linuxサービススクリプトを使用してAdvanced Serverを起動する場合は、 LD_LIBRARY_PATHがサービススクリプト内に設定されていることを確認しください。スクリプトがpg_ctlユーティリティを呼び出してAdvanced Serverを起動したときに有効になります。
Windowsの場合のみ: postgresqlに oracle _ home構成パラメータを設定します。 confファイルを編集し、次の行を追加してファイルを編集します。
oracle_home = ' lib_directory '
oci を含むWindowsディレクトリの名前に 置き換えてくださいlib_directoryのためのdll
設定後 のOracle _ ホーム設定パラメータを、変更を有効にするには、サーバーを再起動する必要があります。 Windowsサービスコンソールからサーバーを再起動します。
12.1 dblink_ora関数とプロシージャ
dblink_oraは、以下の機能と手順をサポートしています。
12.1.1 dblink_ora_connect()
dblink_ora_connect() 関数は、ユーザが指定した接続情報を使用してOracleデータベースへの接続を確立します。 この関数には2つの形式があります。最初の形式の署名は次のとおりです。
dblink_ora_connect( conn_name server_name service_name user_name password port asDBA
場所:
conn_name リンクの名前を指定します。
サーバーの名前 ホストの名前を指定します。
service_nameは、サービスの名前を指定します。
user_nameは、サーバーへの接続に使用される名前を指定します。
passwordは、ユーザー名に関連付けられたパスワードを指定します。
ポート番号を指定します。
OracleサーバーでSYSDBA権限を要求する場合は、 asDBATrueです。 このパラメータはオプションです。省略された場合、デフォルト値は FALSE です。
dblink_ora_connect() の最初の形式 は、 TEXT 値を 返し ます。
dblink_ora_connect() 関数の 2番目の形式のシグネチャは次の とおり です。
dblink_ora_connect( foreign_server _ name asDBA
場所:
foreign_server_name 外部サーバーの名前を指定します。
OracleサーバーでSYSDBA権限を要求する場合は、 asDBATrueです。 このパラメータはオプションです。省略された場合、デフォルト値は FALSE です。
dblink_ora_connect() 関数 の2つ目の形式では 、サーバーへの接続を確立するときに、あらかじめ定義された外部サーバーの接続プロパティを使用できます。
dblink_ora_connect() 関数 の2番目の形式を呼び出す前に CREATE SERVER コマンドを使用して、システム・テーブルへのリンクの接続プロパティを格納します。 dblink _ ora _ connect() 関数 を呼び出すとき は、 CREATEで 指定されたサーバー名を使用します SERVER コマンドを使用して、リンク名を指定します。
dblink_ora_connect() の2番目の形式 は、 TEXT 値を 返し ます。
12.1.2 dblink_ora_status()
dblink_ora_status() 関数は、データベース接続のステータスを返します。 署名は次のとおりです。
dblink_ora_status( conn_name
場所:
conn_name リンクの名前を指定します。
指定された接続がアクティブな場合、この関数は TEXT 値を OKに 戻します
12.1.3 dblink_ora_disconnect()
dblink_ora_disconnect() 関数は、データベース接続を閉じます。 署名は次のとおりです。
dblink_ora_disconnect( conn_name
場所:
conn_name リンクの名前を指定します。
関数は TEXT 値を 返し ます。
12.1.4 dblink_ora_record()
dblink_ora_record() 関数は、データベースから情報を検索します。 署名は次のとおりです。
dblink_ora_record( conn_name query_text
場所:
conn_name リンクの名前を指定します。
query_text Oracleサーバー上で呼び出されるSQL SELECT文のテキストを指定します。
この関数は SETOF レコードを 返します
12.1.5 dblink_ora_call()
dblink_ora_call() 関数は、Oracle データベース上の SELECT 文を 実行 し、結果セットを返します。 署名は次のとおりです。
dblink_ora_call( conn_name コマンド 反復
場所:
conn_name リンクの名前を指定します。
コマンド Oracleサーバー上で呼び出されるSQL文のテキストを指定します。
iterationsは、文が実行される回数を指定します。
この関数は SETOF レコードを 返します
12.1.6 dblink_ora_exec()
dblink_ora_exec() プロシージャは、リモート・データベースでのDMLまたはDDL文を実行します。 署名は次のとおりです。
dblink_ora_exec(conn_name、command)
場所:
conn_name リンクの名前を指定します。
コマンド Oracleサーバー上で呼び出されるINSERTUPDATE 、またはDELETE SQLステートメントのテキストを指定します。
この関数は VOIDを 返します
12.1.7 dblink_ora_copy()
dblink_ora_copy()関数は、Oracle表をEnterpriseDB表にコピーします。 dblink_ora_copy()関数は、コピーされた行の数を表すBIGINT値を返します。署名は次のとおりです。
dblink_ora_copy( conn_name command schema_name table_name truncate count
場所:
conn_name リンクの名前を指定します。
コマンド Oracleサーバー上で呼び出されるSQL SELECT文のテキストを指定します。
schema_nameは、ターゲット・スキーマの名前を指定します。
table_nameは、ターゲット表の名前を指定します。
truncate は、 コピーする前に サーバが テーブル TRUNCATE する かどうかを指定します TRUE 指定する と、サーバーが TRUNCATE する 必要が あります。 切り捨て はオプションです。省略された場合、値は FALSEになります
countは、 nレコードごとにステータス情報を報告するようにサーバーに指示します( nは指定された番号です)。 この機能の実行中、アドバンストサーバは カウントの繰り返しごと に重大度 INFOの 通知を 発行 します。たとえば、FeedbackCountが 10の 場合 dblink_ora_copy() 10 レコード ごとに通知を 発行し ます。 カウント はオプションです。省略された場合、値は 0 です。
12.2 dblink_ora関数の呼び出し
次のコマンドは、 dblink_ora_connect() 関数 を使用して接続を確立し ます。
SELECT dblink_ora_connect( 'acctg'、 'localhost'、 'xe'、 'hr'、 'pwd'、1521);
この例では 、ユーザー名が hr 、パスワードが pwdの ポート 1521 localhost上 )で 実行さ れている xe という名前のサービスに接続し ます 他のdblink_ora関数を呼び出すときは 、接続名 acctg使用してこの接続参照できます。
次のコマンドは、使用して Advanced Serverの名前付き as_acctg のインスタンス上の public スキーマ にあるテーブルに ora_acctg という名前(Oracleサーバー上の)テーブルから EMPID DEPTNO 列を コピーする edb_conn という名前の接続を介して dblink_ora_copy() 関数を TRUNCATE オプション が適用され、そして 3 のフィードバックカウントが 指定されています。
edb =#SELECT dblink_ora_copy( 'edb_conn'、 'empid、deptno FROM ora_acctg'、 'public'、 'as_acctg'、true、3)を選択します。
情報:行:0
情報:行:3
情報:行:6
情報:行:9
情報:行:12

dblink_ora_copy
-----------------
12

(1行)
次の SELECT 文は、 dblink_ora_record() 関数と acctg 接続を使用してOracleサーバーから情報を取得します。
SELECT * FROM dblink_ora_record( 'acctg'、 'employees first_name from employees')AS t1(id VARCHAR);
このコマンド は、 employees 表の first_name 列の すべてのエントリを含むリストを取得し ます。
13 システムカタログテーブル
システムカタログテーブルには、Advanced Serverで使用可能なデータベースオブジェクトの定義が含まれています。システムテーブルのレイアウトは変更される可能性があります。システムテーブルに格納されている情報に依存するアプリケーションを作成する場合は、既存のカタログビューを使用するか、カタログビューを作成してアプリケーションをシステムテーブルの変更から隔離することが賢明です。
システムカタログ表の詳細については、次のURLにあるOracle Developer's Reference GuideのDatabase Compatibilityを参照してください。
https://www.enterprisedb.com/resources/product-documentation
14 謝辞
PostgreSQLの8.3、8.4、9.0、9.1、9.2、9.3、9.4、9.5、9.6、10、及び11は、PostgreSQL文書に共通するこのガイドの部分のためのベースラインを提供し、ここに認められています。
この EnterpriseDBソフトウェアおよびドキュメンテーションの一部は 、以下の著作物を使用することができ、その使用はここで認められます。
PostgreSQLのドキュメント、データベース管理システム
PostgreSQLはPostgreSQLグローバル開発グループ著作権©1996-2018に基づき、以下のカリフォルニア大学ライセンスの条件に基づいて配布されています。
Postgres95は カリフォルニア大学リージェントの著作権©1994-5。
上記の著作権表示と本項および次の2つの段落がすべてのコピーに記載されていれば、無償で、かつ書面による合意なしに、本ソフトウェアおよびその文書を使用、複製、改変、および配布することが許可されます。
いかなる場合においても、カリフォルニア大学は、カリフォルニア大学が実施していたとしても、ソフトウェアおよびその文書の使用に起因する損害を含む、直接的、間接的、偶発的、派生的、派生的損害に対する賠償責任を負わないものとしますそのような損害の可能性を知らされた。
カリフォルニア州立大学は、商品性および特定目的への適合性の黙示的な保証を含む(ただしこれらに限定されない)いかなる保証も特に断ります。本契約に基づいて提供される本ソフトウェアは、現状のままであり、カリフォルニア州立大学は、保守、サポート、更新、拡張または改変を提供する義務を負いません。