Excel - 合并具有不同结构

时间:2017-07-28 10:41:01

标签: excel-vba merge worksheet vba excel

我有一个包含100多个工作表的Excel工作簿,所有工作表都有不同的结构(有些列在所有这些工作表中,但有些不是)。有没有一种简单的方法可以通过它们共有的列合并工作表?

提前谢谢!

1 个答案:

答案 0 :(得分:1)

执行以下操作:

  • 打开VBA编辑器窗口
  • 点击“文件”菜单中的“工具”
  • 从“工具”菜单中选择“参考”
  • 向下滚动,直至找到“Microsoft Scripting Runtime”
  • 选中“Microsoft Scripting Runtime”
  • 旁边的框
  • 点击确定

然后将其粘贴到Excel vba模块中:

    Option Explicit
    Public Sub CombineSheetsWithDifferentHeaders()

        Dim wksDst As Worksheet, wksSrc As Worksheet
        Dim lngIdx As Long, lngLastSrcColNum As Long, _
            lngFinalHeadersCounter As Long, lngFinalHeadersSize As Long, _
            lngLastSrcRowNum As Long, lngLastDstRowNum As Long
        Dim strColHeader As String
        Dim varColHeader As Variant
        Dim rngDst As Range, rngSrc As Range
        Dim dicFinalHeaders As Scripting.Dictionary
        Set dicFinalHeaders = New Scripting.Dictionary

        'Set references up-front
        dicFinalHeaders.CompareMode = vbTextCompare
        lngFinalHeadersCounter = 1
        lngFinalHeadersSize = dicFinalHeaders.Count
        Set wksDst = ThisWorkbook.Worksheets.Add

        ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        'Start Phase 1: Prepare Final Headers and Destination worksheet'
        ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

        'First, we loop through all of the data worksheets,
        'building our Final Headers dictionary
        For Each wksSrc In ThisWorkbook.Worksheets

            'Make sure we skip the Destination worksheet!
            If wksSrc.Name <> wksDst.Name Then

                With wksSrc

                    'Loop through all of the headers on this sheet,
                    'adding them to the Final Headers dictionary
                    lngLastSrcColNum = LastOccupiedColNum(wksSrc)
                    For lngIdx = 1 To lngLastSrcColNum

                        'If this column header does NOT already exist in the Final
                        'Headers dictionary, add it and increment the column number
                        strColHeader = Trim(CStr(.Cells(1, lngIdx)))
                        If Not dicFinalHeaders.Exists(strColHeader) Then
                            dicFinalHeaders.Add Key:=strColHeader, _
                                                Item:=lngFinalHeadersCounter
                            lngFinalHeadersCounter = lngFinalHeadersCounter + 1
                        End If

                    Next lngIdx

                End With

            End If

        Next wksSrc

        'Wahoo! The Final Headers dictionary now contains every column
        'header name from the worksheets. Let's write these values into
        'the Destination worksheet and finish Phase 1
        For Each varColHeader In dicFinalHeaders.Keys
            wksDst.Cells(1, dicFinalHeaders(varColHeader)) = CStr(varColHeader)
        Next varColHeader

        '''''''''''''''''''''''''''''''''''''''''''''''
        'End Phase 1: Final Headers are ready to rock!'
        '''''''''''''''''''''''''''''''''''''''''''''''

        '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        'Start Phase 2: write the data from each worksheet to the Destination!'
        '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

        'We begin just like Phase 1 -- by looping through each sheet
        For Each wksSrc In ThisWorkbook.Worksheets

            'Once again, make sure we skip the Destination worksheet!
            If wksSrc.Name <> wksDst.Name Then

                With wksSrc

                    'Identify the last row and column on this sheet
                    'so we know when to stop looping through the data
                    lngLastSrcRowNum = LastOccupiedRowNum(wksSrc)
                    lngLastSrcColNum = LastOccupiedColNum(wksSrc)

                    'Identify the last row of the Destination sheet
                    'so we know where to (eventually) paste the data
                    lngLastDstRowNum = LastOccupiedRowNum(wksDst)

                    'Loop through the headers on this sheet, looking up
                    'the appropriate Destination column from the Final
                    'Headers dictionary and creating ranges on the fly
                    For lngIdx = 1 To lngLastSrcColNum
                        strColHeader = Trim(CStr(.Cells(1, lngIdx)))

                        'Set the Destination target range using the
                        'looked up value from the Final Headers dictionary
                        Set rngDst = wksDst.Cells(lngLastDstRowNum + 1, _
                                                  dicFinalHeaders(strColHeader))

                        'Set the source target range using the current
                        'column number and the last-occupied row
                        Set rngSrc = .Range(.Cells(2, lngIdx), _
                                            .Cells(lngLastSrcRowNum, lngIdx))

                        'Copy the data from this sheet to the destination!
                        rngSrc.Copy Destination:=rngDst

                    Next lngIdx

                End With

            End If

        Next wksSrc

        'Yay! Let the user know that the data has been combined
        MsgBox "Data combined!"

    End Sub

    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'INPUT       : Sheet, the worksheet we'll search to find the last row
    'OUTPUT      : Long, the last occupied row
    'SPECIAL CASE: if Sheet is empty, return 1
    Public Function LastOccupiedRowNum(Sheet As Worksheet) As Long
        Dim lng As Long
        If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
            With Sheet
                lng = .Cells.Find(What:="*", _
                                  After:=.Range("A1"), _
                                  Lookat:=xlPart, _
                                  LookIn:=xlFormulas, _
                                  SearchOrder:=xlByRows, _
                                  SearchDirection:=xlPrevious, _
                                  MatchCase:=False).Row
            End With
        Else
            lng = 1
        End If
        LastOccupiedRowNum = lng
    End Function

    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'INPUT       : Sheet, the worksheet we'll search to find the last column
    'OUTPUT      : Long, the last occupied column
    'SPECIAL CASE: if Sheet is empty, return 1
    Public Function LastOccupiedColNum(Sheet As Worksheet) As Long
        Dim lng As Long
        If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
            With Sheet
                lng = .Cells.Find(What:="*", _
                                  After:=.Range("A1"), _
                                  Lookat:=xlPart, _
                                  LookIn:=xlFormulas, _
                                  SearchOrder:=xlByColumns, _
                                  SearchDirection:=xlPrevious, _
                                  MatchCase:=False).Column
            End With
        Else
            lng = 1
        End If
        LastOccupiedColNum = lng
    End Function

然后运行宏 原始来源改编自:https://danwagner.co/how-to-combine-data-with-different-columns-on-multiple-sheets-into-a-single-sheet/