【IRIS/Cache】テーブルのレコードからCSVファイルを作成する

テーブルのレコードから、CSVファイルを生成する方法をご紹介します。

※この記事は下記の方向けになります。
  • テーブルのレコードからCSVファイルを生成したい
  • テーブル毎に固有のクラスを作りたくない

はじめに

テーブルのレコードから、CSVファイルを作成する方法をご紹介します。

今回の方法は、「SQL.Export.Mgr.cls」を利用して、CSVを出力します。
全件出力するので、出力条件を定義する事が出来ませんが、レコードを簡易に出力できるので利便性は高いです。

また、テーブル毎の出力関数を作成する必要がないのもメリットです。

CSVファイルの取り込みに関しては、下記記事を参照してください。

CSVファイルをエクスポートする

前述した通り、CSVファイルを出力するには「SQL.Export.Mgr.cls」を使用します。

サンプルは下記になります。
関数の解説は後程行います。

ClassMethod export(fileName As %String, clsNm As %String, rowName As %String, rowType As %String = "", dlm As %String = ",", charSet As %String = "UTF8")
{
	s (makeRflg,openFlg, total,rows) = 0
	try {
		s mgr = ##class(%SQL.Export.Mgr).%New()
		
		s sNm = $tr($ClassMethod(clsNm, "%PackageName"),".","_")
		, tNm = $ClassMethod(clsNm, "%ClassName")
		
		s mobj = ##class(%SQL.Manager.API).%New()
		$$$ThrowOnError(mobj.CheckIdentifier(.sNm))
		$$$ThrowOnError(mobj.CheckIdentifier(.tNm))
		
		s mgr.FileName = fileName
		s mgr.TableName = sNm_"."_tNm
		s mgr.IQN = $$$BuildIQN(sNm,tNm)
		
    // CSVファイルの設定
		s mgr.Delimiter = dlm
		//s mgr.StringQuote = ""
		s mgr.Charset = charSet
		s mgr.HasHeaders = 1 // 1:ヘッダを出力
		
		// 日時フォーマット
		s mgr.DateFormat = 3
		s mgr.TimeFormat = 1
		
		
		// CSVカラムと型を設定
		f pos=1:1:$l(rowName,",") d mgr.ColumnNames.Insert($p(rowName,",",pos))
		i (rowType'="") f pos=1:1:$l(rowType,",") d mgr.ColumnTypes.Insert($p(rowType,",",pos))


		$$$ThrowOnError(mgr.GenerateExportRoutine()) s makeRflg = 1
		$$$ThrowOnError(mgr.OpenExport()) s openFlg = 1
		
		d {
			$$$ThrowOnError( mgr.ExportRows(.rows, .done))
			s total = total + rows
		} while('done)
				
		$$$ThrowOnError( mgr.CloseExport() ) s openFlg = 0
		$$$ThrowOnError( mgr.DeleteExportRoutine() )
	}catch e {
		w !,$System.Status.DisplayError(e.AsStatus())
		
		d:(openFlg) mgr.CloseExport() // ファイルを閉じる
		d:(makeRflg) mgr.DeleteExportRoutine() // ルーチン削除
	}
	
	w !!,$$$FormatText("総数:%1 at %2", total, $zdt($h,3,1))
}

【コマンド実行】
s fileName = “D:\Temp\csv\読み込み\patient_data_sample_export.csv”
s clsNm = “developer.csv.Patient”
s rowName = “xActive,zUpdateCount,dele,storeCd,patientId,漢字氏名,カナ氏名,ローマ字氏名,漢字旧姓,カナ旧姓,性別,生年月日,死亡日時,コメント,新患登録日,ABO血液型,RH血液型,未使用区分”
s rowType = “N,N,N,S,S,S,S,S,S,S,S,D,TS,S,D,S,S,N”

d ##class(developer.csv.Sample).export(fileName,clsNm,rowName,rowType)

解説

関数の引数を解説

引数名説明
fileNameCSVファイルの出力先(ファイル名含む)
clsNm出力対象テーブルの名称
rowNameCSVファイルの列名を指定する
 ※データクラスのプロパティ名と一致させる必要があり
rowTypeCSVファイルの列の型を指定する
 ・D – Date
 ・TS – TimeStamp // あまり役に立っていない「S」でもいい
 ・N – Numeric
 ・S – String
 ・STREAM – Stream
 ・T – Time
dlmデリミタ(初期値=”,”)
charSetファイルの文字コード(初期値=”UTF8″)
関数の引数を説明

出力するプロパティが全てString型であれば、rowTypeの指定は不要です。

もし、プロパティの型に「%Date」や「%Time」等を出力する場合は、型指定を行わないと$horolog型のまま出力します。

出力処理の解説

先ずは、クラス「%SQL.Export.Mgr.cls」をインスタンス化する事から始まります。

s mgr = ##class(%SQL.Export.Mgr).%New()

FileName」「TableName」「IQN」は必須の設定になります。

s mgr.FileName = fileName // 出力先のファイル名とパス
s mgr.TableName = sNm_"."_tNm // SQLで使用するテーブル名称
s mgr.IQN = $$$BuildIQN(sNm,tNm) // 内部用

Delimiter」は、ファイルの区切り文字を指定します。
TSVファイル時は「$c(9)」を設定します。

出力値を特定の文字で括りたい場合は、「StringQuote」を指定します。
ただし、全ての値が括られるわけではありません。
String型、Stream型であり、区切り文字・括り文字が含まれる, 値の前後に半角スペースが含まれている等々の条件が必要になります。

ファイルの文字コードを「Charset」に指定します。

ヘッダを出力する場合は「HasHeaders」に「1」を指定します。

s mgr.Delimiter = dlm
s mgr.StringQuote = """"
s mgr.Charset = charSet
s mgr.HasHeaders = 1 // 1:ヘッダを出力

DateFormat」「TimeFormat」も、各$zDate(val, format), $zTime(val, format)のformat部を指定します。

s mgr.DateFormat = 3
s mgr.TimeFormat = 1

カラム(列)の名称と型を設定します。
プロパティ名とカラム名は完全一致である必要があります。

f pos=1:1:$l(rowName,",") d mgr.ColumnNames.Insert($p(rowName,",",pos))
i (rowType'="") f pos=1:1:$l(rowType,",") d mgr.ColumnTypes.Insert($p(rowType,",",pos))

出力部分のメイン処理になります。

d {
	$$$ThrowOnError( mgr.ExportRows(.rows, .done))
	s total = total + rows
} while('done)

引数「rows」を足していくと、読み込んだ総レコード数となります。
引数「done=1」で、最終行の読み込み完了となります。

出力部のミソ

下記は「%SQL.Export.Mgr.mac」で、レコードを取得する処理(SQL文)を生成する処理になります。

 Set text=" &SQL(DECLARE Z CURSOR FOR SELECT"

 ; SELECT list
 Set colno=1
 For i=1:1:cols Do
 . Set name=..ColumnNames.GetAt(i),type=..ColumnTypes.GetAt(i)
 . Set:name'="" text=text_$S(colno=1:" ",1:", ")_$s(type'="STREAM":name,1:"%OBJECT("_name_")"),colno=colno+1

 Set text=text_" INTO"

 ; INTO list
 Set colno=1
 For i=1:1:cols Do
 . Set name=..ColumnNames.GetAt(i)
 . Set:name'="" text=text_$S(colno=1:" ",1:", ")_"%d("_colno_")",colno=colno+1

 Set text=text_" FROM "_..TableName_")"

 Do rtn.WriteLine(text)

「%SQL.Export.Mgr」を利用してのCSVファイル出力は、下記のような特性があります。

%SQL.Export.Mgr.clsの特性
  • 「ColumnNames」に設定するカラム名は、プロパティ名でなければならない
  • 全件が出力対象である

また、生成されたルーチンを確認してみます。

 Write %d(1),",",%d(2),",",%d(3),",",$$QUOTE(%d(4)),",",$$QUOTE(%d(5)),",",$$QUOTE(%d(6)),",",$$QUOTE(%d(7)),",",$$QUOTE(%d(8)),",",$$QUOTE(%d(9)),",",$$QUOTE(%d(10)),",",$$QUOTE(%d(11)),",",$S(%d(12)="":"",1:$ZDT(%d(12),3)),",",%d(13),",",$$QUOTE(%d(14)),",",$S(%d(15)="":"",1:$ZDT(%d(15),3)),",",$$QUOTE(%d(16)),",",$$QUOTE(%d(17)),",",%d(18),!

QUOTE(s) { If s'["",s'[",",$l($zstrip(s,"<>W"))=$l(s),s'[$c(10) Quit s
 For i=$l(s,""):-1:2 Set $piece(s,"",i)=""_$piece(s,"",i)
 Quit ""_s_"" }
  • Date, Timeはフォーマット指定通りに出力される
  • TimeStampは、Stringと同じ扱いとなっている
  • 全ての項目で、「”」等で括って出力することが不可能である
  • Stringでも、特定の条件でなければ「”」で括ることはない

おわりに

今回はCSVファイルの出力をご紹介致しました。

「%SQL.Export.Mgr」を利用すれば、「出力PGを別途作成する必要がない」為、非常に使い勝手の良い方法だと思います。

ただし、対象レコードを絞り込む事が出来ない、%DateTimeや特殊な型に対応出来ない等、全ての値にたいし特定文字で括れない等、若干機能制限があります。

それでも、ターミナル等で設定すれば簡単にCSVファイルが出力できるので、活用するタイミングはあると思います。