14 PL/SQLの言語要素

PL/SQLの言語要素の構文と意味の概要、および例と関連トピックへのリンクを示します。

構文図の読み方は、『Oracle Database SQL言語リファレンス』を参照してください。

ここでのトピック

関連項目:

14.1 イテレータ

イテレータでは、イテランドと繰返しコントロールを指定します。

イテレータは、次の文で使用できます。

構文

iterand_decl ::=

iteration_ctl_seq ::=

pred_clause_seq ::=

stepped_control ::=

single_expression_control ::=

dynamic_sql ::=

セマンティクス

iterator

イテレータでは、イテランドと繰返しコントロールを指定します。

ループの外側の文は、iteratorを参照できません。ループの内側の文はiteratorを参照できますが、その値を変更することはできません。FOR LOOP文の実行後、iteratorは不定になります。

iterand_decl

イテランドのタイプは、暗黙的または明示的に宣言できます。明示的にイテランドを初期化することはできません。

イテランドのタイプは、ループ・ヘッダーのイテランドの後にタイプの宣言がない場合、暗黙的に宣言されます。暗黙的なタイプは、最初の繰返しコントロールによって決定されます。

表14-1 イテランドの暗黙的なタイプのデフォルト

繰返しコントロール 暗黙的なイテランドのタイプ
ステップ・コントロール PLS_INTEGER
単一式 PLS_INTEGER
カーソル制御 CURSOR%ROWTYPE
VALUES OFコントロール コレクション要素タイプ
INDICES OFコントロール コレクション索引タイプ
PAIRS OFコントロール 最初のイテランドはコレクションの索引タイプを示し、2番目のイテランドはコレクションの要素タイプを示します

pls_identifier

FOR LOOP文に対してローカルな、暗黙に宣言された変数のイテランド名。

[ MUTABLE | IMMUTABLE ]

イテランドの可変性プロパティにより、ループ本体での代入を可能にするかどうかが決まります。イテレータで指定したすべての繰返しコントロールがカーソル・コントロールの場合、イテランドはデフォルトで可変です。それ以外の場合、イテランドは不変です。イテランドのデフォルトの可変性プロパティは、イテランド変数の後ろにキーワードMUTABLEまたはIMMUTABLEを指定することで、イテランド宣言内で変更できます。可変性プロパティのキーワードは予約されていません。タイプの名前として使用することも可能です。そのような使用方法は、あいまいになります。そのため、イテランドの可変性プロパティは、タイプの名前をmutableやimmutableにする場合、イテランドの宣言内で明示的に指定する必要があります。INDICES OF繰返しコントロールのイテランドおよびPAIRS OF繰返しコントロールの索引イテランドは、可変にすることはできません。

constrained_type

イテランドは、ループ・ヘッダーでイテランドのタイプを指定するときに明示的に宣言します。イテランドに値を代入する際には、タイプに定義された制約が考慮されます。繰返しコントロールによって生成される値には、イテランドのタイプとの代入互換性が必要です。通常の変換ルールが適用されます。すべての制約違反に対して例外が発生します。

iteration_ctl_seq

複数の繰返しコントロールは、それらをカンマで区切って連鎖できます。

iteration_ctl_seqの制限:

Pairs Ofイテランドには2つのイテランドが必要になるため、Pairs Of繰返しコントロールは別の種類の繰返しコントロールと混在できません。

qual_iteration_ctl

修飾反復コントロールはREVERSEオプション、およびオプションで停止述語句やスキップ述語句を指定します。

[ REVERSE ]

オプションのキーワードREVERSEを指定すると、シーケンス内の値の順序が逆転されます。

このオプションは、コレクション・ベクトル値式で使用できます。その場合、REVERSEを指定すると、FIRSTからLASTではなく、LASTからFIRSTに向けて値が生成されます。

REVERSEの制限:
  • このオプションは、繰返しコントロールでパイプライン・ファンクションが指定されているときには使用できません。
  • 単一式の繰返しコントロールでは単一値が生成されるため、このオプションは使用できません。そのため、このキーワードは、このコントロールに対して実用的な意味を持ちません。

  • 繰返しコントロールでSQL文を指定しているときには、このオプションは使用できません。これは、問合せによって返されたレコードのシーケンスを生成します。SQL文にORDER BY句を指定することで、適切な順序に行をソートできます。

  • このオプションは、コレクションがカーソル、カーソル変数、動的SQLの場合や、パイプライン・テーブル・ファンクションを呼び出す式の場合には使用できません。

