コンテンツにスキップ

5.10 TAGメタデータ

Tagメタデータ

概要

METADATAはタグごとに1行の現在の属性です。通常のTAG検索では、同じ属性が各DATA行とともに 表示されます。現在の属性を変えると過去のDATAの検索結果にも新しい属性が表示される場合があるため、 発生時点の属性が必要な場合はDATAまたは別の属性履歴に保存します。

以下では基本メタデータ、JSONメタデータ、全体例を別々のテーブルに分けます。 タグの静的属性を保存する領域として使用し、センサー位置、装置状態、設置情報、外部識別子、 JSONドキュメント形式の属性を格納できます。

メタデータ専用SQLで次の操作を実行できます。以下の例のTAGはテーブル名であり、 使用時には実際のTAGテーブル名に置き換えます。

  • メタデータ専用の検索
  • メタデータ条件によるUPDATE / DELETE
  • メタデータ行の最終変更時刻の検索
  • ARRAYメタデータ列のADD/DROPと既存行へのDEFAULT適用
  • JSON型メタデータ列の宣言
  • JSONパスの検索とJSONパスインデックス
  • JSONドキュメントの一部だけを変更する部分更新

ユーザーは内部ストレージテーブルを直接操作せず、TAG METADATA構文だけを使用できます。

メタデータ列の定義

メタデータ列はCREATE TAG TABLEMETADATA (...)句で定義します。

CREATE TAG TABLE ch5_meta (
    name VARCHAR(20) PRIMARY KEY,
    time DATETIME BASETIME,
    value DOUBLE
)
METADATA (
    location VARCHAR(100),
    status VARCHAR(20),
    srcip IPV4
);

メタデータ列はタグ名ごとに1行だけ保存されます。

ARRAYメタデータ列の追加と削除

Standard Editionでは、既存TAGテーブルのMETADATA領域に固定長の数値ARRAY列を 追加・削除できます。

INSERT INTO ch5_meta (name, time, value)
VALUES ('TEMP_OLD', TO_DATE('2026-09-05 00:00:00'), 10.0);

ALTER TABLE ch5_meta METADATA
    ADD COLUMN (limits DECIMAL(12,4)[2] DEFAULT [0.0000, NULL]);

INSERT INTO ch5_meta (name, time, value)
VALUES ('TEMP_NEW', TO_DATE('2026-09-05 00:00:01'), 20.0);

SELECT name, limits
  FROM ch5_meta METADATA
 ORDER BY name;

ALTER前から存在するTEMP_OLDのメタデータ行には[0.0000, NULL]が補充されます。 ALTER後にTAG DATAの入力で自動登録されたTEMP_NEWのメタデータ行にはADD COLUMNのDEFAULTが 再適用されず、limits全体がNULLになります。DEFAULTがない場合はALTER前の行も全体がNULLです。

追加したARRAYメタデータ列は、通常のTAG検索の明示的な射影とSELECT *にも含まれます。 ARRAYメタデータ列にはインデックスが自動作成されず、以下のような明示的なインデックスも サポートされません。

-- サポートされず、エラーを返します。
CREATE INDEX idx_sensor_limits ON ch5_meta METADATA(limits);

列を削除する場合もMETADATAを指定します。

ALTER TABLE ch5_meta METADATA DROP COLUMN (limits);

TAG DATAの通常のARRAY列はCREATE TAG TABLEで宣言できますが、ALTERでは追加できません。 サポートされる要素型、要素数、DEFAULTの規則は 数値ARRAY型を参照してください。

メタデータの入力

メタデータはINSERT INTO ... METADATAで入力します。

INSERT INTO ch5_meta METADATA VALUES (
    'TEMP_001',
    'Building-A/F1',
    'READY',
    '192.168.0.11'
);

列一覧も指定できます。

INSERT INTO ch5_meta METADATA (name, status, srcip, location)
VALUES ('TEMP_002', 'STOP', '192.168.0.12', 'Building-A/F2');

注意事項:

  • 列一覧を省略したVALUESは、タグ名に続いてメタデータの宣言順に従います。
  • 列一覧を指定した場合は、その一覧の順に値を渡します。
  • 省略した入力のNULL・DEFAULT処理は、該当DDLと入力経路の規則に従います。
  • 識別子はTAGのタグ名列です。この例ではnameという名前で宣言しています。
  • メタデータ行の作成時に_LAST_UPDATE_TIMEがサーバー時刻で自動記録されます。

メタデータの検索

メタデータのみ検索

メタデータ専用検索はFROM TAG METADATAを使用します。

SELECT name, location, status, srcip
  FROM ch5_meta METADATA
 ORDER BY name;

この検索はタグ名ごとに1行を返します。

SELECT *
  FROM ch5_meta METADATA
 ORDER BY name;

SELECT *table_alias.*NAMEとメタデータ列のみを返します。

_LAST_UPDATE_TIMEなどのシステム管理列はSELECT *の結果に表示されません。 必要な場合は列名を明示します。

最終変更時刻の検索

TAGメタデータには、各メタデータ行の最終変更時刻を示すシステム管理列 _LAST_UPDATE_TIMEがあります。

_LAST_UPDATE_TIMEはTagデータ行の最終入力時刻ではなく、Tagメタデータ行が作成された時刻、 または実際にメタデータ値が変更された時刻です。

検索方法

_LAST_UPDATE_TIMEは列名を明示して検索します。

SELECT name, _last_update_time
  FROM ch5_meta METADATA;

他のメタデータ列とともに検索したり、条件に使用したりできます。

SELECT name, location, status, _last_update_time
  FROM ch5_meta METADATA
 WHERE name = 'TEMP_001';

SELECT *table_alias.*の結果には_LAST_UPDATE_TIMEは表示されません。

自動記録・更新の規則

メタデータ行が新しく作成されると_LAST_UPDATE_TIMEが自動記録されます。

INSERT INTO ch5_meta METADATA(name, location, status)
VALUES('TEMP_003', 'Building-A/F3', 'READY');

ユーザーメタデータ値が実際に変わると_LAST_UPDATE_TIMEが更新されます。

UPDATE ch5_meta METADATA
   SET status = 'DONE'
 WHERE name = 'TEMP_003';

同じ値への更新やJSONの存在しないパスの削除など、保存結果が変わらない更新は実際の変更と みなしません。この場合、_LAST_UPDATE_TIMEは維持されます。

UPDATE ch5_meta METADATA
   SET status = 'DONE'
 WHERE name = 'TEMP_003';

JSONの存在しないパスの削除も、保存値が変わらなければno-opです。 実行例は以下のJSONテーブルを作成してから確認します。

直接入力・変更の制限

_LAST_UPDATE_TIMEはシステム管理列のため、ユーザーが直接値を入力・変更できません。

次の文は許可されません。

INSERT INTO ch5_meta METADATA(name, location, status, _last_update_time)
VALUES('TEMP_004', 'Building-A/F4', 'READY', now);
UPDATE ch5_meta METADATA
   SET _last_update_time = now
 WHERE name = 'TEMP_003';

また、TAGの名前列名、TAGメタデータ列名、ALTER TABLE ... METADATA ADD COLUMNの 対象列名に_LAST_UPDATE_TIMEは使用できません。 ALTER TABLE ... METADATA DROP COLUMN_LAST_UPDATE_TIMEを削除することもできません。

CREATE TAG TABLE invalid_sensor (
    _last_update_time VARCHAR(128) PRIMARY KEY,
    time              DATETIME BASETIME,
    value             DOUBLE
);
CREATE TAG TABLE invalid_sensor_meta (
    name  VARCHAR(128) PRIMARY KEY,
    time  DATETIME BASETIME,
    value DOUBLE
)
METADATA (
    _last_update_time DATETIME
);

_LAST_UPDATE_TIME2のように接頭辞だけが同じ名前は、別のユーザー列として使用できます。

時間条件による検索と自動インデックス

_LAST_UPDATE_TIMEには時間条件検索用のインデックスが自動提供されます。

SELECT name, location, _last_update_time
  FROM ch5_meta METADATA
 WHERE _last_update_time >= TO_DATE('2026-06-08 00:00:00')
 ORDER BY _last_update_time;

そのため、ユーザーが同じ列に別のインデックスを重複作成する必要はありません。

machloader / tagmetaimportの使用時の注意事項

TAGメタデータのインポートでは、入力ファイルやformファイルにはNAMEとユーザーメタデータ列のみを 含めます。内部列_IDとシステム管理列_LAST_UPDATE_TIMEは入力対象ではありません。

メタデータがlocationstatusの場合、入力データは次の形式です。

TEMP_001,Building-A/F1,READY
TEMP_002,Building-A/F2,STOP

_LAST_UPDATE_TIMEはインポート時にサーバーが自動設定します。

通常のLOG、LOOKUP、VOLATILEテーブルでユーザーが_LAST_UPDATE_TIMEという列を定義した場合は、 通常のユーザー列として動作します。予約された動作はTAGメタデータのシステム列だけに適用されます。

データとともに検索

メタデータ条件で時系列データを検索する場合は、通常のFROM TAGを使用します。

SELECT name, status, time, value
  FROM ch5_meta
 WHERE status = 'READY'
 ORDER BY name, time;

この検索はデータ行単位で返すため、同じタグのメタデータ値が各データ行で繰り返されます。

注意事項:

  • FROM TAG METADATAではTIMEVALUEなどのデータ列は検索できません。
  • FROM TAGはデータ検索モード、FROM TAG METADATAはメタデータ検索モードです。
  • TAG METADATAでは内部列_ID_RIDを使用できません。

