テーブルから別テーブルへの転記 ③ 配列と連想配列の組合せ ~その4.空白列を無視~
前回はテーブル間の転記について、転記先にキー情報がない場合は、
キーを追加したうえで情報を転記することに挑戦した。
infoment.hatenablog.com
前回までは、転記元が空白であって転記先に何らかの値が入っている場合、
無条件で空白を上書きしていた。
ということで今回は、それを選択できるよう改修してみよう。
例えば、↓ このような場合。
転記元:テーブルDのA001,A003,A005は、日付が空欄になっている。一方で、
転記先:テーブルAのA001,A003,A005は、日付が空欄ではない。
このようなとき、少なくとも
- 何某か日付が決まっていたものが、白紙に戻った。
- 一旦決まった日付は、テーブルD作成時に省略された。
の二パターンがあると思う。
そこで、テーブル間の転記用プロシージャに、空白無視を選択する引数を追加
することにした。
Optional ignore_blank As Boolean = False
- True : 空白の場合は転記しない
- False : 空白であっても転記する
基本的には、空白であっても無条件で転記することにしよう。
転記するかしないかは、ignore_blankの二択と、転記元が空欄か否かの二択の
掛け算になるから、4パターンが存在する。
これを踏まえて、転記する条件を一つ追加したのがこちら。
' テーブル間のデータ受け渡し。 ' 各テーブルの指定列をkeyに、別の指定列をitemとして授受する。 ' ※転記先テーブルにあって転記元テーブルに無いレコードは保持される。 Function Transcription_Tb2Tb(src_tb As ListObject, dst_tb As ListObject, _ src_key As Variant, src_item As Variant, _ Optional dst_key As Variant, _ Optional dst_item As Variant, _ Optional ignore_blank As Boolean = False) As Excel.ListObject ' ignore_blankは、空白の反映に関する設定。 ' Trueの場合、転記元のitemが空白であれば転記しない。 Dim DstKey As Variant DstKey = dst_key: If IsError(DstKey) Then DstKey = src_key Dim DstItem As Variant DstItem = dst_item: If IsError(DstItem) Then DstItem = src_item ' 転記元テーブルで連想配列を作成できなかった場合の処理。 Dim SrcDict As Object Set SrcDict = CreateDict(src_tb, src_key, src_item) If SrcDict Is Nothing Then Debug.Print "転記元テーブルで連想配列を作成できませんでした。" Exit Function End If ' テーブルにkeyまはたitemとなる列が存在しない場合のためのエラートラップ。 On Error GoTo er: Dim DstKeyArray As Variant DstKeyArray = dst_tb.ListColumns(DstKey).DataBodyRange Dim DstItemArray As Variant DstItemArray = dst_tb.ListColumns(DstItem).DataBodyRange On Error GoTo 0 Dim tempKey As Variant Dim i As Long For i = 1 To dst_tb.ListRows.Count tempKey = DstKeyArray(i, 1) If tempKey <> vbNullString Then If SrcDict.Exists(tempKey) Then ' 「空白無視の引数がTrue」で、且つ「実際に空白」の場合のみ転記しない。 ' 従ってその逆「空白無視しない または 空白以外」の場合に転記する。 If Not ignore_blank Or SrcDict(tempKey) <> vbNullString Then DstItemArray(i, 1) = SrcDict(tempKey) End If End If End If Next dst_tb.ListColumns(DstItem).DataBodyRange = DstItemArray Set Transcription_Tb2Tb = dst_tb er: Debug.Print "keyまたはitem列が、指定テーブルに存在しません。" End Function
全転記のプロシージャにも追加しよう。
' テーブル間のデータ受け渡し。 ' 転記元テーブルの指定列をkeyに、転記先テーブルにある全項目について転記する。 ' ※転記先テーブルにあって転記元テーブルに無いレコードは保持される。 Function Transcription_Tb2Tb_All(src_tb As ListObject, _ dst_tb As ListObject, _ src_key As Variant, _ Optional dst_key As Variant, _ Optional add_new_record As Boolean = False, _ Optional ignore_blank As Boolean = False) As Excel.ListObject ' 転記元にあって転記先にないkey情報の転記(選択可)。 Dim SrcKeyArray As Variant Dim DstKeyArray As Variant Dim DifferenceSet As Variant ' 集合クラス Dim MS As VBAProject.MathSet Set MS = New VBAProject.MathSet If add_new_record Then On Error GoTo er: ' 転記元のkey情報を格納した配列。 SrcKeyArray = src_tb.ListColumns(src_key).DataBodyRange ' 転記先のkey情報を格納した配列。 If dst_tb.ListRows.Count = 0 Then DstKeyArray = Array() Else DstKeyArray = dst_tb.ListColumns(src_key).DataBodyRange End If On Error GoTo 0 ' 「転記元」-「転記先」。 ' ※数学の「集合」は、英語で「Set」(見た目ややこしい)。 ' ※差分が存在しない、つまり新たなレコードが無い場合、空配列を返す。 DifferenceSet = MS.GetDifferenceSet(DstKeyArray, SrcKeyArray, False) ' 空配列のUboundは「-1」であることを利用して、処理を場合分け。 If UBound(DifferenceSet) <> -1 Then ' 転記先テーブルに一行追加したうえで、差分情報を貼り付け。 ' ※テーブル範囲は、貼り付けレコードのサイズに合わせて ' 自動的に拡張される。 With dst_tb.ListRows.Add .Range(dst_tb.ListColumns(src_key).index). _ Resize(UBound(DifferenceSet) + 1) = _ WorksheetFunction.Transpose(DifferenceSet) End With End If End If Dim ItemLabel As Variant Dim SrcItem As Variant ' 転記先の、keyラベルを除く全ての列名で転記をループ。 For Each ItemLabel In src_tb.HeaderRowRange SrcItem = ItemLabel.Value If SrcItem <> src_key Then Transcription_Tb2Tb src_tb:=src_tb, _ dst_tb:=dst_tb, _ src_key:=src_key, _ src_item:=SrcItem, _ dst_key:=dst_key, _ ignore_blank:=ignore_blank End If Next ' 転記先のテーブルを戻り値としてセット。 Set Transcription_Tb2Tb_All = dst_tb er: Debug.Print "keyまたはitem列が、指定テーブルに存在しません。" End Function
それでは、冒頭の例で確認してみよう。
↓ この場合、アイテムが空白の場合は転記しない。
Sub test5() Transcription_Tb2Tb_All src_tb:=ActiveSheet.ListObjects("テーブルD"), _ dst_tb:=ActiveSheet.ListObjects("テーブルA"), _ src_key:="コード", _ add_new_record:=True, _ ignore_blank:=True End Sub
結果がこちら。
意図したとおり、オレンジ色のセルは空白情報が上書きされなかった。
※A007の日付がオレンジ色になったのは、テーブルの行を追加した際、
一つ上の塗りつぶし情報をコピーしてしまったため。
だいぶん良い感じになってきたが、実用化のためにもう少し味付けが必要か。
ということで次回も、今回の結果をさらに機能拡張して紹介します。
参考まで。