以下のように、MS Excel 2007ワークブックの2つの別々のシートに2つのテーブルがあります。
===========================
no. f_name l_name
===========================
13 Little Timmy
1 John Doe
17 Baby Jessica
---------------------------
===========================
no. f_name l_name
===========================
1 john Tim
16 kyle joe
14 Baby katy
22 qbcd wsde
---------------------------
どちらにも同じ列がありますが、データが異なる場合があります。
両方のテーブルのデータを垂直に結合します。つまり、1つのテーブルとすべてのデータを3番目のシートにまとめます。可能であれば、行の元のシート名を含む別の列を追加します。
===================================
SheetName no. f_name l_name
===================================
Sheet1 13 Little Timmy
Sheet1 1 John Doe
Sheet1 17 Baby Jessica
Sheet2 1 john Tim
Sheet2 16 kyle joe
Sheet2 14 Baby katy
Sheet2 22 qbcd wsde
-----------------------------------
マクロを使わずにできますか?
この回答は、Excelで解釈される 構造化テーブル を扱います。メソッドは、割り当てられたテーブル構造なしで生データマトリックスに簡単に転記できますが、このソリューションの数式とVBAコーディングは、真の構造化テーブルを対象としています。
3番目のテーブルは、2つのテーブルといくつかのネイティブワークシートの数式を組み合わせたデータを維持できますが、依存テーブルに対して行が追加または削除されるときに3番目のテーブルのサイズを正しく維持するには、手動のサイズ変更操作またはこれらの変更を追跡して準拠するVBAが必要です適合する3番目のテーブル。この回答の最後に、ソーステーブルのワークシート名とテーブルメンテナンスVBAコードの両方を追加するオプションを含めました。
説明のない操作例のワークブックだけが必要な場合は、この回答の最後までスキップして、この手順の作成に使用したワークブックへのリンクを探してください。
OPのサンプルデータを使用して、ワークシートSheet1およびSheet2にそれぞれ(デフォルトで)Table1およびTable2という名前の2つのテーブルを作成しました。親ワークシート上の位置に関係なく、構造化テーブルがそれ自体または別のエンティティとして数式内の別の構造化テーブルに対処する構造化テーブルの機能を示すために、意図的にそれらを各ワークシートのA1セルからさまざまな程度にオフセットしました。 3番目のテーブルも同様の方法で作成されます。これらのオフセットはデモンストレーションのみを目的としています。それらは必要ありません。
3番目のテーブルのヘッダーを作成し、その将来のヘッダー行とその下の少なくとも1つの行を選択して、[挿入]►[テーブル]►[テーブル]コマンドのベースにします。
Sheet3ワークシートの新しい空の3番目のテーブルは、次のようになります。
最初に、3番目のテーブルの最初のセルに DataBodyRange を入力します。この例では、それはSheet3!C6になります。次の式は、デフォルトのテーブル名に基づいていることに注意して、C6に入力するか貼り付けます。テーブル名を変更した場合は、適宜調整してください。
_=IFERROR(INDEX(Table1, ROW([@[no.]])-ROW(Table3[#Headers]),COLUMN(A:A)), INDEX(Table2, ROW([@[no.]])-ROW(Table3[#Headers])-ROWS(Table1),COLUMN(A:A)))
_
INDEX関数 は、最初にTable1から使用可能な各行を取得します。実際の行番号は、構造化されたテーブルの定義済みの部分を参照する ROW関数 を使用して、簡単な計算とともに導出されます。 Table1で行が不足すると、取得はTable2を参照する2番目のINDEX関数に渡され、 IFERROR関数 によって行が取得されます。その行はROWおよび ROWS functions もう少し数学を使用しています。 COLUMN function はCOLUMN(A:A)
として使用されます。これは、ワークシートのどこにあるかに関係なく、参照されるテーブルの最初の列を取得します。数式が正しく入力されると、2番目、3番目などの列に進みます。
右詰めといえば、右の式をE6まで書きます。次のようなものが必要です。
右下隅にあるTable3のサイズ変更ハンドル(下のサンプル画像ではオレンジ色の矢印で示されています)をつかみ、1列右にドラッグして、新しい列をテーブルに追加します。ヘッダーラベルの名前をデフォルトよりも適切なものに変更します。 Sheetを列ラベルとして使用しました。
ソーステーブルのワークシート名を直接取得することはできませんが、 CELL関数 は、保存されたワークブックの任意のセルの完全修飾パス、ファイル名、およびワークシートを、オプションinfo_types。
次の数式を、作成した新しい列の最初の行にあるTable3の空のセルに入力します。
_=TRIM(RIGHT(SUBSTITUTE(CELL("filename", IF((ROW([@[no.]])-ROW(Table3[#Headers]))>ROWS(Table1), Table2, Table1)), CHAR(93), REPT(CHAR(32), 999)), 255))
_
表3の作成を計算
2つのソーステーブルのいずれかから行が追加または削除されたときにTable3のディメンションを維持するためにVBAを使用してこの小さなプロジェクトを完了する予定がない場合は、Table3のサイズ変更ハンドルをつかんで、両方のテーブルからすべてのデータが蓄積されるまで下にドラッグします。 。予想される結果のサンプル画像については、この回答の下部を参照してください。
VBAの追加を計画している場合は、Table3の全母集団をスキップして、次のステップに進みます。
ワークシートのデータの変更によってトリガーされるプロセスの完全な自動化は、ワークシートの Worksheet_Change イベントマクロで処理するのが最適です。 3つのテーブルが関係しているため、それぞれが独自のワークシートにあるため、 Workbook_SheetChangeイベントマクロ は、複数のワークシートからの変更イベントを処理するための優れた方法です。
でVBEを開く Alt+F11。開いたら、左上にあるProject Explorerを探します。表示されていない場合は、 Ctrl+R それを開きます。 ThisWorkbookを見つけて右クリックし、[コードの表示]を選択します(または、ThisWorkbookをダブルクリックします)。
Book1-ThisWorkbook(Code)のようなタイトルの新しいペインに以下を貼り付けます。
_Option Explicit
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Select Case Sh.Name
Case Sheet1.Name
If Not Intersect(Target, Sheet1.ListObjects("Table1").Range.Offset(1, 0)) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
Call update_Table3
End If
Case Sheet2.Name
If Not Intersect(Target, Sheet2.ListObjects("Table2").Range.Offset(1, 0)) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
Call update_Table3
End If
End Select
bm_Safe_Exit:
Application.EnableEvents = True
End Sub
Private Sub update_Table3()
Dim iTBL3rws As Long, rng As Range, rngOLDBDY As Range
iTBL3rws = Sheet1.ListObjects("Table1").DataBodyRange.Rows.Count
iTBL3rws = iTBL3rws + Sheet2.ListObjects("Table2").DataBodyRange.Rows.Count
iTBL3rws = iTBL3rws + Sheet3.ListObjects("Table3").DataBodyRange.Cells(1, 1).Row - _
Sheet3.ListObjects("Table3").Range.Cells(1, 1).Row
With Sheet3.ListObjects("Table3")
Set rngOLDBDY = .DataBodyRange
.Resize .Range.Cells(1, 1).Resize(iTBL3rws, .DataBodyRange.Columns.Count)
If rngOLDBDY.Rows.Count > .DataBodyRange.Rows.Count Then
For Each rng In rngOLDBDY
If Intersect(rng, .DataBodyRange) Is Nothing Then
rng.Clear
End If
Next rng
End If
End With
End Sub
_
これらの2つのルーチンは、ワークシート 。CodeNameプロパティ を広範囲に使用します。ワークシートのCodeNameはSheet1、Sheet2、Sheet3などであり、ワークシートの名前が変更されても変更されません。実際、これらは、より上級のユーザーによっても変更されることはめったにありません。これらは、コードを変更せずにワークシートの名前を変更できるように使用されています。ただし、これらは正しいワークシートを指しているはずです。テーブルとワークシートが指定されたものと異なる場合は、コードを変更してください。 VBEのプロジェクトエクスプローラーを示す上記の画像では、個々のワークシートのコード名をワークシートの横にあるかっこ内に表示されます 。Nameプロパティ 。
をタップ Alt+Q ワークシートに戻ります。あとは、Table1またはTable2のセルを選択し、タップして変更するふりをしてTableの入力を終了するだけです。 F2 その後 Enter↵。結果は次のようになります。
ここまで進んでいる場合は、2つのソース「子」テーブルからのデータをアクティブに組み合わせる、かなり包括的なコレクションテーブルが必要です。 VBAも追加した場合、3番目のコレクションテーブルのメンテナンスは事実上存在しません。
3つのテーブルのいずれかまたはすべての名前を変更することを選択した場合、ワークシートの数式は即座に自動的に変更を反映します。 Workbook_SheetChangeと付随するヘルパーサブプロシージャを含めることを選択した場合は、ThisWorkbookコードシートに戻り、検索と置換を使用して適切な変更を行う必要があります。
サンプルワークブック
完全に機能するサンプルワークブックをパブリックDropBoxから入手できるようにしました。
Table_Collection_w_Sheetname.xlsb
¹ CELL関数 は、保存されたワークブックのワークシート名のみを取得できます。ワークブックが保存されていない場合、ファイル名はありません。ファイル名を要求すると、CELL関数は空の文字列を返します。
Officeクリップボード(リボンの[ホーム]タブのクリップボードセクションの右下にある矢印)をアクティブ化できます。両方の範囲をコピーして、次に示すようにPaste Allコマンドを使用します。
それでも、フィルハンドルをダブルクリックして行うことができますが、最初に追加の列にシート名を入力する必要があります。
更新
数式で同じ結果を得るには、シート名にこれを入力してみてください。
=IF(ROW()<=COUNTA(Sheet1!A:A),"Sheet1",IF(ROW()<COUNTA(Sheet1:Sheet2!A:A),"Sheet2",""))
次に、次の表の値の数式を入力します。
=IF(ROW()<=COUNTA(Sheet1!A:A),Sheet1!A2,IF(ROW()<COUNTA(Sheet1:Sheet2!A:A),INDEX(Sheet2!A:A,ROW()-COUNTA(Sheet1!A:A)+1),""))
lori_mは、Microsoft Excelのテーブルと構造化参照を使用して構築した非常に優れた貢献をしました。
まず、テーブル内の行番号を含むRowIDという出力テーブルの列を作成し、これを使用してデータ値を入力します。
=IF( INDIRECT("Table3[RowId]")<=ROWS(Table1)
,INDEX(Table1[column1],INDIRECT("Table3[RowId]"))
,INDEX(Table2[Column1],INDIRECT("Table3[RowId]")-ROWS(Table1)))
これが私のブログでどのように機能するかの詳細な説明 があり、ここに含めるには長すぎます。
Jeepedのコードに若干の変更。
同様のアプローチを使用しているが、いくつかのテーブル(例:10を超える)を使用している場合、すべてのテーブルのすべての名前を手動で追加しようとすると、かなり面倒になります。名前はVBAに固定されているため、テーブルの名前を変更した場合にも問題になります。追加の作業を回避するには、次のことを考慮してください。
したがって、以下を想定します。
上記の例のWorkbook_SheetChange Subは次のようになります。
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim tbl As ListObject
For Each tbl In ActiveSheet.ListObjects
If Not Intersect(Target, tbl.Range.Offset(1, 0)) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
Call update_Table
End If
Next tbl
bm_Safe_Exit:
Application.EnableEvents = True
End Sub
編集。 2番目のルーチンは、次のようになります。
Private Sub update_Table()
Dim iTBL3rws As Long, rng As Range, rngOLDBDY As Range
Dim tbl As ListObject
Dim sht As Worksheet
iTBL3rws = 0
' consider all tables, excluding master table
For Each sht In ThisWorkbook.Worksheets
For Each tbl In sht.ListObjects
If tbl.Name <> "Table3" Then
iTBL3rws = iTBL3rws + tbl.DataBodyRange.Rows.Count
End If
Next tbl
Next sht
iTBL3rws = iTBL3rws + Sheet3.ListObjects("Table3").DataBodyRange.Cells(1, 1).Row - Sheet3.ListObjects("Table3").Range.Cells(1, 1).Row
With Sheet3.ListObjects("Table3")
Set rngOLDBDY = .DataBodyRange
.Resize .Range.Cells(1, 1).Resize(iTBL3rws, .DataBodyRange.Columns.Count)
If rngOLDBDY.Rows.Count > .DataBodyRange.Rows.Count Then
For Each rng In rngOLDBDY
If Intersect(rng, .DataBodyRange) Is Nothing Then
rng.Clear
End If
Next rng
End If
End With
End Sub
このルーチンは、事前にプログラムされたケースを排除することにより、以前のルーチンとは異なります。アクティブなワークシートに変更が登録されている場合、変更しようとしているこのワークシートのテーブルがトリガーされますpdate_Tableプロシージャ。
私はこのコード/式を使用しています。 3つ以上のテーブルを参照として使用できるように、より良いセル式を作成する方法を知りたいだけです。現在、iferror内にiferrorステートメントの多くをネストしています
=IFERROR(INDEX(Table1, ROW([@Date])-ROW(Table3[#Headers]),COLUMN(A:A)),IFERROR( INDEX(Table2, ROW([@Date])-ROW(Table3[#Headers])-ROWS(Table1),COLUMN(A:A)), IFERROR(INDEX(Table4, ROW([@Date])-ROW(Table3[#Headers])-ROWS(Table2)-ROWS(Table1),COLUMN(A:A)),INDEX(Table5, ROW([@Date])-ROW(Table3[#Headers])-ROWS(Table2)-ROWS(Table1)-ROWS(Table4),COLUMN(A:A)))))
私も使用しています