iteration_control

繰返しコントロールは、値のシーケンスをイテランドに提供します。

pred_clause_seq

繰返しコントロールは、オプションの停止述語句と、それに続くオプションのスキップ述語句で変更されることがあります。述語句に含まれる式は、BOOLEAN型にする必要があります。

[ WHILE boolean_expression ]

停止述語句により、繰返しコントロールを完全に消化できます。boolean_expressionは、ループの各反復の最初に評価されます。TRUEに評価されない場合は、繰返しコントロールが完全に消化されています。

[ WHEN boolean_expression ]

スキップ述語句により、いくつかの値についてループ本体をスキップできます。boolean_expressionが評価されます。TRUEに評価されない場合、繰返しコントロールは次の値にスキップします。

stepped_control

lower_bound .. upper_bound [ BY step ]

REVERSEが指定されていない場合、iterandの値はlower_boundから始まり、upper_boundに到達するまで、ループの反復ごとにstepずつ増加します。

REVERSEを指定すると、iterandの値はupper_boundから始まり、lower_boundに達するまで、ループの反復ごとにstepずつ減少します。upper_boundlower_boundよりも小さい場合、statementsは実行されません。

stepのデフォルト値は1です(このオプションのBY句を指定していない場合)。

lower_boundupper_boundは、数値(数値リテラル、数値変数または数値式のいずれか)に評価されます。境界の数値が指定されていない場合、PL/SQLは事前定義の例外VALUE_ERRORを呼び出します。PL/SQLでは、lower_boundupper_boundFOR LOOP文に入ったときに一度評価され、一時的なPLS_INTEGER値として格納されます(必要に応じて、最も近い整数に四捨五入されます)。

lower_boundupper_boundが等しい場合、statementsは一度のみ実行されます。

ステップ値は0 (ゼロ)より大きい値である必要があります。

single_expression_control

単一式の繰返しコントロールは、単一値を生成します。REPEATを指定すると、停止句によって繰返しコントロールが完全に消化されるまで、式が繰り返し評価されて値のシーケンスが生成されます。

single_expression_controlの制限:

REVERSEは単一式の繰返しコントロールには使用できません。

values_of_control

コレクションの要素タイプには、イテランドとの代入互換性が必要です。

indices_of_control

コレクションの索引タイプには、イテランドとの代入互換性が必要です。

INDICES OF繰返しコントロールに使用するイテランドは可変にできません。

pairs_of_control

PAIRS OF繰返しコントロールには、2つのイテランドが必要です。PAIRS OF繰返しコントロールと、それとは別の種類のコントロールを混在させることはできません。最初のイテランドは索引イテランドです。2番目は値イテランドです。それぞれのイテランドの後ろには明示的なタイプが続くことがあります。

コレクションの要素タイプには、値イテランドとの代入互換性が必要です。コレクションの索引タイプには、索引イテランドとの代入互換性が必要です。

PAIRS OF繰返しコントロールに使用する索引イテランドは可変にできません。

cursor_iteration_control

カーソルの繰返しコントロールは、明示カーソルまたは暗黙カーソルによって返されるレコードのシーケンスを生成します。カーソル定義が制御式になります。

cursor_iteration_controlの制限:

カーソルの繰返しコントロールでは、REVERSEは使用できません。

cursor_object

cursor_objectは、明示的なPL/SQLカーソル・オブジェクトです。

sql_statement

sql_statementは、繰返しコントロールで直接指定したSQL文に応じて作成される暗黙的なPL/SQLカーソル・オブジェクトです。

cursor_variable

REF CURSORオブジェクトの以前に宣言した変数の名前。

dynamic_sql

EXECUTE IMMEDIATE dynamic_sql_stmt [ USING [ IN ] (bind_argument [,] )+]

動的問合せは、カーソルまたはコレクションの繰返しコントロールで暗黙的カーソル定義のかわりに使用できます。このような構成では、デフォルトのタイプを指定できません。最初の繰返しコントロールとして使用する場合は、イテランドまたはPairs Ofコントロールの値イテランドに明示的なタイプを指定する必要があります。

オプションのUSING句は、動的SQLで許容される唯一の句です。INと1つ以上のバインド変数(カンマで区切る)を含めることのみ可能です。

dynamic_sql_stmt

SQL文を表す文字列リテラル、文字列変数または文字列式です。その型は、CHAR型、VARCHAR2型またはCLOB型である必要があります。

注意:

動的SQLを使用する場合は、セキュリティ・リスクのSQLインジェクションに注意してください。SQLインジェクションの詳細は、「SQLインジェクション」を参照してください。

  • 例5-25繰返しコントロールとしての動的SQLの使用
  • 例5-17 「ステップ範囲の繰返しコントロール」
  • 例5-18 「FOR LOOP文のSTEP句」
  • 例5-24カーソルの繰返しコントロール
  • 例5-21VALUES OF繰返しコントロール
  • 例5-22INDICES OF繰返しコントロール
  • 例5-23PAIRS OF繰返しコントロール

14.2 修飾式

修飾式を使用すると、複雑な値も簡潔な形式で、値が必要になった場所で宣言と定義ができます。

修飾式は、次の場所で使用できます。

構文

positional_choice_list ::=

sequence_iterator_choice ::=

named_choice_list ::=

indexed_choice_list ::=

セマンティクス

qualified_expression

RECORD型の修飾式は、RECORD型の式が許可されている任意のコンテキストで使用できます。

連想配列型の修飾式は、連想配列型の式が許可されている任意のコンテキストで使用できます。

typemark ( aggregate )

集計(修飾項目)の型を明示的に指定します。

typemark

type_name

修飾式は明示的な型の指定を使用することで修飾項目の型を指定します。この明示的な指定はtypemarkと呼ばれるものです。

identifier [ . ]

修飾項目の型を示します。

aggregate

修飾式は式要素を組み合せて、RECORD型または連想配列型の値を作成します。

positional_choice_list

expr [ , ]

RECORD型の修飾式では位置関連付けを使用できます。

位置関連付けが同じ構造体内の名前関連付けに従っていない場合もあります(その逆も同様です)。

sequence_iterator_choice

FOR iterator SEQUENCE => expr

シーケンス・イテレータ選択アソシエーションは、定位置引数です。これは、別の定位置引数と自由に混在させることができます。すべての位置指定引数は、定位置ではない引数よりも前に指定する必要があります。

explicit_choice_list

named_choice_list | indexed_choice_list | basic_iterator_choice | index_iterator_choice

名前関連付けでは修飾する構造型からのフィールドの名前を使用する必要があります。索引キーの値は修飾するベクトル型の索引の型と互換している必要があります。

named_choice_list

名前指定選択は構造型にのみ適用されます。

identifier => expr [ , ]

RECORD型の修飾式に名前関連付けを使用できます。

indexed_choice_list

索引選択は、ベクトル型にのみ適用されます。

expr => expr [ , ]

索引指定選択(キーと値のペア)を連想配列型の修飾式で使用できます。キーおよび値に式を使用することができます。

連想配列型の構造体で、NULLを索引キー値として使用することはできません。

basic_iterator_choice

FOR iterator => expr

基本イテレータ選択アソシエーションは、イテランドを索引として使用します。

制限:

PAIRS OF繰返しコントロールは、基本イテレータ選択アソシエーションに使用できません。

index_iterator_choice

FOR iterator INDEX expr => expr

索引イテレータ選択アソシエーションは、値式と連動する索引式を実現します。

  • 例6-11 「修飾式を使用したRECORD型変数への値の代入」
  • 例6-12 「修飾式を使用した連想配列型変数への値の代入」
  • 例6-8 「修飾式での基本イテレータ選択アソシエーション」
  • 例6-9 「修飾式での索引イテレータ選択アソシエーション」
  • 例6-10 「修飾式でのシーケンス・イテレータ選択アソシエーション」
  • 例5-26 「修飾式での繰返しコントロールとしての動的SQLの使用」

関連トピック

14.3 SQL_MACRO句

SQL_MACRO句では、ファンクションにSQLマクロとしてのマークを付けて、スカラー式または表式のどちらかとして使用できるようにします。

TABLEマクロは、SQL_MACROの注釈が付いている、TABLEタイプとして定義されたファンクションです。

SCALARマクロは、SQL_MACROの注釈が付いている、SCALARタイプとして定義されたファンクションです。

ビューで参照されるSQLマクロは、常にビューの所有者の権限で実行されます。

AUTHIDプロパティは指定できません。SQLマクロは呼び出されると、実行者の正しいファンクションのように動作します。SQLマクロ所有者は、起動元のファンクションに継承権限を付与する必要があります。

マクロ注釈付きファンクションをPL/SQLで使用する場合は、通常のファンクション戻り文字またはCLOB型のようにマクロ拡張なしで動作します。

SQL_MACROの注釈は、次のSQL文で使用できます。

SQLマクロの使用上の制限:
  • TABLEマクロは、問合せ表式のFROM句でのみ使用できます。
  • SCALARマクロは、問合せ表式のFROM句では使用できません。選択リストまたはWHERE句で使用できます。
  • Scalarマクロには、表引数を指定できません。
  • SQLマクロは、仮想列式、ファンクション索引、エディショニング・ビューまたはマテリアライズド・ビューでは使用できません。
  • タイプ・メソッドには、SQL_MACROで注釈を付けることはできません。

構文

sql_macro_clause ::=

セマンティクス

sql_macro_clause

sql_macro_clauseは、ファンクション内で1回のみ使用できます。SQLマクロ・ファンクションを作成するには、ファンクション定義にsql_macro_clauseを含めます。SQLマクロ・ファンクションを定義前に宣言する場合は、ファンクションの宣言でsql_macro_clauseを指定する必要があります。

SCALARまたはTABLEを指定していない場合、TABLEがデフォルトになります。

SCALAR

マクロ・ファンクションをスカラー式で使用可能にする場合は、SCALARを指定します。

TABLE (デフォルト)

マクロ・ファンクションを表式で使用可能にする場合は、TABLEを指定します。

sql_macro_clauseの制限

SQL_MACROの注釈は、RESULT_CACHEPARALLEL_ENABLEおよびPIPELINEDには使用できません。DETERMINISTICプロパティは指定できませんが、SQLマクロは常に暗黙で決定的になります。

SQLマクロ・ファンクションには、VARCHAR2CHARまたはCLOBの戻り型が必要です。

例14-1 Emp_doc: Scalarマクロを使用した列のJSONまたはXML文書への変換

emp_doc SQLマクロは、従業員フィールドを文書文字列(JSONまたはXML)に変換します。
The macro is implemented as a tree of nested macros with the following call graph structure.
emp_doc()
   ==> emp_json()
          ==> name_string()
          ==> email_string()
                ==> name_string()
          ==> date_string()
   ==> emp_xml 
          ==> name_string()
          ==> email_string()
                ==> name_string()
          ==> date_string()
date_stringファンクションは、日付を4桁の年、月(01-12)および日(1-31)としてフォーマットした文字列に変換します。
CREATE FUNCTION date_string(dat DATE) 
                    RETURN VARCHAR2 SQL_MACRO(SCALAR) IS
BEGIN
   RETURN q'{
             TO_CHAR(dat, 'YYYY-MM-DD')
          }';
END;
/
name_stringファンクションは、first_nameおよびlast_nameの各単語の最初の文字を大文字、他の文字をすべて小文字に設定します。フォーマット済の名前とフォーマット済の姓をスペースで連結して、結果の文字列の先頭と末尾のスペースを削除します。
CREATE FUNCTION name_string(first_name VARCHAR2,
                                 last_name VARCHAR2)
                     RETURN VARCHAR2 SQL_MACRO(SCALAR) IS
BEGIN
   RETURN q'{
          TRIM(INITCAP(first_name) || ' ' || INITCAP(last_name))
          }';
END;
/
email_stringは、name_stringファンクションを使用してfirst_nameとlast_nameでEメール・アドレスを設定し、すべてのスペースをピリオドに置き換え、デフォルト・ドメイン名のexample.comを追加します。
CREATE FUNCTION email_string(first_name VARCHAR2,
                                  last_name VARCHAR2,
                                  host_name VARCHAR2 DEFAULT 'example.com')
                    RETURN VARCHAR2 SQL_MACRO(SCALAR) IS
BEGIN
   RETURN q'{
          REPLACE(LOWER(name_string(first_name, last_name)),' ','.') || '@' || host_name
          }';
END;
/
emp_json SQLマクロは、JSONドキュメント文字列を返します。
CREATE FUNCTION emp_json(first_name VARCHAR2 DEFAULT NULL,
                              last_name VARCHAR2 DEFAULT NULL,
                              hire_date DATE DEFAULT NULL,
                              phone_num VARCHAR2 DEFAULT NULL)
                    RETURN VARCHAR2 SQL_MACRO(SCALAR) IS
BEGIN
   RETURN q'{
          JSON_OBJECT(
             'name'      : name_string(first_name, last_name),
             'email'     : email_string(first_name, last_name),
             'phone'     : phone_num,
             'hire_date' : date_string(hire_date)
             ABSENT ON NULL)
          }';
END;
/
emp_xml SQLマクロは、XML文書の文字列を返します。
CREATE FUNCTION emp_xml(first_name VARCHAR2 DEFAULT NULL,
                             last_name VARCHAR2 DEFAULT NULL,
                             hire_date DATE DEFAULT NULL,
                             phone_num VARCHAR2 DEFAULT NULL)
                    RETURN VARCHAR2 SQL_MACRO(SCALAR) IS
BEGIN
   RETURN q'{
       XMLELEMENT("xml",
                  CASE WHEN first_name || last_name IS NOT NULL THEN
                     XMLELEMENT("name", name_string(first_name, last_name))
                  END,
                  CASE WHEN first_name || last_name IS NOT NULL THEN
                     XMLELEMENT("email", email_string(first_name, last_name))
                  END,
                  CASE WHEN hire_date IS NOT NULL THEN
                     XMLELEMENT("hire_date", date_string(hire_date))
                  END,
                  CASE WHEN phone_num IS NOT NULL THEN
                     XMLELEMENT("phone", phone_num)
                  END)
           }';
END;
/ 
emp_doc SQLマクロは、従業員フィールドをJSON (デフォルト)またはXML文書の文字列に返します。
CREATE FUNCTION emp_doc(first_name VARCHAR2 DEFAULT NULL,
                             last_name VARCHAR2 DEFAULT NULL,
                             hire_date DATE DEFAULT NULL,
                             phone_num VARCHAR2 DEFAULT NULL,
                             doc_type VARCHAR2 DEFAULT 'json')
                    RETURN VARCHAR2 SQL_MACRO(SCALAR) IS
BEGIN
   RETURN q'{
     DECODE(LOWER(doc_type),
            'json', emp_json(first_name, last_name, hire_date, phone_num),
            'xml', emp_xml(first_name, last_name, hire_date, phone_num))
         }';
END;
/
この問合せは、部門30のJSONドキュメント文字列にあるすべての従業員をリストするためのスカラー式で使用されるemp_doc SQLマクロを示しています。
SELECT department_id,
            emp_doc(first_name => e.first_name, hire_date => e.hire_date) doc
FROM hr.employees e
WHERE department_id = 30
ORDER BY last_name;
結果:
  
     30 {"name":"Shelli","email":"shelli@example.com","hire_date":"2005-12-24"}
     30 {"name":"Karen","email":"karen@example.com","hire_date":"2007-08-10"}
     30 {"name":"Guy","email":"guy@example.com","hire_date":"2006-11-15"}
     30 {"name":"Alexander","email":"alexander@example.com","hire_date":"2003-05-19"} 
     30 {"name":"Den","email":"den@example.com","hire_date":"2002-12-07"}
     30 {"name":"Sigal","email":"sigal@example.com","hire_date":"2005-07-24"}
この問合せは、XML文書文字列にあるすべての従業員をリストするためのスカラー式で使用されるemp_doc SQLマクロを示しています。
SELECT deptno,
            emp_doc(first_name => ename, hire_date => hiredate, doc_type => 'xml') doc
FROM scott.emp
ORDER BY ename;
結果:
20 <xml><name>Adams</name><email>adams@example.com</email><hire_date>1987-05-23</hire_date></xml>
30 <xml><name>Allen</name><email>allen@example.com</email><hire_date>1981-02-20</hire_date></xml>
30 <xml><name>Blake</name><email>blake@example.com</email><hire_date>1981-05-01</hire_date></xml> 
10 <xml><name>Clark</name><email>clark@example.com</email><hire_date>1981-06-09</hire_date></xml> 
20 <xml><name>Ford</name><email>ford@example.com</email><hire_date>1981-12-03</hire_date></xml> 
...
30 <xml><name>Ward</name><email>ward@example.com</email><hire_date>1981-02-22</hire_date></xml>
VARIABLE surname VARCHAR2(100)
EXEC :surname := 'ellison'
WITH e AS (SELECT emp.*, :surname lname FROM emp WHERE deptno IN (10,20))
SELECT deptno,
       emp_doc(first_name => ename, last_name => lname, hire_date => hiredate) doc
FROM e
ORDER BY ename;
結果:
10 {"name":"Clark Ellison","email":"clark.ellison@example.com","hire_date":"1981-06-09"} 
20 {"name":"Ford Ellison","email":"ford.ellison@example.com","hire_date":"1981-12-03"}
20 {"name":"Jones Ellison","email":"jones.ellison@example.com","hire_date":"1981-04-02"}
10 {"name":"King Ellison","email":"king.ellison@example.com","hire_date":"1981-11-17"}
10 {"name":"Miller Ellison","email":"miller.ellison@example.com","hire_date":"1982-01-23"}
20 {"name":"Scott Ellison","email":"scott.ellison@example.com","hire_date":"1987-04-19"}
20 {"name":"Smith Ellison","email":"smith.ellison@example.com","hire_date":"1980-12-17"}

例14-2 Env:スカラー式でのScalarマクロの使用

env SQLマクロは、現在のセッションについて説明するコンテキスト・ネームスペースUSERENVに関連付けられたパラメータの値にラッパーを提供します。

CREATE PACKAGE env AS
   FUNCTION current_user RETURN VARCHAR2 SQL_MACRO(SCALAR);
   FUNCTION current_edition_name RETURN VARCHAR2 SQL_MACRO(SCALAR);
   FUNCTION module RETURN VARCHAR2 SQL_MACRO(SCALAR);
   FUNCTION action RETURN VARCHAR2 SQL_MACRO(SCALAR);
END;
/
CREATE PACKAGE BODY env AS
   FUNCTION current_user RETURN VARCHAR2 SQL_MACRO(SCALAR) IS
     BEGIN
        RETURN q'{SYS_CONTEXT('userenv','SESSION_USER')}';
     END;
   FUNCTION current_edition_name RETURN VARCHAR2 SQL_MACRO(SCALAR) IS
     BEGIN
        RETURN q'{SYS_CONTEXT('userenv','CURRENT_EDITION_NAME')}';
     END;
   FUNCTION module RETURN VARCHAR2 SQL_MACRO(SCALAR) IS
     BEGIN
        RETURN q'{SYS_CONTEXT('userenv','MODULE')}';
     END;
   FUNCTION action RETURN VARCHAR2 SQL_MACRO(SCALAR) IS
     BEGIN
        RETURN q'{SYS_CONTEXT('userenv','ACTION')}';
     END;
END;
/

現在のユーザー情報を選択します。

SELECT env.current_user, env.module, env.action FROM DUAL;
結果:
SCOTT   SQL*PLUS            

例14-3 Budget :表式でのTableマクロの使用

この例は、表式で使用するbudgetというSQLマクロを示しています。このマクロは、特定の役職の従業員に対する部署ごとの合計給与を返します。

CREATE FUNCTION budget(job VARCHAR2) RETURN VARCHAR2 SQL_MACRO IS
BEGIN
   RETURN q'{SELECT deptno, SUM(sal) budget 
             FROM scott.emp
             WHERE job = budget.job
             GROUP BY deptno}';
END;

この問合せは、表式で使用されるSQLマクロbudgetを表示します。

SELECT * FROM budget('MANAGER');

結果:

    
DEPTNO     BUDGET 
---------- ----------   
        20       2975  
        30       2850 
        10       2450  

例14-4 Take: 多相ビューでのTableマクロの使用

この例では、表マクロを作成します。このマクロは、表tから最初のn行を返します。
CREATE FUNCTION take (n NUMBER, t DBMS_TF.table_t) 
                      RETURN VARCHAR2 SQL_MACRO IS
BEGIN
   RETURN 'SELECT * FROM t FETCH FIRST take.n ROWS ONLY';