メタデータの更新

メタデータの更新はUPDATE TAG METADATAを使用します。

UPDATE ch5_meta METADATA
   SET status = 'DONE',
       srcip = '10.0.0.20'
 WHERE name = 'TEMP_001';

メタデータ条件で複数タグを一度に更新することもできます。

UPDATE ch5_meta METADATA
   SET status = 'DONE'
 WHERE status = 'READY';

注意事項:

  • 更新対象はNAMEとメタデータ列です。
  • TIMEVALUEなどのデータ列はUPDATE ... METADATAで変更できません。
  • 内部列は変更できません。
  • 実際にメタデータ値が変わった場合だけ_LAST_UPDATE_TIMEが更新されます。

メタデータの削除

メタデータの削除はDELETE FROM TAG METADATAを使用します。

特定タグのメタデータを削除する場合は、WHERE句でタグ名条件を指定します。

DELETE FROM ch5_meta METADATA
 WHERE name = 'TEMP_002';

メタデータ条件で複数タグを一度に削除することもできます。

DELETE FROM ch5_meta METADATA
 WHERE status = 'STOP';

WHERE句を省略すると全メタデータが対象です。この実習には前に入力したTEMP_OLD・TEMP_NEWの DATAが残っているため、以下の全削除は意図的に失敗します。

DELETE FROM ch5_meta METADATA;

注意事項:

  • 削除対象のいずれかに実データ行がある場合、文全体が失敗します。
  • つまり、使用中のタグのメタデータは削除できません。
  • 全削除でも使用中のタグが1つでもあると、一部だけを削除せず文全体が失敗します。

使用中のタグのメタデータを削除する場合は、先にそのタグのデータ行を削除してから メタデータ削除を再実行します。

DELETE FROM ch5_meta
 WHERE name = 'TEMP_001';

DELETE FROM ch5_meta METADATA
 WHERE name = 'TEMP_001';

JSONメタデータ列

メタデータにJSON列を宣言できます。

CREATE TAG TABLE ch5_meta_json (
    name VARCHAR(20) PRIMARY KEY,
    time DATETIME BASETIME,
    value DOUBLE
)
METADATA (
    status VARCHAR(20),
    info JSON
);

JSONメタデータの入力例:

INSERT INTO ch5_meta_json METADATA VALUES (
    'SHIP_001',
    'READY',
    '{"name":"alpha","ship":{"status":"READY"}}'
);

注意事項:

  • JSONメタデータ列には長さを指定しません。
  • 無効なJSON文字列はエラーになります。
  • 生のJSON列自体にはインデックスが自動作成されません。

JSONの値が変わらない場合

SELECT name, _last_update_time FROM ch5_meta_json METADATA;
UPDATE ch5_meta_json METADATA
   SET info = JSON_REMOVE(info, '$.missing')
 WHERE name = 'SHIP_001';
SELECT name, _last_update_time FROM ch5_meta_json METADATA;

パスが存在せず保存値が変わらない場合、変更時刻も維持されます。

JSONパスの検索

JSONメタデータは->演算子で検索できます。

SELECT name,
       info->'$.name',
       info->'$.ship.status'
  FROM ch5_meta_json METADATA
 WHERE info->'$.ship.status' = 'READY'
 ORDER BY name;

データ検索でも同じ方法を使用できます。

SELECT name, time, value
  FROM ch5_meta_json
 WHERE info->'$.ship.status' = 'READY'
 ORDER BY name, time;

パスの表記規則

検索と部分更新のパスは完全なJSONPathを使用します。

  • 通常のキー: $.name
  • ネストしたキー: $.ship.status
  • キー名に.または-が含まれる場合は角括弧表記を使用
SELECT info->'$[''ship.owner'']'
  FROM ch5_meta_json METADATA;

SELECT info->'$[''ship-owner'']'
  FROM ch5_meta_json METADATA;

JSONパスインデックス

テーブル作成時に宣言

頻繁に検索するJSONパスは、メタデータ定義時にインデックスを作成できます。

CREATE TAG TABLE ch5_meta_json_indexed (
    name VARCHAR(20) PRIMARY KEY,
    time DATETIME BASETIME,
    value DOUBLE
)
METADATA (
    status VARCHAR(20),
    info JSON INDEX('name', 'ship.status')
);

INDEX(...)内の文字列は次の規則で解釈されます。

  • 'name'$.name
  • 'ship.status'$.ship.status
  • 特殊文字のあるキーや複雑なパスは完全なJSONPathを直接使用
INFO JSON INDEX('$[''ship.owner'']')

作成後にインデックスを追加

テーブル作成後もJSONパスインデックスを追加できます。

CREATE INDEX idx_ship_owner
ON ch5_meta_json METADATA (info->'$.owner');

インデックスの削除

インデックス名だけで削除します。

SHOW INDEX idx_ship_owner;
DROP INDEX idx_ship_owner;

明示的に作成したインデックスは、作成時に指定した名前で管理します。SHOW INDEX idx_ship_owner;は DROP前に実行します。削除後に同名を検索すると、存在しないオブジェクトになります。

インデックス使用時の注意事項

現在のJSONパスインデックスは、主に文字列比較で動作します。

SELECT name
  FROM ch5_meta_json METADATA
 WHERE info->'$.status' = 'READY';

文字列リテラルとの比較はインデックスを使用できます。一方、数値リテラルとの比較は フルスキャンになる場合があります。

例:

  • info->'$.num' = '10': インデックスを使用可能
  • info->'$.num' = 10: フルスキャンの可能性あり

JSONの部分更新

JSON関数は、指定パスを変更した新しいドキュメント値を返します。UPDATEはその結果を列に保存します。 これはパス単位の論理更新であり、保存ファイルの一部だけをその場で変更するという性能保証ではありません。

JSON_SET

SQLのスカラー値をJSONのスカラーとして保存します。

UPDATE ch5_meta_json METADATA
   SET info = JSON_SET(info, '$.ship.status', 'DONE')
 WHERE name = 'SHIP_001';

JSON_SET_JSON

入力文字列をJSONとして解釈し、オブジェクトまたは配列を保存します。

UPDATE ch5_meta_json METADATA
   SET info = JSON_SET_JSON(info, '$.owner', '{"name":"machbase","team":"db"}')
 WHERE name = 'SHIP_001';

JSON_REMOVE

指定したメンバーまたは下位パスを削除します。

UPDATE ch5_meta_json METADATA
   SET info = JSON_REMOVE(info, '$.owner.team')
 WHERE name = 'SHIP_001';

部分更新の規則

  • JSON_SET(..., path, NULL)はJSONのnullを保存します。
  • JSON_SET_JSON(..., path, NULL)の結果はSQLのNULLです。
  • JSONドキュメント引数がNULLの場合、関数の結果はSQLのNULLです。
  • パスがNULLまたは空文字列の場合はエラーになります。
  • 存在しないパスへのJSON_REMOVEはエラーではなくno-opです。
  • JSON_REMOVE(..., '$')は許可されません。
  • 部分更新は主にオブジェクトのパスをサポートします。
  • 配列要素のパス更新(例: $.items[0])はサポートしません。

全体例

CREATE TAG TABLE ch5_meta_complete (
    name VARCHAR(20) PRIMARY KEY,
    time DATETIME BASETIME,
    value DOUBLE
)
METADATA (
    status VARCHAR(20),
    srcip IPV4,
    info JSON INDEX('name', 'ship.status')
);

INSERT INTO ch5_meta_complete METADATA VALUES (
    'SHIP_001',
    'READY',
    '192.168.0.11',
    '{"name":"alpha","ship":{"status":"READY"}}'
);

INSERT INTO ch5_meta_complete VALUES ('SHIP_001', '2026-04-01 00:00:00', 10.5);

SELECT name, status, info
  FROM ch5_meta_complete METADATA;

SELECT name, time, value
  FROM ch5_meta_complete
 WHERE info->'$.ship.status' = 'READY';

CREATE INDEX idx_ship_owner
ON ch5_meta_complete METADATA (info->'$.owner');

UPDATE ch5_meta_complete METADATA
   SET info = JSON_SET(info, '$.ship.status', 'DONE')
 WHERE name = 'SHIP_001';

DROP INDEX idx_ship_owner;

まとめ

  • メタデータ専用検索はFROM TAG METADATA
  • データ検索はFROM TAG
  • メタデータの更新・削除はUPDATE/DELETE ... METADATA
  • ARRAYメタデータ列の変更はALTER TABLE ... METADATA ADD/DROP COLUMN
  • JSONメタデータはINFO JSON
  • _LAST_UPDATE_TIMEはメタデータ行の最終変更時刻で、明示的に検索可能
  • JSONパスインデックスはINFO JSON INDEX(...)またはCREATE INDEX ... ON TAG METADATA (...)
  • JSONの部分更新はJSON_SETJSON_SET_JSONJSON_REMOVE
  • _LAST_UPDATE_TIMEはサーバーが自動管理し、StandardとClusterで同じ動作

実習の後片付け

全削除の失敗例とは異なり、DROPはテーブルとDATA・METADATAをすべて削除します。 以下の名前が今回の実習で作成したオブジェクトであることを確認して実行します。

DROP TABLE ch5_meta;
DROP TABLE ch5_meta_json;
DROP TABLE ch5_meta_json_indexed;
DROP TABLE ch5_meta_complete;
最終更新日