【IRIS/Cache】【SQL】クラスで構築していないグローバルに対しSQLを実行する(基本編)

はじめに

現在のデータクラスが普及する前のデータベースは、グローバルに直接記述する方法が採用されていました。

そのグローバル構造を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)
^Sample.Use

グローバルのノードとして、「ユーザコード」「更新通番」の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マッピングもインデックスを追加する事は可能です。

では、漢字氏名を検索するインデックスを作って、マッピングしてみましょう。

インデックス用としてマッピング出来るグローバルは、必ず「IdKey」で使用したプロパティが含まれている必要があります。

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

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

マップ名は任意で命名して下さい。
マップタイプは今回「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」も、グローバルマッピングもそこまでの差がありません。
その為、こんな芸当も可能なんでしょうね。

昔の構成までフォロー可能なシステムは、本当に素敵だと思います。
昔のシステムも、まだまだ活かせますよね!

次回は、色々なグローバルのマッピングをご紹介したいと思います。