
はじめに
現在のデータクラスが普及する前のデータベースは、グローバルに直接記述する方法が採用されていました。
そのグローバル構造をSQLで取得する必要が出てきたので、備忘を兼ねて2回に分けて記事にします。
手順
サンプルとなるグローバル
先ずは対象となるグローバルの構造を知る必要があります。
サンプルとして、下記ユーザ情報を作成しました。
ノード1 | ノード2 | データ項目 | 備考 | 区切り | |
---|---|---|---|---|---|
ユーザコード | 更新通番 | 漢字氏名 | |||
カナ氏名 | $c(2) | ||||
性別 | 1:男性,2:女性,3:不明 | $c(2) | |||
生年月日 | %Date型 | $c(2) | |||
更新日時 | YYYY-MM-DD hh:mm:ss | $c(1) | |||
初回登録日時 | YYYY-MM-DD hh:mm:ss | $c(2) | |||
登録者コード | $c(2) |

グローバルのノードとして、「ユーザコード」「更新通番」の2つを用意し、データ部として$c(1)で大きく2つに分割、前半の区切りをユーザ情報として$c(2)で区切り、後半の区切りを更新情報として$c(2)で区切りデータとします。
マッピングするデータクラスの作成
SQLを使用するのであれば、どうしてもデータクラスを作成する必要があります。
データクラスを作成し、データをマッピングします。
※コンパイルしていない状態で下記まで作成しています。
全ての項目をプロパティにする必要はありません。SQLで取得したい項目のみで十分です。
Class developer.data.UserData Extends %Persistent
{
Index priKey On (userCode, ver) [ IdKey ];
/// ユーザコード
Property userCode As %String;
/// 更新通番
Property ver As %Integer;
/// 漢字氏名
Property name As %String;
/// カナ氏名
Property kanaName As %String;
/// 性別
Property sex As %Integer;
/// 生年月日
Property birthDate As %Date;
/// 更新日時
Property updateDatetime As %TimeStamp;
/// 初回登録日時
Property firstRegDatetime As %TimeStamp;
/// 登録者コード
Property regUserCode As %String;
}
マッピング開始
マッピング作業は、スタジオのウィザードを使用する方が断然楽です。

[インスペクタ] > [Storage] > [新規ストレージ]で「新規ストレージウィザード」画面が起動します。

ストレージ名を入力し、SQLストレージにチェックをいれたら、完了ボタンをクリックします。

「…」ボタンをクリックしたら、マッピングのウィザードが表示されます。

追加ボタンをクリックする事で、設定画面に切り替わります。

マップ名は任意で設定して下さい。
グローバル名は、今回マッピング対象の「^Sample.Use」になります。

「PripmaryKey」に相当するマッピングを行います。

「②追加ボタン → ③プロパティを選択」を繰り返して、「{userCode}」「{ver}」を設定します。
次は、データ部のマッピングを行います。

データ部の設定も、サブスクリプトと同様に、「②追加ボタン → ③プロパティを選択」を繰り返します。
「{name}」「{kanaName}」「{sex}」「{birthDate}」「{updateDatetime}」「{firstRegDatetime}」「{regUserCode}」を設定する。

設定が完了したら左の「データ」ツリーから、各項目をクリックして詳細な設定を行います。

「name」は、$c(1)で区切られた1番目の中の、$c(2)で区切られた1番目であるため、「デリミタ=$c(1),$c(2)」「Piece=1,1」と入力します。
全プロパティに対し設定を行い、問題がなければ「OK」ボタンをクリックします。

では、管理ポータルよりSQLを実行してみましょう!

旧グローバル構成がSQLで取得できました。
インデックスグローバルを追加する
検索を有利にするため、インデックスの存在は必須です。
データクラスにもインデックスが追加できるので、SQLマッピングもインデックスを追加する事は可能です。
では、漢字氏名を検索するインデックスを作って、マッピングしてみましょう。

再度ウィザードを起動させます。

新規マッピングを作成したいため、ルートをクリックして「追加」ボタンをクリックします。

マップ名は任意で命名して下さい。
マップタイプは今回「index」に設定し、グローバル名を「^Sample.Use.Idx」とします。
ノードを設定するため「サブスクリプト」を選択肢し、「”name”」「{name}」「{userCode}」「{var}」を設定します。
※インデックスの第1ノードは、固定値の「”name”」になります。

「OK」をクリックしたら、データクラスをコンパイルします。
さて、コンパイルが終わったら、インデックスを使用しているか、クエリプランを確認してみましょう。

作成したインデックスを使用している事が確認できました。
成功です!
データクラスの状態確認
設定が全て完了したデータクラスの状態になります。
ストレージ情報に設定した内容が反映されているのが分かります。
Class developer.data.UserData Extends %Persistent [ StorageStrategy = UserData ]
{
Index priKey On (userCode, ver) [ IdKey ];
/// ユーザコード
Property userCode As %String;
/// 更新通番
Property ver As %Integer;
/// 漢字氏名
Property name As %String;
/// カナ氏名
Property kanaName As %String;
/// 性別
Property sex As %Integer;
/// 生年月日
Property birthDate As %Date;
/// 更新日時
Property updateDatetime As %TimeStamp;
/// 初回登録日時
Property firstRegDatetime As %TimeStamp;
/// 登録者コード
Property regUserCode As %String;
Storage UserData
{
<SQLMap name="Map1">
<ConditionalWithHostVars></ConditionalWithHostVars>
<Data name="birthDate">
<Delimiter>$c(1),$c(2)</Delimiter>
<Piece>1,4</Piece>
</Data>
<Data name="firstRegDatetime">
<Delimiter>$c(1),$c(2)</Delimiter>
<Piece>2,2</Piece>
</Data>
<Data name="kanaName">
<Delimiter>$c(1),$c(2)</Delimiter>
<Piece>1,2</Piece>
</Data>
<Data name="name">
<Delimiter>$c(1),$c(2)</Delimiter>
<Piece>1,1</Piece>
</Data>
<Data name="regUserCode">
<Delimiter>$c(1),$c(2)</Delimiter>
<Piece>2,3</Piece>
</Data>
<Data name="sex">
<Delimiter>$c(1),$c(2)</Delimiter>
<Piece>1,3</Piece>
</Data>
<Data name="updateDatetime">
<Delimiter>$c(1),$c(2)</Delimiter>
<Piece>2,1</Piece>
</Data>
<Global>^Sample.Use</Global>
<Subscript name="1">
<Expression>{userCode}</Expression>
</Subscript>
<Subscript name="2">
<Expression>{ver}</Expression>
</Subscript>
<Type>data</Type>
</SQLMap>
<SQLMap name="nameIdx">
<ConditionalWithHostVars></ConditionalWithHostVars>
<Global>^Sample.Use.Idx</Global>
<Subscript name="1">
<Expression>"name"</Expression>
</Subscript>
<Subscript name="2">
<Expression>{name}</Expression>
</Subscript>
<Subscript name="3">
<Expression>{userCode}</Expression>
</Subscript>
<Subscript name="4">
<Expression>{ver}</Expression>
</Subscript>
<Type>index</Type>
</SQLMap>
<StreamLocation>^developer.data.UserDataS</StreamLocation>
<Type>%Storage.SQL</Type>
}
}
インスタンス化からのデータ登録が可能か確認する
このSQLマッピングのクラスで、インスタンス化からのデータ登録ができるか確認したいと思います。
「developer.data.UserData.cls」をインスタンス化して、%Save()を実施する流れです。
s obj=##class(developer.data.UserData).%New()
s obj.userCode="002"
s obj.ver=1
s obj.name="テスト 太郎"
s obj.kanaName="テスト タロウ"
s obj.sex=1
s obj.birthDate=$zdh("2000-07-12",3)
s obj.updateDatetime="2024-04-29 09:44:00"
s obj.firstRegDatetime="2024-04-28 12:15:32"
s obj.regUserCode="012"
w obj.%Save()
%Save()の戻り値が「1」なので、登録が正常に成功しました。
では、登録したデータを管理ポータルで確認してみましょう。

設定したデリミタに沿ってデータが作成されているのが確認できます。

インデックスグローバルも作成されています。

SQLでも正常に取得できる事が確認できました。
以上より、既存ロジックでの登録以外に、インスタンス化からのデータ登録という選択肢が増えたことが分かります。
おわりに
いかがだったでしょうか。
データクラスの「IdKey」も、グローバルマッピングもそこまでの差がありません。
その為、こんな芸当も可能なんでしょうね。
昔の構成までフォロー可能なシステムは、本当に素敵だと思います。
昔のシステムも、まだまだ活かせますよね!
次回は、色々なグローバルのマッピングをご紹介したいと思います。