web-dev-qa-db-ja.com

2つのExcelテーブルを1つの追加データに結合しますか?

以下のように、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
-----------------------------------

マクロを使わずにできますか?

10
anuj

この回答は、Excelで解釈される 構造化テーブル を扱います。メソッドは、割り当てられたテーブル構造なしで生データマトリックスに簡単に転記できますが、このソリューションの数式とVBAコーディングは、真の構造化テーブルを対象としています。

前文

3番目のテーブルは、2つのテーブルといくつかのネイティブワークシートの数式を組み合わせたデータを維持できますが、依存テーブルに対して行が追加または削除されるときに3番目のテーブルのサイズを正しく維持するには、手動のサイズ変更操作またはこれらの変更を追跡して準拠するVBAが必要です適合する3番目のテーブル。この回答の最後に、ソーステーブルのワークシート名とテーブルメンテナンスVBAコードの両方を追加するオプションを含めました。

説明のない操作例のワークブックだけが必要な場合は、この回答の最後までスキップして、この手順の作成に使用したワークブックへのリンクを探してください。

サンプルデータテーブル

Table Collection Sample Data

OPのサンプルデータを使用して、ワークシートSheet1およびSheet2にそれぞれ(デフォルトで)Table1およびTable2という名前の2つのテーブルを作成しました。親ワークシート上の位置に関係なく、構造化テーブルがそれ自体または別のエンティティとして数式内の別の構造化テーブルに対処する構造化テーブルの機能を示すために、意図的にそれらを各ワークシートのA1セルからさまざまな程度にオフセットしました。 3番目のテーブルも同様の方法で作成されます。これらのオフセットはデモンストレーションのみを目的としています。それらは必要ありません。

ステップ1:3番目のテーブルを作成する

3番目のテーブルのヘッダーを作成し、その将来のヘッダー行とその下の少なくとも1つの行を選択して、[挿入]►[テーブル]►[テーブル]コマンドのベースにします。

Combining Tables New Table

Sheet3ワークシートの新しい空の3番目のテーブルは、次のようになります。

Collecting Table Data Build New Table

ステップ2: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 functionCOLUMN(A:A)として使用されます。これは、ワークシートのどこにあるかに関係なく、参照されるテーブルの最初の列を取得します。数式が正しく入力されると、2番目、3番目などの列に進みます。

右詰めといえば、右の式をE6まで書きます。次のようなものが必要です。

Aggregating table data, third table

ステップ2.5:[オプション]ソーステーブルの親ワークシート名を追加する

右下隅にあるTable3のサイズ変更ハンドル(下のサンプル画像ではオレンジ色の矢印で示されています)をつかみ、1列右にドラッグして、新しい列をテーブルに追加します。ヘッダーラベルの名前をデフォルトよりも適切なものに変更します。 Sheetを列ラベルとして使用しました。

Collating table data - source worksheet name

ソーステーブルのワークシート名を直接取得することはできませんが、 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の全母集団をスキップして、次のステップに進みます。

ステップ3:VBAを追加して3番目のテーブルを維持する

ワークシートのデータの変更によってトリガーされるプロセスの完全な自動化は、ワークシートの Worksheet_Change イベントマクロで処理するのが最適です。 3つのテーブルが関係しているため、それぞれが独自のワークシートにあるため、 Workbook_SheetChangeイベントマクロ は、複数のワークシートからの変更イベントを処理するための優れた方法です。

でVBEを開く Alt+F11。開いたら、左上にあるProject Explorerを探します。表示されていない場合は、 Ctrl+R それを開きます。 ThisWorkbookを見つけて右クリックし、[コードの表示]を選択します(または、ThisWorkbookをダブルクリックします)。

Collect data from multiple tables

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プロパティ を広範囲に使用します。ワークシートのCodeNameSheet1、Sheet2、Sheet3などであり、ワークシートの名前が変更されても変更されません。実際、これらは、より上級のユーザーによっても変更されることはめったにありません。これらは、コードを変更せずにワークシートの名前を変更できるように使用されています。ただし、これらは正しいワークシートを指しているはずです。テーブルとワークシートが指定されたものと異なる場合は、コードを変更してください。 VBEのプロジェクトエクスプローラーを示す上記の画像では、個々のワークシートのコード名をワークシートの横にあるかっこ内に表示されます 。Nameプロパティ

をタップ Alt+Q ワークシートに戻ります。あとは、Table1またはTable2のセルを選択し、タップして変更するふりをしてTableの入力を終了するだけです。 F2 その後 Enter↵。結果は次のようになります。

Combine two tables into one automatically

ここまで進んでいる場合は、2つのソース「子」テーブルからのデータをアクティブに組み合わせる、かなり包括的なコレクションテーブルが必要です。 VBAも追加した場合、3番目のコレクションテーブルのメンテナンスは事実上存在しません。

テーブルの名前を変更する

3つのテーブルのいずれかまたはすべての名前を変更することを選択した場合、ワークシートの数式は即座に自動的に変更を反映します。 Workbook_SheetChangeと付随するヘルパーサブプロシージャを含めることを選択した場合は、ThisWorkbookコードシートに戻り、検索と置換を使用して適切な変更を行う必要があります。

サンプルワークブック

完全に機能するサンプルワークブックをパブリックDropBoxから入手できるようにしました。

Table_Collection_w_Sheetname.xlsb


¹ CELL関数 は、保存されたワークブックのワークシート名のみを取得できます。ワークブックが保存されていない場合、ファイル名はありません。ファイル名を要求すると、CELL関数は空の文字列を返します。

9
user4039065

Officeクリップボード(リボンの[ホーム]タブのクリップボードセクションの右下にある矢印)をアクティブ化できます。両方の範囲をコピーして、次に示すようにPaste Allコマンドを使用します。

それでも、フィルハンドルをダブルクリックして行うことができますが、最初に追加の列にシート名を入力する必要があります。

enter image description here

更新

数式で同じ結果を得るには、シート名にこれを入力してみてください。

=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),""))
4
lori_m

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)))

これが私のブログでどのように機能するかの詳細な説明 があり、ここに含めるには長すぎます。

2
James Bayley

Jeepedのコードに若干の変更。

同様のアプローチを使用しているが、いくつかのテーブル(例:10を超える)を使用している場合、すべてのテーブルのすべての名前を手動で追加しようとすると、かなり面倒になります。名前はVBAに固定されているため、テーブルの名前を変更した場合にも問題になります。追加の作業を回避するには、次のことを考慮してください。

したがって、以下を想定します。

  • 各ワークシートには1つまたは複数のテーブルがありますが、それらは同様の構造を持っています。
  • ワークシートにはテーブルしかありません-ListObjectsコレクションの他のメンバーは存在していません。
  • シートのテーブルを編集するたびに、マスターテーブルの更新がトリガーされます(テーブル3)。

上記の例の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プロシージャ。

1
Infinito

私はこのコード/式を使用しています。 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)))))

私も使用しています

0
DJRCB