Объединить 2 таблицы Excel в одну, добавляя данные? - PullRequest
9 голосов
/ 29 марта 2012

У меня есть 2 таблицы на 2 отдельных листах книги MS Excel 2007, как показано ниже:

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

Обе имеют одинаковые столбцы, но могут иметь разные данные.

Iхотите объединить данные обеих таблиц по вертикали, т.е. одну таблицу со всеми данными на 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
-----------------------------------

Можно ли это сделать без использования макросов?

Ответы [ 5 ]

8 голосов
/ 20 сентября 2015

В этом ответе рассматриваются Структурированные таблицы в интерпретации Excel. В то время как методы можно легко перевести в матрицы необработанных данных без назначенной структуры таблиц, формулы и кодирование VBA для этого решения будут нацелены на истинно структурированные таблицы.

Преамбула

Третья таблица может содержать объединенные данные двух таблиц с некоторыми собственными формулами рабочего листа, но для правильного размера третьей таблицы при добавлении или удалении строк в / из зависимых таблиц потребуются либо операции изменения размера вручную, либо некоторый VBA, который отслеживает их изменяет и соответствует третьей таблице, чтобы удовлетворить. В конце этого ответа я включил варианты добавления имени рабочего листа исходной таблицы, а также некоторого кода VBA для обслуживания таблицы.

Если вам нужна только рабочая книга с примерами без объяснений, перейдите к концу этого ответа, чтобы получить ссылку на книгу, использованную для создания этой процедуры.

Примеры таблиц данных

1017 *Table Collection Sample Data

Я использовал пример данных ОП для построения двух таблиц с именами (по умолчанию) Table1 и Table2 на листах Sheet1 и Sheet2 соответственно. Я намеренно сместил их, меняя градусы от ячейки A1 каждого рабочего листа, чтобы продемонстрировать способность структурированной таблицы обращаться либо к себе, либо к другой структурированной таблице в формуле как к отдельной сущности, независимо от ее положения на родительском листе. Третья таблица будет построена аналогичным образом. Эти смещения предназначены только для демонстрационных целей; они не обязательны.

Шаг 1: постройте третий стол

Создайте заголовки для третьей таблицы и выберите эту будущую строку заголовка и хотя бы одну строку под ней, чтобы использовать команду Вставить ► Таблицы ► Таблица.

1028 *Combining Tables New Table

Ваша новая пустая третья таблица на листе Sheet3 должна выглядеть следующим образом.

1035 *Collecting Table Data Build New Table

Шаг 2: Заполните третью таблицу

Начните с заполнения первой ячейки в 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 заканчиваются строки, поиск передается второй функции INDEX, ссылающейся на Table2 с помощью функции IFERROR , и ее последовательные строки извлекаются с помощью функций ROW и ROWS используя немного больше математики. Функция COLUMN используется как COLUMN(A:A), которая будет извлекать первый столбец ссылочной таблицы независимо от того, где она находится на рабочем листе. Это будет переходить ко второму, третьему столбцу и т. Д., Если формула заполнена правильно.

Говоря о правильном заполнении, заполните формулу прямо до E6. У вас должно быть что-то похожее на следующее.

1066 *Aggregating table data, third table

Шаг 2.5: [необязательно] Добавить имя родительского листа исходной таблицы

Возьмите ручку определения размера Table3 (обозначенную оранжевой стрелкой на приведенном ниже примере изображения) в правом нижнем углу и перетащите ее вправо на один столбец, чтобы добавить новый столбец в таблицу. Переименуйте заголовок метки в нечто более подходящее, чем значение по умолчанию. Я использовал Лист в качестве метки столбца.

1077 *Collating table data - source worksheet name

Хотя вы не можете получить имя листа исходной таблицы напрямую, функция CELL может получить полный путь, имя файла и лист любой ячейки в сохраненной книге¹ в качестве одного из необязательных info_types .

Положите следующую формулу яВ пустую ячейку Таблицы в первой строке нового столбца, который вы только что создали.

=TRIM(RIGHT(SUBSTITUTE(CELL("filename", IF((ROW([@[no.]])-ROW(Table3[#Headers]))>ROWS(Table1), Table2, Table1)), CHAR(93), REPT(CHAR(32), 999)), 255))

Составить заполнение Таблицы3

Если вы не планируете завершить этот небольшой проект с помощью некоторого VBA, чтобы сохранить размеры таблицы 3 при добавлении или удалении строк из одной из двух исходных таблиц, просто возьмите ручку изменения размера таблицы 3 и перетащите вниз, пока вы не накопите все данные. из обеих таблиц. Внизу этого ответа приведено примерное изображение ожидаемых результатов.

Если вы планируете добавить немного VBA, пропустите все заполнение таблицы 3 и перейдите к следующему шагу.

Шаг 3: Добавьте немного VBA для поддержки третьей таблицы

Полная автоматизация процесса, который запускается изменениями данных рабочего листа, лучше всего обрабатывается макросом события Worksheet_Change рабочего листа. Поскольку задействованы три таблицы, каждая на своем рабочем листе, макрос события Workbook_SheetChange является лучшим методом обработки событий изменения из нескольких рабочих листов.

Откройте VBE с помощью Alt + F11 . Когда он откроется, найдите Project Explorer в левом верхнем углу. Если его не видно, нажмите Ctrl + R , чтобы открыть его. Найдите ThisWorkbook и щелкните правой кнопкой мыши, затем выберите Просмотреть код (или просто дважды щелкните ThisWorkbook).

1121 *Collect data from multiple tables

Вставьте следующее в новую панель под названием что-то вроде Book1 - ThisWorkbook (Код) .

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

Эти две подпрограммы широко используют свойство Worksheet .CodeName . CodeName рабочего листа имеет значение Sheet1, Sheet2, Sheet3 и т. Д. и не изменяется при переименовании рабочего листа. На самом деле, они редко меняются даже более опытным пользователем. Они были использованы для того, чтобы вы могли переименовывать свои рабочие листы без изменения кода. Тем не менее, они должны указывать на правильные рабочие листы сейчас. Измените код, если ваши таблицы и таблицы не совпадают с данными. Вы можете видеть отдельные кодовые имена рабочих листов в скобках рядом с их рабочим листом . Имя свойства на изображении выше, показывающем проводник проекта VBE.

Нажмите Alt + Q , чтобы вернуться к рабочим листам. Все, что осталось, это закончить заполнение Table3 , выбрав любую ячейку в Table1 или Table2 и сделав вид, что ее изменили, нажав F2 затем Введите↵ . Ваши результаты должны напоминать следующее.

1157 *Combine two tables into one automatically

Если вы проделали весь этот путь, то у вас должна быть довольно полная таблица сбора, которая активно объединяет данные из двух исходных «дочерних» таблиц. Если вы также добавили VBA, то обслуживание третьей таблицы сбора практически отсутствует.

Переименование таблиц

Если вы решите переименовать одну или все три таблицы, формулы рабочего листа будут мгновенно и автоматически отражать изменения. Если вы решили включить Workbook_SheetChange и сопровождающую вспомогательную процедуру помощника, вам придется вернуться в кодовую таблицу ThisWorkbook и использовать Find & Replace, чтобы внести соответствующие изменения.

Пример рабочей книги

Я сделал полностью рабочую рабочую книгу примера доступной из моего общедоступного DropBox.

Table_Collection_w_Sheetname.xlsb


¹ Функция CELL может извлечь только имя листа сохраненной книги. Если рабочая книга не была сохранена, то у нее нет имени файла, и функция CELL вернет пустую строку при запросе имени файла.

3 голосов
/ 29 марта 2012

Вы можете активировать Офисный буфер обмена (стрелка в правом нижнем углу раздела буфера обмена на вкладке «Главная» ленты).Скопируйте оба диапазона, затем используйте команду Вставить все , как показано ниже.

Вам по-прежнему необходимо сначала заполнить имя листа в дополнительном столбце, хотя это можно сделать, дважды щелкнув маркер заполнения.

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),""))
1 голос
/ 15 марта 2013

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

Подробное объяснение того, как это работает, есть в моем блоге , поскольку его было слишком долго включать здесь.

0 голосов
/ 30 января 2017

Я использую этот код / ​​формулу. хорошо работает для моих нужд. Единственное, что я хотел бы знать, это как сделать лучшую формулу ячейки, чтобы я мог использовать более 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 голосов
/ 30 октября 2016

Небольшое изменение кода Джипеда.

Если вы используете аналогичный подход, но с несколькими таблицами (например, более 10), то будет довольно сложно попытаться вручную добавить каждое имя каждой таблицы. Это также проблема, если вы изменяете имена таблиц, так как имена жестко связаны в VBA. Чтобы избежать дополнительной работы, учтите это:

Итак, предположим следующее:

  • На каждом рабочем листе есть одна или несколько таблиц, но они имеют схожую структуру.
  • На рабочих листах есть только таблицы - других членов коллекции ListObjects нет.
  • Каждый раз, когда мы редактируем таблицу на листе, это вызывает обновление в основной таблице (таблица 3).

Тогда подпункт Workbook_SheetChange в приведенном выше примере может выглядеть следующим образом:

     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

Edit. Вторая процедура будет выглядеть так:

   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

Эта процедура отличается от предыдущей тем, что исключает запрограммированные случаи. Если в активном рабочем листе зарегистрировано изменение, то любая таблица в этом рабочем листе, которая будет изменена, вызовет процедуру update_Table .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...