7

У меня есть сотни файлов Excel, которые имеют один и тот же формат (то есть 4 листа на файл Excel). Мне нужно объединить все файлы в один файл для пения и танца, который должен иметь тот же формат, что и оригиналы (то есть поддерживать четыре отдельных листа, которые имеют одинаковое название).

Хотя каждый файл имеет одинаковую структуру, количество столбцов (и имен заголовков) между листами 1 и 2 (например) различно. Поэтому его нельзя объединить в один файл со всем на одном листе!

Есть два осложнения:

  1. Мне нужно создать столбец EXTRA в объединенном файле (на КАЖДОМ листе), чтобы определить исходный файл («имя файла»).

  2. Файлы содержат много нулевых записей данных (например, 55 строк полезных данных, за которыми следуют сотни строк нулей), которые мне нужно удалить из объединенного файла.

Я никогда не использовал VBA, но каждый должен начать где-то, я полагаю.

6 ответов6

13

Это серьезная просьба, но у меня был вечер для записи, так что вот код, который, я думаю, сработает. (Знание форматов ваших листов не помогает, но мы можем работать с этим.)

Откройте новую рабочую книгу (это будет ваша основная рабочая книга), перейдите в среду VBA (Alt + F11) и создайте новый модуль («Вставка»> «Модуль»). Вставьте следующий код VBA в окно нового модуля:

Option Explicit
Const NUMBER_OF_SHEETS = 4

Public Sub GiantMerge()
    Dim externWorkbookFilepath As Variant
    Dim externWorkbook As Workbook
    Dim i As Long
    Dim mainLastEnd(1 To NUMBER_OF_SHEETS) As Range
    Dim mainCurEnd As Range

    Application.ScreenUpdating = False

    ' Initialise

    ' Correct number of sheets
    Application.DisplayAlerts = False
    If ThisWorkbook.Sheets.Count < NUMBER_OF_SHEETS Then
        ThisWorkbook.Sheets.Add Count:=NUMBER_OF_SHEETS - ThisWorkbook.Sheets.Count
    ElseIf ThisWorkbook.Sheets.Count > NUMBER_OF_SHEETS Then
        For i = ThisWorkbook.Sheets.Count To NUMBER_OF_SHEETS + 1 Step -1
            ThisWorkbook.Sheets(i).Delete
        Next i
    End If
    Application.DisplayAlerts = True

    For i = 1 To NUMBER_OF_SHEETS
        Set mainLastEnd(i) = GetTrueEnd(ThisWorkbook.Sheets(i))
    Next i


    ' Load the data
    For Each externWorkbookFilepath In GetWorkbooks()
        Set externWorkbook = Application.Workbooks.Open(externWorkbookFilepath, , True)

        For i = 1 To NUMBER_OF_SHEETS

            If mainLastEnd(i).Row > 1 Then
                ' There is data in the sheet

                ' Copy new data (skip headings)
                externWorkbook.Sheets(i).Range("A2:" & GetTrueEnd(externWorkbook.Sheets(i)).Address).Copy ThisWorkbook.Sheets(i).Cells(mainLastEnd(i).Row + 1, 1)

                ' Find the end column and row
                Set mainCurEnd = GetTrueEnd(ThisWorkbook.Sheets(i))
            Else
                ' No nata in sheet yet (prob very first run)

                ' Get correct sheet name from first file we check
                ThisWorkbook.Sheets(i).Name = externWorkbook.Sheets(i).Name

                ' Copy new data (with headings)
                externWorkbook.Sheets(i).Range("A1:" & GetTrueEnd(externWorkbook.Sheets(i)).Address).Copy ThisWorkbook.Sheets(i).Cells(mainLastEnd(i).Row, 1)

                ' Find the end column and row
                Set mainCurEnd = GetTrueEnd(ThisWorkbook.Sheets(i)).Offset(, 1)

                ' Add file name heading
                ThisWorkbook.Sheets(i).Cells(1, mainCurEnd.Column).Value = "File Name"
            End If

            ' Add file name into extra column
            ThisWorkbook.Sheets(i).Range(ThisWorkbook.Sheets(i).Cells(mainLastEnd(i).Row + 1, mainCurEnd.Column), mainCurEnd).Value = externWorkbook.Name

            Set mainLastEnd(i) = mainCurEnd
        Next i

        externWorkbook.Close
    Next externWorkbookFilepath

    Application.ScreenUpdating = True
End Sub

' Returns a collection of file paths, or an empty collection if the user selects cancel
Private Function GetWorkbooks() As Collection
    Dim fileNames As Variant
    Dim xlFile As Variant

    Set GetWorkbooks = New Collection

    fileNames = Application.GetOpenFilename(Title:="Please choose the files to merge", _
                                               FileFilter:="Excel Files, *.xls;*.xlsx", _
                                               MultiSelect:=True)
    If TypeName(fileNames) = "Variant()" Then
        For Each xlFile In fileNames
            GetWorkbooks.Add xlFile
        Next xlFile
    End If
End Function

' Finds the true end of the table (excluding unused columns/rows and rows filled with 0's)
Private Function GetTrueEnd(ws As Worksheet) As Range
    Dim lastRow As Long
    Dim lastCol As Long
    Dim r As Long
    Dim c As Long

    On Error Resume Next
    lastCol = ws.UsedRange.Find("*", , , xlPart, xlByColumns, xlPrevious).Column
    lastRow = ws.UsedRange.Find("*", , , xlPart, xlByRows, xlPrevious).Row
    On Error GoTo 0

    If lastCol <> 0 And lastRow <> 0 Then

        ' look back through the last rows of the table, looking for a non-zero value
        For r = lastRow To 1 Step -1
            For c = 1 To lastCol
                If ws.Cells(r, c).Text <> "" Then
                    If ws.Cells(r, c).Text <> 0 Then
                        Set GetTrueEnd = ws.Cells(r, lastCol)
                        Exit Function
                    End If
                End If
            Next c
        Next r
    End If

    Set GetTrueEnd = ws.Cells(1, 1)
End Function

Сохраните его, и мы готовы начать его использовать.

Запустите макрос GiantMerge . Вы должны выбрать файлы Excel, которые хотите объединить (вы можете выбрать несколько файлов в диалоговом окне обычным способом Windows (Ctrl для выбора нескольких отдельных файлов, Shift для выбора диапазона файлов)). Вам не нужно запускать макрос для всех файлов, которые вы хотите объединить, вы можете сделать это только для нескольких файлов за раз. При первом запуске он настроит вашу основную рабочую книгу на правильное количество листов, назовет листы на основе первой выбранной книги для объединения и добавит заголовки.

Я сделал следующие предположения (не полный список):

  • Есть 4 листа (это можно легко изменить, изменив константу в верхней части кода.)
  • Листы находятся в одинаковом порядке во всех дополнительных рабочих книгах
  • Столбцы на каждом листе находятся в одинаковом порядке во всех книгах (хотя не все листы в книге будут иметь одинаковые столбцы. Например, WorkBook1, Sheet1 имеет столбцы A, B, C, Sheet2 имеет столбцы A, B; WorkBook2, Sheet1 имеет столбцы A, B, C, в Sheet2 есть столбцы A, B. И т. д. Если в рабочей книге есть следующее: Sheet1 имеет столбцы A, C, B, в Sheet2 есть столбцы B, A, то столбцы не будут правильно выровнены)
  • В дополнительных книгах нет лишних или отсутствующих столбцов
  • На каждом листе в каждой книге есть заголовок (и только в первом ряду на каждом листе)
  • Все столбцы должны быть включены (даже если они содержат только 0)
  • Все строки в конце таблицы, содержащие только 0, не копируются в мастер
  • В дополнительном столбце нужно только имя файла (а не путь к файлу)
  • Я не знаю, насколько хорошо это будет работать, если у вас нет данных на некоторых листах (или они просто заполнены нулями)

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

1

Если вам нужен инструмент только для объединения этих файлов Excel, ознакомьтесь с JMC Excel.

1

Стоит также упомянуть, что Рон де Брюин создал потрясающий плагин Windows для объединения таблиц Excel, который называется RDBMerge. Инструкции можно найти здесь: http://www.rondebruin.nl/merge.htm. Для меня это работало без сбоев, объединяя файлы xlsx в Excel 2007.

Он создает дополнительный столбец в объединенном файле, содержащий имя исходного файла. Не уверен, как он обрабатывает ноль записей (вторая часть исходного вопроса), хотя.

0

Метод с использованием простого скрипта Python (намного короче, чем VB!).

https://superuser.com/a/1138948/141182

0
Sub simpleXlsMerger()
    Dim bookList As Workbook
    Dim mergeObj As Object, dirObj As Object, filesObj As Object, everyObj As Object
    Application.ScreenUpdating = False
    Set mergeObj = CreateObject("Scripting.FileSystemObject")

    ' change folder path of excel files here
    Set dirObj = mergeObj.Getfolder("D:\change\to\excel\files\path\here")
    Set filesObj = dirObj.Files
    For Each everyObj In filesObj
        Set bookList = Workbooks.Open(everyObj)

        ' change "A2" with cell reference of start point for every files here
        ' for example "B3:IV" to merge all files start from columns B and rows 3 
        ' If you're files using more than IV column, change it to the latest column
        ' Also change "A" column on "A65536" to the same column as start point
        Range("A2:IV" & Range("A65536").End(xlUp).Row).Copy
        ThisWorkbook.Worksheets(1).Activate

        ' Do not change the following column. It's not the same column as above
        Range("A65536").End(xlUp).Offset(1, 0).PasteSpecial
        Application.CutCopyMode = False
        bookList.Close
    Next
End Sub
0

Это достойный по размеру проект, но очень выполнимый. Вот хорошее начало VBA, на котором вы можете построить. Это позволит вам просмотреть все файлы, которые вам нужно объединить, если они у вас есть (одни) в одной папке. Основная рабочая книга, с которой вы объединяетесь, НЕ должна находиться в этом каталоге.

Option Explicit
Sub giantmerge()
    Dim f As Object, fso As Object
    Dim folder As String
    Dim wb As Workbook, ws1 As Worksheet, ws2 As Worksheet, ws3 As Worksheet, ws4 As Worksheet
    Dim sn1 As String, sn2 As String, sn3 As String, sn4 As String
    Set wb = ThisWorkbook
    'Change sheet names to match those in your workbooks.
    sn1 = "Sheet1"
    sn2 = "Sheet2"
    sn3 = "Sheet3"
    sn4 = "Sheet4"
    Set ws1 = wb.Sheets(sn1)
    Set ws2 = wb.Sheets(sn2)
    Set ws3 = wb.Sheets(sn3)
    Set ws4 = wb.Sheets(sn4)

    Set fso = CreateObject("Scripting.FileSystemObject")
    With Application.FileDialog(msoFileDialogFolderPicker)
        .Show
        If .SelectedItems.Count = 0 Then
            MsgBox "Cancel Selected"
            End
        End If
        folder = .SelectedItems(1)
    End With
    For Each f In fso.GetFolder(folder).Files
        Workbooks.Open Filename:=f.Path
        'Get data and store in temporary arrays.
        Workbooks(f.Name).Close
        'Input data in this workbook (master).
    Next
End Sub

Теперь вы (или кто-то еще) можете предоставить код для цикла For в конце. Надеюсь это поможет.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .