Макрос Excel: как скопировать все строки из 3 листов и объединить строки, уникальные в первом столбце?

Таблицы содержат сотни строк с номерами счетов в столбце A, описанием счетов в столбце B и итогами в столбце C. Я хочу скопировать строки из всех 3 рабочих листов в один 4-й рабочий лист, но там, где обнаружены повторяющиеся номера счетов, я хочу, чтобы там был только один с итоговыми суммами, агрегированными в столбце C этой строки и дополнительных удалил, вот так:

Ввод с листов (все листы в одном файле .xls):

Лист 1 книги

                A                     B                       C
1            abc-123            Project Costs             1,548.33
2            abc-321           Housing Expenses                250
3            abc-567           Helicopter Rides          11,386.91

Лист 2 книги

                A                     B                       C
1            abc-123            Project Costs             1,260.95
2            abc-321           Housing Expenses                125
3            abc-567           Helicopter Rides          59,605.48

Лист 3 книги

                A                     B                       C
1            abc-123            Project Costs             1,785.48
2            abc-321           Housing Expenses                354
3            def-345            Elephant Treats         814,575.31

Каким бы я хотел получить результат:

                A                     B                       C
1            abc-123            Project Costs             4,642.28
2            abc-321           Housing Expenses                729
3            abc-567           Helicopter Rides          70,992.39
4            def-345            Elephant Treats         814,575.31

Примечание: некоторые номера счетов никогда не повторяются, но некоторые повторяются.


person orokusaki    schedule 29.01.2010    source источник


Ответы (3)


Вот один способ.

Option Explicit

Sub Test()
    Dim sheetNames: sheetNames = Array("Sheet1", "Sheet2", "Sheet3")
    Dim target As Worksheet: Set target = Worksheets("Sheet4")
    Dim accounts As New Dictionary
    Dim balances As New Dictionary
    Dim source As Range
    Dim row As Range
    Dim id As String
    Dim account As String
    Dim balance As Double
    Dim sheetName: For Each sheetName In sheetNames
        Set source = Worksheets(sheetName).Range("A1").CurrentRegion
        Set source = source.Offset(1, 0).Resize(source.Rows.Count - 1, source.Columns.Count)
        For Each row In source.Rows
            id = row.Cells(1).Value
            account = row.Cells(2).Value
            balance = row.Cells(3).Value
            accounts(id) = account
            If balances.Exists(id) Then
                balances(id) = balances(id) + balance
            Else
                balances(id) = balance
            End If
        Next row
    Next sheetName

    Call target.Range("A2:A65536").EntireRow.Delete

    Dim rowIndex As Long: rowIndex = 1
    Dim key
    For Each key In accounts.Keys
        rowIndex = rowIndex + 1
        target.Cells(rowIndex, 1).Value = key
        target.Cells(rowIndex, 2).Value = accounts(key)
        target.Cells(rowIndex, 3).Value = balances(key)
    Next key
End Sub
  1. Создайте новый модуль (редактор VBA -> Вставить -> Модуль) и вставьте в него приведенный выше код.

  2. Добавьте ссылку на Microsoft Scripting Runtime (редактор VBA -> Инструменты -> Ссылки -> Отметьте Microsoft Scripting Runtime).

  3. Запустите его, поместив курсор в код и нажав F5.

Очевидно, листы должны называться Sheet1, Sheet2, Sheet3 и Sheet4. Он не будет вставлять заголовки столбцов в Sheet4, но, по-видимому, они статичны, поэтому вы можете просто настроить их заранее.

person Adam Ralph    schedule 29.01.2010
comment
Работал!!!!! Спасибо, но он выводит что-то из этого: 9.09495E-15. Я не упомянул, что некоторые входные данные в общем разделе равны 0, но они отображаются в Excel как тире, и если я дважды щелкну по полю, я вижу 0. Все поля, в которых это было, при входе в новый файл превратился в ту ерунду Е-24. - person orokusaki; 30.01.2010
comment
О, я просто заменил Double на Currency, и это сработало. Большое спасибо, чувак. Ваш код потрясающий (я думаю, вам нужен Python, исходя из простоты вашего кода). - person orokusaki; 30.01.2010
comment
Большое спасибо за голоса. Я действительно фанат Python. Я недавно играл с IronPython, так как сейчас специализируюсь на .NET. Инструменты IronPython сейчас немного ограничены, но я очень хочу, чтобы они улучшились. Я бы тоже хотел поиграть с чистым Python на каком-то этапе, если и когда у меня будет время - person Adam Ralph; 30.01.2010

На самом деле вы хотите запустить макрос или что-то еще, что копирует все ваши данные с трех листов на новый лист, а затем запускает сводную таблицу на основе результата. Сводные таблицы обрабатывают уникальность вашего набора данных и агрегацию данных для множественности.


Вы можете использовать следующий код VB (введите Alt-F11 в Excel, чтобы перейти к редактору VBA, вставьте новый модуль и вставьте в него этот код). Этот код предполагает, что ваша электронная таблица имеет три листа с именами Sheet1, Sheet2 и Sheet3, которые содержат ваши данные, и что данные непрерывны и начинаются в ячейке A1 на каждом листе. Также предполагается, что в вашей электронной таблице есть лист с именем «Сводная таблица», на который будут скопированы все данные.

Sub CopyDataToPivotSheet()

  Sheets("Pivot Sheet").Select
  Range("A1:IV65536").Select
  Selection.Clear

  Sheets("Sheet1").Select
  Range("A1").Select
  Range(Selection, Selection.End(xlToRight)).Select
  Range(Selection, Selection.End(xlDown)).Select
  Selection.Copy
  Sheets("Pivot Sheet").Select
  Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
      :=False, Transpose:=False

  Sheets("Sheet2").Select
  Range("A1").Select
  Range(Selection, Selection.End(xlDown)).Select
  Range(Selection, Selection.End(xlToRight)).Select
  Application.CutCopyMode = False
  Selection.Copy
  Sheets("Pivot Sheet").Select
  Range("A1").Select
  Selection.End(xlDown).Offset(1, 0).Range("A1").Select
  Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
      :=False, Transpose:=False

  Sheets("Sheet3").Select
  Range("A1").Select
  Range(Selection, Selection.End(xlToRight)).Select
  Range(Selection, Selection.End(xlDown)).Select
  Application.CutCopyMode = False
  Selection.Copy
  Sheets("Pivot Sheet").Select
  Selection.End(xlDown).Select
  Range("A1").Select
  Selection.End(xlDown).Offset(1, 0).Range("A1").Select
  Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
      :=False, Transpose:=False

  Rows("1:1").Select
  Application.CutCopyMode = False
  Selection.Insert Shift:=xlDown
  Range("A1").Select
  ActiveCell.FormulaR1C1 = "AccountNum"
  Range("B1").Select
  ActiveCell.FormulaR1C1 = "Description"
  Range("C1").Select
  ActiveCell.FormulaR1C1 = "Total"

End Sub

Это 95% сгенерированный код excel (через макрос записи), но я изменил некоторые вещи, чтобы сделать его более общим. В любом случае, вы можете назначить этот макрос кнопке обычным способом или назначить его сочетанию клавиш через диалог Инструменты => Макрос => Макросы ... Параметры ....

В любом случае, ваши данные будут агрегированы на сводной таблице с соответствующими заголовками.

Затем вы можете перейти в Data => PivotTable and PivotChart Report. Нажмите «Далее», выберите данные на сводной таблице (включая заголовки!), Нажмите «Далее» и выберите «Макет».

Перетащите поле AccountNumber (справа от мастера) в область с надписью «Строка». Перетащите поле «Описание» под поле «Номер счета» в области «Строка». Перетащите поле «Итого» в область «Данные», затем дважды щелкните по нему в области «Данные» и выберите «Сумма», чтобы оно агрегировало это поле. Нажмите OK, и вы должны получить сводную таблицу. Вероятно, вы захотите скрыть промежуточные итоги, щелкнув правой кнопкой мыши заголовок промежуточных итогов (например, «бла-бла Всего») и выбрав «Скрыть». Этот результат в основном выглядит точно так же, как и ваш желаемый результат.

Если вы хотите пофантазировать, вы могли бы автоматизировать этот последний абзац, но, вероятно, это того не стоит.

Надеюсь это поможет!

person vicatcu    schedule 29.01.2010
comment
О, прекрасно. Да, макрос - это то, что я имел в виду. Я думал, что это называется VBScript, но кто-то отредактировал мой заголовок, чтобы вместо него было написано VBA. Это правильно? Как мне сделать все, о чем вы упомянули? - person orokusaki; 29.01.2010
comment
Кроме того, код VBA выше просто «полезен», он не требуется, так как вы всегда можете скопировать данные в сводную таблицу вручную. - person vicatcu; 29.01.2010

Я думаю, что ADO лучше всего подходит для этого, здесь вы найдете некоторые примечания: Функция обнаружения дубликатов в листе Excel

Вы можете использовать подходящую строку SQL для объединения и группировки ваших записей.

Например:

strSQL = "SELECT F1, F2, Sum(F3) FROM (" _
       & "SELECT F1,F2,F3 FROM [Sheet1$] " _
       & "UNION ALL " _
       & "SELECT F1,F2,F3 FROM [Sheet2$] " _
       & "UNION ALL " _
       & "SELECT F1,F2,F3 FROM [Sheet3$] ) " _
       & "GROUP BY F1, F2"
person Fionnuala    schedule 29.01.2010