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の2つの変数を宣言しています。出力結果は次のとおりです: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以下のバージョンの場合、パッケージタイプはパッケージ内のルーチンパラメータ位置に存在するタイプである必要があります。パッケージ内で定義されているだけで、パッケージ内のいずれのルーチンパラメータでも使用されていない場合は、呼び出しはサポートされません。
-
リモートの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;
その他のUDFの説明と紹介については、ユーザー定義関数を参照してください。
パッケージ関数を呼び出します。
リモートの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に関するその他の操作については、以下の情報を参照してください: