DBLinkを使用して、テーブル、ビュー、シノニム、シーケンス、ストアドプロシージャ、UDFなどのリモートデータベースオブジェクトにアクセスできます。
前提条件
DBLinkの作成が完了していることを確認してください。DBLinkの作成手順については、DBLinkの作成を参照してください。
OceanBase V4.2.1以降では、DBLink機能を使用してリモートのOracleデータベースにアクセスする場合、クラスタ内のすべてのOBServerノードにOCI-12.2をインストールおよび設定する必要があります。また、OceanBase V4.2.1未満からV4.2.1以上にアップグレードする場合も、既に設定されているOCI-11.2をOCI-12.2に再設定する必要があります。
OCI-12.2のインストールと設定の詳細な手順については、OCIのインストールと設定を参照してください。
リモートデータベースのテーブルデータへのアクセス
SELECT... FROM テーブル名@DBLink 名 構文を使用して、リモートデータベースのテーブルデータにアクセスできます。SQLステートメントは以下のとおりです:
SELECT select_expr_list
FROM table_name@dblink_name
WHERE where_conditions;
select_expr_list:
table_name.*
| table_alias_name.*
| expr [[AS] column_alias_name]
ステートメントの使用方法:
select_expr_list:クエリ対象の式または列名を指定します。複数の列は半角カンマ(,)で区切り、アスタリスク(*)はすべての列を表します。table_name.*:指定したテーブルやビューからすべての列を選択します。table_alias_name.*:テーブルやビューのエイリアスを指定します。expr [[AS] column_alias_name]:クエリ列や式のエイリアスを指定します。ASはオプションです。
table_name@dblink_name:クエリ対象のリモートデータベースのテーブルを指定します。複数のデータベースは半角カンマ(,)で区切ります。where_conditions:フィルタ条件を指定します。クエリ結果には条件を満たすデータのみが含まれます。これはオプションです。
その他のDBLink関連のクエリステートメントについては、SIMPLE SELECTを参照してください。
my_link という名前のDBLinkを使用して、リモートデータベースのテーブル tbl1 のデータをクエリする例を以下に示します:
obclient [SYS]> SELECT * FROM tbl1@my_link;
リモートデータベース内のシーケンスへのアクセス
OceanBase データベースは V4.2.1 以降、DBLink を使用してリモートデータベース(OceanBase データベースおよび Oracle データベースを含む)内のシーケンス値にアクセスできるようになりました。
例:
ローカルデータベースで、リモートの OceanBase データベースの Oracle テナントへの DBLink
my_linkとデータベーステーブルtbl1を作成します。DBLink
my_linkの作成obclient [SYS]> CREATE DATABASE LINK my_link CONNECT TO ob_user@oracle IDENTIFIED BY ****** HOST 'xx.xx.xx.xx:2881';テーブル
tbl1の作成obclient [SYS]> CREATE TABLE tbl1 (C1 int,C2 int);
リモートの OceanBase データベースで、シーケンス
seqを作成します。obclient [SYS]> CREATE SEQUENCE seq START WITH 10000 INCREMENT BY 1 CACHE 50 NOCYCLE;作成成功後、シーケンスの次の値が
10000であることを確認します。obclient [SYS]> SELECT seq.nextval FROM DUAL;結果は次のとおりです:
+---------+ | NEXTVAL | +---------+ | 10000 | +---------+ 1 row in setシーケンスに関するその他の操作については、シーケンスの管理を参照してください。
ローカルデータベースで、DBLink を使用してリモートシーケンスの次の値と現在値を確認します。
次の値の確認
obclient [SYS]> SELECT seq.nextval@my_link FROM DUAL;クエリ結果は次のとおりです:
+---------+ | NEXTVAL | +---------+ | 10001 | +---------+ 1 row in set現在値の確認
obclient [SYS]> SELECT seq.currval@my_link FROM DUAL;クエリ結果は次のとおりです:
+---------+ | CURRVAL | +---------+ | 10001 | +---------+ 1 row in set
DBLink を使用して、リモートシーケンスの値をローカルデータベースのテーブルに挿入します。
obclient [SYS]> INSERT INTO tbl1(C1,C2) VALUES (1,seq.nextval@my_link);挿入成功後、テーブル内のデータをクエリします:
obclient [SYS]> SELECT * FROM tbl1;結果は次のとおりです:
+------+-------+ | C1 | C2 | +------+-------+ | 1 | 10002 | +------+-------+ 1 row in set
注意:特定の特殊なシナリオでは、OceanBase データベースがリモートデータベースオブジェクトのクエリパフォーマンスを向上させるため、システムがリモートシーケンスの CURRVAL の最新値を取得できない場合があります。例えば、以下のクエリ文では、OceanBase データベースは SELECT 部分全体をリモート側に実行委譲し、ローカル側はデータの取得と挿入のみを担当します。文の実行が成功した後、SELECT seq.currval#my_link FROM DUAL; 文で CURRVAL 値をクエリする際、最新の値を取得できない可能性があります。
INSERT INTO local_tbl1 SELECT remote_tbl1.NAME, seq.nextval@my_link FROM remote_tbl1@my_link;
リモートデータベース内のストアドプロシージャを呼び出す
OceanBaseデータベースは、DBLinkを介してリモートのOracleデータベースまたはOceanBase Oracleテナント内のストアドプロシージャを呼び出すことをサポートしています。 現在のOceanBaseデータベースのOracleモードでは、DBLinkは複雑なデータ型の転送をサポートしています。このような型は通常、基本型(整数、文字列など)だけでなく、ネストされた複雑な構造も含みます。サポートされているネスト方法は以下のとおりです:
- record(basic):基本型のフィールドを含むレコード型です。
- array(basic):要素が基本型の配列型です。
- array(record(basic)):要素がレコード型で、そのレコード型のフィールドが基本型の配列型です。
DBLinkを介して、リモートのOceanBase Oracleテナント内の複雑型パラメータを含むストアドプロシージャを呼び出す際には、以下の点に注意する必要があります:
record(basic),array(basic),array(record(basic))の複雑型のみがサポートされており、これらは直接呼び出しを行うパッケージ内で定義されている必要があります。- 現在、
BINARY_DOUBLE型をarray(basic)、array(record(basic))方式で呼び出すことはサポートされていません。 - 現在、
float/timestamp/timestmap with time zone/timestamp with local time zoneの各型を配列型の出力パラメータとして使用することはサポートされていません。 - リモートのネイティブOceanBaseデータベースのストアドプロシージャを呼び出す場合、
char型のパラメータをサポートします。
DBLinkを介してリモートのOracleデータベース内のストアドプロシージャを呼び出す前に、以下の点に注意する必要があります:
リモートのネイティブOracleデータベースのストアドプロシージャを呼び出す場合、
char型のパラメータはサポートされていません。ストアドプロシージャを呼び出す際、以下の基本型の入出力パラメータをサポートします:
VARCHAR2、VARCHAR、CHAR などの文字列型
NUMBER、INT、INTEGER、FLOAT、DOUBLE などの数値型
DATE 型
TIMESTAMP 型
パッケージのストアドプロシージャを呼び出す際、パッケージ型が以下の複合データ型である場合の入出力パラメータをサポートします:
-
同時に、レコード型の要素型も以下の基本型である必要があります:
VARCHAR2、VARCHAR、CHAR などの文字列型
NUMBER、INT、INTEGER、FLOAT、DOUBLE などの数値型
DATE 型
TIMESTAMP 型
ただし、リモートのOracleデータベースがoracle-12c以下のバージョンの場合、パッケージ型はパッケージ内のルーチンパラメータの位置に存在する型である必要があります。パッケージ内でのみ定義され、パッケージ内のいかなるルーチンパラメータでも使用されていない場合は、呼び出しはサポートされません。
-
リモートのOracleデータベース内部のストアドプロシージャやパッケージのシノニムを呼び出すことをサポートします。また、ローカルデータベース内に作成されたリモートのストアドプロシージャやパッケージのシノニムを呼び出すこともサポートします。
リモートのパッケージ型のコンストラクタはサポートされていません。
以下、いくつかの簡単な例を用いて説明します。ローカルのOceanBaseデータベースに、リモートのOracleデータベースへのDBLink orcl_link が作成されていることを前提とします。
obclient [SYS]> CREATE DATABASE LINK orcl_dblink CONNECT TO orcl_user@oracle IDENTIFIED BY ****** OCI HOST 'xx.xx.xx.xx:1521/ORCL';
シンプルなストアドプロシージャを呼び出す。
データ環境を準備します。
リモートのOracleデータベースには顧客情報テーブル
customer_infoが存在します:SQL> CREATE TABLE customer_info (id NUMBER, name VARCHAR2(20));そして、テーブルに以下のデータを挿入します:
SQL> INSERT INTO customer_info (id, name) VALUES (2, 'Jane Smith');SQL> INSERT INTO customer_info (id, name) VALUES (3, 'Mike Johnson');SQL> INSERT INTO customer_info (id, name) VALUES (4, 'Sarah Davis');SELECT * FROM customer_info;ステートメントを実行してテーブルのデータをクエリすると、結果は次のとおりです:ID NAME ---------- -------------------- 2 Jane Smith 3 Mike Johnson 4 Sarah Davis同時に、リモートデータベースにはストアドプロシージャも作成されています。このストアドプロシージャは、
customer_idパラメータを受け取り、その顧客のIDを返すために使用されます。SQL> CREATE OR REPLACE PROCEDURE get_customer_id ( customer_id IN NUMBER ) IS BEGIN DBMS_OUTPUT.PUT_LINE('Customer ID is: ' || customer_id); END; /ローカルのOceanBaseデータベースでストアドプロシージャを呼び出します。
obclient [SYS]> CALL get_customer_id@orcl_dblink(2);
しかし、現在、以下の方法でこのストアドプロシージャを呼び出すことはサポートされていません。以下のステートメントで上記のストアドプロシージャを呼び出すと、エラーが発生します:
SELECT get_customer_id@orcl_dblink(2) FROM DUAL;それ以外にも、リモートのOracleデータベース上のストアドプロシージャ
get_customer_idに対して以下のシノニムを作成した場合:リモートのOracleデータベース上でストアドプロシージャ
get_customer_idのシノニムsyn_remote_customer_idを作成します。obclient> CREATE OR REPLACE SYNONYM syn_remote_customer_id FOR get_customer_id;ローカルのOceanBaseデータベース上で、DBLinkを通じてストアドプロシージャ
get_customer_idのシノニムsyn_local_customer_idを作成します。obclient [SYS]> CREATE OR REPLACE SYNONYM syn_local_customer_id FOR get_customer_id@orcl_dblink;
これらのシノニムを呼び出すことができます。呼び出しステートメントは以下のとおりです:
リモートのOracleデータベース上のシノニムを呼び出します。
obclient [SYS]> CALL syn_remote_customer_id@orcl_dblink(2);ローカルのOceanBaseデータベース上のシノニムを呼び出します。
obclient [SYS]> CALL syn_local_customer_id(2);
入出力パラメータを含むストアドプロシージャを呼び出します。
以下のように、リモートのOracleデータベースに
employeesという従業員テーブルが存在すると仮定します:SQL> CREATE TABLE employees (name VARCHAR2(20), id NUMBER);ストアドプロシージャを作成しました。このストアドプロシージャは、
p_employee_idを入力パラメータとして受け取り、その従業員の名前とIDを返します。該当する従業員が見つからない場合はEmployee not foundのメッセージを返し、他の例外が発生した場合はError occurredを返します。SQL> CREATE OR REPLACE PROCEDURE get_employee_info ( p_employee_id IN NUMBER, p_employee_name OUT VARCHAR2, p_employee_id_out OUT NUMBER ) IS BEGIN SELECT name, id INTO p_employee_name, p_employee_id_out FROM employees WHERE id = p_employee_id; EXCEPTION WHEN NO_DATA_FOUND THEN p_employee_name := 'Employee not found'; p_employee_id_out := NULL; WHEN OTHERS THEN p_employee_name := 'Error occurred'; p_employee_id_out := NULL; END; /入力パラメータ
employee_idと出力パラメータemployee_nameのデータ型はすべて要件を満たしています。ローカルデータベースで、以下のステートメントを使用してストアドプロシージャを呼び出すことができます。obclient [SYS]> SET SERVEROUTPUT ON;obclient [SYS]> DECLARE v_employee_name VARCHAR2(20); v_employee_id NUMBER; BEGIN get_employee_info@orcl_dblink(1, v_employee_name, v_employee_id); DBMS_OUTPUT.PUT_LINE('Employee Name: ' || v_employee_name); DBMS_OUTPUT.PUT_LINE('Employee ID: ' || v_employee_id); END; /上記のステートメントでは、ストアドプロシージャの出力結果を受け取るための変数
v_employee_nameとv_employee_idを宣言しています。出力結果は次のとおりです:Employee Name: Employee not found Employee ID:パッケージ型が複合データ型の入出力パラメータを持つパッケージのストアドプロシージャを呼び出します。
リモートのOracleデータベースには
tbl1_vというテーブルと、パッケージ型がネスト表であるpkg1が存在します。SQL> CREATE TABLE tbl1_v(v varchar2(1000));SQL> CREATE OR REPLACE PACKAGE pkg1 AS TYPE ty1 IS TABLE OF varchar2(32767); TYPE ty2 IS TABLE OF NUMBER; v varchar2(1000); PROCEDURE pro1(param1 ty1); PROCEDURE pro1(param1 ty2); PROCEDURE pro1_out(param1 out ty1); PROCEDURE pro1_out(param1 out ty2); PROCEDURE pro1_inout(param1 in out ty1); PROCEDURE pro1_inout(param1 in out ty2); END; /対応するパッケージ本体は以下のとおりです:
SQL> CREATE OR REPLACE PACKAGE BODY pkg1 IS PROCEDURE pro1(param1 ty1) IS v varchar2(1024); BEGIN DELETE FROM tbl1_v; FOR idx IN param1.first .. param1.last LOOP v := 'param1(' || idx || ')=' || param1(idx) || ';'; INSERT INTO tbl1_v values(v); END LOOP; END; PROCEDURE pro1(param1 ty2) IS BEGIN DELETE FROM tbl1_v; FOR idx in param1.first .. param1.last LOOP v := 'param1(' || idx || ')=' || param1(idx) || ';'; INSERT INTO tbl1_v values(v); END LOOP; END; PROCEDURE pro1_out(param1 out ty1) IS BEGIN param1 := ty1(); param1.extend(10); FOR idx in 1..10 LOOP param1(idx) := idx; END LOOP; END; PROCEDURE pro1_out(param1 out ty2) IS BEGIN param1 := ty2(); param1.extend(10); FOR idx in 1..10 LOOP param1(idx) := idx; END LOOP; END; PROCEDURE pro1_inout(param1 IN OUT ty1) IS BEGIN pro1(param1); pro1_out(param1); END; PROCEDURE pro1_inout(param1 IN OUT ty2) IS BEGIN pro1(param1); pro1_out(param1); END; END; /ローカルのOceanBaseデータベースでは、以下の方法でパッケージのストアドプロシージャを呼び出すことができます:
obclient [SYS]> CREATE TABLE tbl_local (c1 int);obclient [SYS]> INSERT INTO tbl_local VALUES(1);obclient [SYS]> DECLARE param pkg1.ty2@orcl_dblink; BEGIN SELECT C1 bulk collect INTO param FROM tbl_local; pkg1.pro1@orcl_dblink(param); END; /しかし、以下のパッケージのストアドプロシージャ
pkg2については:SQL> CREATE OR REPLACE PACKAGE pkg2 AS TYPE ty1 IS RECORD(c1 varchar2(10), c2 int); TYPE ty2 IS TABLE OF varchar2(10); TYPE ty3 IS TABLE OF ty1; TYPE ty4 IS TABLE OF varchar2(10) INDEX BY PLS_INTEGER; TYPE ty5 IS TABLE OF ty1 INDEX BY PLS_INTEGER; TYPE ty6 IS TABLE OF varchar2(10); PROCEDURE pro2(param1 ty1, param2 ty2, param3 ty3 , param4 ty4, param5 ty5); END; /パッケージ
pkg2に対応するパッケージ本体:SQL> CREATE OR REPLACE PACKAGE BODY pkg2 AS PROCEDURE pro2 (param1 ty1, param2 ty2, param3 ty3 , param4 ty4, param5 ty5) IS BEGIN DBMS_OUTPUT.PUT_LINE('Parameter 1: ' || param1.c1 || ', ' || param1.c2); FOR i IN param2.FIRST .. param2.LAST LOOP DBMS_OUTPUT.PUT_LINE('Parameter 2(' || i || '): ' || param2(i)); END LOOP; FOR i IN param3.FIRST .. param3.LAST LOOP DBMS_OUTPUT.PUT_LINE('Parameter 3(' || i || '): ' || param3(i).c1 || ', ' || param3(i).c2); END LOOP; END pro2; END pkg2; /以下の方法で呼び出すと、エラーが発生します:
obclient [SYS]> DECLARE param1 pkg2.ty1@orcl_dblink; param2 pkg2.ty2@orcl_dblink; param3 pkg2.ty3@orcl_dblink; param4 pkg2.ty4@orcl_dblink; param5 pkg2.ty5@orcl_dblink; BEGIN param1.c1 := 'a'; param1.c2 := 123; param2 := pkg2.ty2@orcl_dblink('b', 'c'); param3 := pkg2.ty3@orcl_dblink(); param3.EXTEND(2); param3(1).c1 := 'd'; param3(1).c2 := 456; param3(2).c1 := 'e'; param3(2).c2 := 789; pkg2.pro2@orcl_dblink(param1, param2, param3, param4, param5); END; /さらに、リモートデータベースがoracle-12c以下のバージョンの場合、この例では
ty6がパッケージpkg2内のルーチンのパラメータリストに含まれていないため、以下のステートメントでパッケージのストアドプロシージャを呼び出すとエラーが発生します:obclient [SYS]> DECLARE v1 pkg2.ty6@orcl_dblink; BEGIN null; END; /パッケージの詳細な使用方法と説明については、プログラムパッケージの作成を参照してください。
リモートデータベース内のUDFを呼び出す
OceanBaseデータベースはV4.2.2バージョンから、DBLinkを介してリモートのOracleデータベース内のUDF(User-Defined functions)およびパッケージ関数を呼び出すことをサポートしています。現在、リモートのOceanBaseデータベース内のUDFやパッケージ関数を呼び出すことはサポートされていません。
DBLinkを介してリモートのOracleデータベース内のUDFまたはパッケージ関数を呼び出す前に、以下の点に注意してください:
UDFを呼び出す際、以下の基本データ型の入出力パラメータをサポートします:
VARCHAR2、VARCHAR、CHARなどの文字列型
NUMBER、INT、INTEGER、FLOAT、DOUBLEなどの数値型
DATE型
TIMESTAMP型
パッケージ関数を呼び出す際、パッケージの型が以下の複合データ型である場合、入出力パラメータをサポートします:
-
同時に、レコード型の要素型も以下の基本データ型である必要があります:
VARCHAR2、VARCHAR、CHARなどの文字列型
NUMBER、INT、INTEGER、FLOAT、DOUBLEなどの数値型
DATE型
TIMESTAMP型
ただし、リモートのOracleデータベースがoracle-12c以下のバージョンの場合、パッケージ型はパッケージ内のRoutineパラメータ位置に現れる型である必要があります。パッケージ内で定義されているだけで、パッケージ内のどのRoutineパラメータでも使用されていない場合は、呼び出しはサポートされません。
-
リモートのOracleデータベース内の関数またはパッケージのシノニムを呼び出すことをサポートしており、ローカルデータベース内に作成されたリモートの関数またはパッケージのシノニムを呼び出すこともサポートしています。
以下の簡単な例をいくつか挙げて説明します。ローカルのOceanBaseデータベースに、リモートのOracleデータベースへのDBLink orcl_link が作成されていることを前提とします。
obclient [SYS]> CREATE DATABASE LINK orcl_dblink CONNECT TO orcl_user@oracle IDENTIFIED BY ****** OCI HOST 'xx.xx.xx.xx:1521/ORCL';
シンプルなUDFを呼び出します。
リモートのOracleデータベースにUDF
AddNumbersを作成します。SQL> CREATE OR REPLACE FUNCTION AddNumbers (num1 IN NUMBER, num2 IN NUMBER) RETURN NUMBER AS BEGIN RETURN num1 + num2; END; /この関数は2つの数値を入力として受け取り、その合計を返します。
ローカルのOceanBaseデータベースでこの関数を呼び出します。
obclient [SYS]> SELECT AddNumbers@orcl_dblink(10, 20) AS Sum_Result FROM DUAL;クエリ結果は次のとおりです:
+------------+ | SUM_RESULT | +------------+ | 30 | +------------+ 1 row in set
ストアドプロシージャと同様に、リモートのOracleデータベースのUDFやパッケージにシノニムを作成した場合、ローカルのOceanBaseデータベースでそのシノニムを通じて呼び出すことができます。例えば、この
AddNumbersに対して以下のシノニムを作成した場合:リモートのOracleデータベースで関数
AddNumbersのシノニムsyn_remote_AddNumbersを作成します。SQL> CREATE OR REPLACE SYNONYM syn_remote_AddNumbers FOR AddNumbers;ローカルのOceanBaseデータベースでDBLinkを通じて関数
AddNumbersのシノニムsyn_local_AddNumbersを作成します。obclient [SYS]> CREATE OR REPLACE SYNONYM syn_local_AddNumbers FOR AddNumbers@orcl_dblink;
これらのシノニムはローカルのOceanBaseデータベースで呼び出すことができ、呼び出しステートメントは以下のとおりです:
リモートのOracleデータベース上のシノニムを呼び出します。
obclient [SYS]> SELECT syn_remote_AddNumbers@orcl_dblink(10, 20) AS Sum_Result FROM DUAL;ローカルのOceanBaseデータベース上のシノニムを呼び出します。
obclient [SYS]> SELECT syn_local_AddNumbers(10, 20) AS Sum_Result FROM DUAL;
詳細および紹介については、ユーザー定義関数を参照してください。
パッケージ関数を呼び出します。
リモートのOracleデータベースにパッケージ
pac_employee_dataを作成し、その中に関数calculate_annual_bonusを定義します。SQL> CREATE OR REPLACE PACKAGE pac_employee_data AS -- 関数のプロトタイプを定義する FUNCTION calculate_annual_bonus(emp_id IN NUMBER, monthly_salary IN NUMBER) RETURN NUMBER; END pac_employee_data; /対応するパッケージ本体は以下のとおりです。
SQL> CREATE OR REPLACE PACKAGE BODY pac_employee_data AS -- 関数を実装する FUNCTION calculate_annual_bonus(emp_id IN NUMBER, monthly_salary IN NUMBER) RETURN NUMBER IS annual_bonus NUMBER; BEGIN -- 従業員の年間ボーナスは年収の10%と仮定する annual_bonus := monthly_salary * 12 * 0.1; RETURN annual_bonus; END calculate_annual_bonus; END pac_employee_data; /ローカルのOceanBaseデータベースでこのパッケージ関数を呼び出します。
PLブロック内でパッケージ内の関数をリモート呼び出しできます。ステートメントは以下のとおりです。
obclient [SYS]> SET SERVEROUTPUT ON;obclient [SYS]> DECLARE emp_id CONSTANT NUMBER := 100; monthly_salary CONSTANT NUMBER := 5000; bonus_amount NUMBER; BEGIN -- パッケージ関数を呼び出して結果を取得する bonus_amount := pac_employee_data.calculate_annual_bonus@orcl_dblink(emp_id, monthly_salary); DBMS_OUTPUT.PUT_LINE('Employee ID: ' || emp_id || ', Annual Bonus: $' || TO_CHAR(bonus_amount, '999,999.99')); END; /実行結果は次のとおりです:
Employee ID: 100, Annual Bonus: $ 6,000.00または、SQLクエリを通じてこのパッケージ関数を呼び出すこともできます。ステートメントは以下のとおりです。
obclient [SYS]> SELECT pac_employee_data.calculate_annual_bonus@orcl_dblink(100, 5000) AS "Annual Bonus" FROM DUAL;クエリ結果は次のとおりです:
+--------------+ | Annual Bonus | +--------------+ | 6000 | +--------------+ 1 row in set
パッケージの詳細な使用方法および説明については、プログラムパッケージの作成を参照してください。
関連ドキュメント
DBLinkに関するその他の操作については、以下を参照してください: