こんにちは、亀井です。

先日APEX_WEB_SERVICE.MAKE_REST_REQUESTをURLパラメータ付きで利用しようとしました。このファンクションは、引数に指定したURLに接続し、結果をCLOBで戻すファンクションです。

マニュアルを参照したところ、URLパラメータを指定する引数(p_parm_name/p_parm_value)に、apex_application_global.VC_ARR2の型を渡すようになっていました。

APEX_STRING.STRING_TO_TABLEを利用するとVC_ARR2型を戻すので、マニュアルの例にある通りこちらを利用すればいいのですが、複数のパラメータを渡す際に区切り文字と同じ値がVALUEにあると余計な分割が入ってしまいます。これではユーザーに入力させた値を利用する場合に困るため、1件ずつパラメータを指定する必要があります。

こちらについて、型の説明がマニュアルに存在しなかったため内容を調査した結果をまとめています。

更新履歴

日付更新概要
2022/11/23記事公開

1件ずつの指定方法について

結論としては以下のように指定すれば1件ずつ値を入れることが出来ます。

DECLARE

  l_clob        CLOB;
  l_name_array  apex_application_global.VC_ARR2;
  l_value_array apex_application_global.VC_ARR2;
BEGIN

  l_name_array(1)  := 'Paramname1';
  l_value_array(1) := 'Value:1';
  l_name_array(2)  := 'Paramname1';
  l_value_array(2) := 'Value/2';
  l_name_array(3)  := 'Paramname1';
  l_value_array(3) := 'Value,3';

  l_clob := APEX_WEB_SERVICE.MAKE_REST_REQUEST(
    p_url         => '<接続先>',
    p_http_method => 'GET',
    p_parm_name   => l_name_array,
    p_parm_value  => l_value_array
  );
END;
/

定義の詳細

定義についての実態確認

apex_application_global.VC_ARR2の定義をデータベースから探っていきます。

set pages 1000 line 120 trim on tab off
col OWNER format a20
col OBJECT_NAME format a30
col SUBOBJECT_NAME format a30
select
  OWNER,
  OBJECT_NAME,
  SUBOBJECT_NAME,
  OBJECT_TYPE
from
  DBA_OBJECTS
where
  OBJECT_NAME = 'APEX_APPLICATION_GLOBAL';
OWNER                OBJECT_NAME                    SUBOBJECT_NAME                 OBJECT_TYPE
-------------------- ------------------------------ ------------------------------ ------------
PUBLIC               APEX_APPLICATION_GLOBAL                                       SYNONYM

シノニムのため、実際のパッケージを検索します。

col OWNER format a20
col TABLE_OWNER format a20
col TABLE_NAME format a30
select
  OWNER,
  TABLE_OWNER,
  TABLE_NAME
from
  DBA_SYNONYMS
where
  SYNONYM_NAME = 'APEX_APPLICATION_GLOBAL';
OWNER                TABLE_OWNER          TABLE_NAME
-------------------- -------------------- ------------------------------
PUBLIC               APEX_220100          WWV_FLOW_GLOBAL
select
  OWNER,
  OBJECT_NAME,
  SUBOBJECT_NAME,
  OBJECT_TYPE
from
  DBA_OBJECTS
where
  OBJECT_NAME = 'WWV_FLOW_GLOBAL';
OWNER                OBJECT_NAME                    SUBOBJECT_NAME                 OBJECT_TYPE
-------------------- ------------------------------ ------------------------------ -------------
PUBLIC               WWV_FLOW_GLOBAL                                               SYNONYM
APEX_220100          WWV_FLOW_GLOBAL                                               PACKAGE
APEX_220100          WWV_FLOW_GLOBAL                                               PACKAGE BODY

実際のコードを確認します。

col TEXT format a85
select
  LINE,
  TEXT
from
  DBA_SOURCE
where
  OWNER = 'APEX_220100'
  and NAME = 'WWV_FLOW_GLOBAL'
  and TYPE = 'PACKAGE'
order by
  LINE;

select
  LINE,
  TEXT
from
  DBA_SOURCE
where
  OWNER = 'APEX_220100'
  and NAME = 'WWV_FLOW_GLOBAL'
  and TYPE = 'PACKAGE BODY'
order by
  LINE;

パッケージに以下の定義が見つかります。

subtype vc_arr2 is sys.dbms_sql.varchar2a;

sys.dbms_sql.varchar2aの定義についてはマニュアルに記載されており、数値索引の連想配列ということがわかります。

162.8.25 DBMS_SQL VARCHAR2A表タイプ

TYPE varchar2a IS TABLE OF VARCHAR2(32767) INDEX BY BINARY_INTEGER;

利用する索引の数値について

ここまででやっと型についてわかったわけですが、数値索引は連続していなくてもマイナスの値でも値を投入できます。
では、Oracle APEXで基本的に何を使えば良いのかというと、APEX_STRING.STRING_TO_TABLEの結果に合わせて、1から連続した値を使うのがベターかと思います。

set serveroutput on
DECLARE

  l_array  apex_application_global.VC_ARR2;
BEGIN

  l_array := APEX_STRING.STRING_TO_TABLE('A:B:C', ':');

  DBMS_OUTPUT.PUT_LINE('First: '||to_char(l_array.first));
  DBMS_OUTPUT.PUT_LINE('Last: '||to_char(l_array.last));

  for i in l_array.first..l_array.last
  loop
    DBMS_OUTPUT.PUT_LINE('Num: '||to_char(i)||' Value:'||l_array(i));
  end loop;
END;
/
First: 1
Last: 3
Num: 1 Value:A
Num: 2 Value:B
Num: 3 Value:C