END;
/
この問合せでは、表部門の最初の2行が戻されます。
SELECT * FROM take(2, dept);
結果:
    DEPTNO DNAME          LOC   
---------- -------------- -------------   
        10 ACCOUNTING     NEW YORK       
        20 RESEARCH       DALLAS   
VAR row_count NUMBER
EXEC :row_count := 5

WITH t AS (SELECT * FROM emp NATURAL JOIN dept ORDER BY ename)
SELECT ename, dname FROM take(:row_count, t);
結果:
ENAME      DNAME  
---------- --------------    
ADAMS      RESEARCH     
ALLEN      SALES     
BLAKE      SALES   
CLARK      ACCOUNTING   
FORD       RESEARCH    

例14-5 Range :表式でのTableマクロの使用

この例では、範囲[first, stop]の行の等差数列を生成するSQLマクロを作成します。最初の行は値firstから始まり、それ以降の各行の値は、直前の行の値よりもstepだけ大きな値になります。

次の引数の組合せにより、生成される行数がゼロになります。
  • step < 0およびfirst < stop
  • step = 0
  • step > 0およびfirst > stop
/*  PACKAGE NAME: GEN
 *  SQL TABLE MACROS:
 *     range(stop  : number to generate starting from zero)
 *     range(first : starting number of the sequence (default=0), 
 *           stop  : generate numbers up to, but not including this number, 
 *           step  : difference between each number in the sequence (default=1) )
*/
CREATE PACKAGE gen IS 
   FUNCTION range(stop NUMBER)
            RETURN VARCHAR2 SQL_MACRO(TABLE);

   FUNCTION range(first NUMBER DEFAULT 0, stop NUMBER, step NUMBER DEFAULT 1)
            RETURN VARCHAR2 SQL_MACRO(TABLE);

   FUNCTION tab(tab TABLE, replication_factor NATURAL)
            RETURN TABLE PIPELINED ROW POLYMORPHIC USING gen;

   FUNCTION describe(tab IN OUT DBMS_TF.TABLE_T, replication_factor NATURAL)
            RETURN DBMS_TF.DESCRIBE_T;

   PROCEDURE fetch_rows(replication_factor NATURALN);
END gen;
/
CREATE PACKAGE BODY gen IS 
   FUNCTION range(stop NUMBER)
            RETURN VARCHAR2 SQL_MACRO(TABLE) IS
   BEGIN 
      RETURN q'{SELECT ROWNUM-1 n FROM gen.tab(DUAL, stop)}'; 
   END;

   FUNCTION range(first NUMBER DEFAULT 0, stop NUMBER, step NUMBER DEFAULT 1)
           RETURN VARCHAR2 SQL_MACRO(TABLE) IS
   BEGIN
      RETURN q'{
             SELECT first+n*step n FROM gen.range(ROUND((stop-first)/NULLIF(step,0)))
             }';
   END;
 
   FUNCTION describe(tab IN OUT DBMS_TF.TABLE_T, replication_factor NATURAL) 
            RETURN DBMS_TF.DESCRIBE_T AS
   BEGIN 
      RETURN DBMS_TF.DESCRIBE_T(row_replication => true);
   END;

  PROCEDURE fetch_rows(replication_factor NATURALN) as
  BEGIN 
    DBMS_TF.ROW_REPLICATION(replication_factor); 
  END;
END gen;
/

gen.get_range SQLマクロは、表式で使用します。

この問合せは、ゼロから始まる連続する5行を返します。
SELECT * FROM gen.range(5);
結果:
         0 
         1 
         2 
         3 
         4   
この問合せは、5から始まり、10未満までのシーケンスを返します。
SELECT * FROM gen.range(5, 10);
結果:
         5  
         6  
         7  
         8   
         9   
この問合せは、ゼロから始まり、0.1ずつ増分して1で停止するシーケンスを返します。
SELECT * FROM gen.range(0, 1, step=>0.1);
結果:
 
         0  
        .1  
        .2  
        .3  
        .4  
        .5  
        .6  
        .7   
        .8   
        .9   
この問合せは、5から始まり、2ずつ減少して-6で停止(これを含まない)するシーケンスを返します。
SELECT * FROM gen.range(+5,-6,-2);
結果:
      5 
      3   
      1   
     -1 
     -3 
     -5  

関連トピック