本記事はOracle Cloud Infrastructure Advent Calendar 2025 シリーズ2 の18日目とJPOUG Advent Calendar 2025の18日目のダブルポストです。
はじめに
本記事は過去記事の続きです。
Oracle Database 9i以降ANYDATA型という多種多様なデータ型を格納できるデータ型が存在します。マニュアルなど公式文書では「SYS.ANYDATA」と表現されていますが実利用の際にスキーマ名修飾は不要です。もちろんつけてもかまいません。
このデータ型を使用することにより列数は固定になりますがレコードによって該当列に格納されるデータ型が異なる状態を作ることが可能です。とはいえANYDATAはその1で紹介したオブジェクト型も格納可能です。本記事の方法でもオブジェクト型と併用することでレコードにより列数が異なるテーブルも作成可能です。余談ですが逆にオブジェクト型内の列の型にANYDATAを指定することも可能です。
本記事の検証環境はATP26aiです。
テーブルの作成
create table anydata1 (id number, col1 anydata);
と、データ型をANYDATAで指定するだけです。今回の記事ではanydataの列は一つだけで検証しますが、以下のように複数列作成することも可能です。
create table anydata2 (id number, col1 anydata, col2 anydata, col3 anydata);
データの格納
ANYDATA型の列や変数へのデータのハンドリングはANYDATA型で用意しているファンクションを経由して操作する必要があり、VARCHAR2型やNUMBER型のデータを直接出し入れすることはできません。データの格納はANYDATA.ConvertNumber(12345)のように「Convert+型名」のファンクションを使用します。
insert into anydata1 values(1, anydata.convertnumber(12345));
insert into anydata1 values(2, anydata.convertvarchar2('Hello World'));
insert into anydata1 values(3, anydata.convertdate(current_date));
commit;
データの取り出し
単にselectしただけでは中身のデータへの直接アクセスができないため以下のような表示なります。
SQL> select * from anydata1;
ID
----------
COL1()
--------------------------------------------------------------------------------
1
ANYDATA()
2
ANYDATA()
3
ANYDATA()
格納時と同様ANYDATA型のファンクション経由で取り出す必要があります。データの表示のためにはまずANYDATA.GetTypeName()で型名を確認し、確認できたデータ型に応じてANYDATA.AccessNumber()のように「Access+型名」のファンクションを使用します。ANYDATA.GetTypeName()で戻る型名は「SYS.NUMBER」のように大文字で指定してください。
SQL> select
2 id,
3 case
4 when t.col1.gettypename() = 'SYS.NUMBER' then
5 to_char(sys.anydata.accessnumber(t.col1))
6 when t.col1.gettypename() = 'SYS.VARCHAR2' then
7 sys.anydata.accessvarchar2(t.col1)
8 when t.col1.gettypename() = 'SYS.DATE' then
9 to_char(sys.anydata.accessdate(t.col1), 'yyyy-mm-dd hh24:mi:ss')
10 else '非対応の型'
11 end as value_string
12 from
13 anydata1 t;
ID
----------
VALUE_STRING
--------------------------------------------------------------------------------
1
12345
2
Hello World
3
2025-12-09 12:17:26
もっと簡単に表示する方法としてXMLTYPE型に変換する方法があります。オブジェクト型についてはConvertObject()はあるのですがAccessObject()が存在しません。そのため、SQL*Plusなどのツールで内容を確認するためには、文字列形式で表示するメンバー・ファンクションをコールするかこの方法を使用する必要があります。以下はその1で作成したオブジェクト型を含むレコードの追加後に全件SELECTしてみた例となります。
SQL> select id, xmltype(col1) from anydata1;
ID
----------
XMLTYPE(COL1)
--------------------------------------------------------------------------------
1
<ANYDATA>12345</ANYDATA>
2
<ANYDATA>Hello World</ANYDATA>
3
<ANYDATA>25-12-09</ANYDATA>
4
<REC2_TYPE>
<ID>12B00A05DB614FF0BF938EC297F64ED5</ID>
<COL101>9</COL101>
<COL102>ABC</COL102>
<COL103>9999</COL103>
<COL104>Oracle</COL104>
</REC2_TYPE>