Search code examples
excelvbams-accessjoinms-access-2010

How to perform a left inner join or similar operation using VBA and MS-ACCESS to join based on shared ID key in four excel sheets?


I have an ms-access button that I use to grab a specific excel file and behind that button is a vba script. I treat the file like an object. This excel file has 9 sheets. Only 2,3,4,5 I am concerned with. I don't want to alter the original 2nd sheet, what I'd like to do is create a copy of the 2nd sheet and place that at the end of the excel sheet (temporarily). This is so I can access that merged sheet and run a set of data validations against it. Once those validations are complete I can remove it, so it's as if the file was never altered.

I want to perform a left inner join or sth like it so that sheet 2 is joined with all columns from 3,4,5, based on the shared join key "Unique Transaction ID", even if there is not a match with the columns they should still be added. And if a match is found with the key, then that rows data is added to the correct line and corresponding column.

The sheets are set up like this:

Sheet 2:

A
Unique Transaction ID some_header
321 d1
123 d2
333 d3
231 d4
908 d5
111 d6
367 d7

Sheet 3:

A
Unique Transaction ID another_header
333 q
231 w
908 e

Sheet 4:

A
Unique Transaction ID x_header
321 h
123 t

Sheet 5:

A
Unique Transaction ID z_header
321
123
333
231
908
111 b_2
367 a_1

The ranges for each sheet is:

Sheet 2: A to AU
Sheet 3: A to I
Sheet 4: A to H
Sheet 5: A to D`

Since I only need the A column "Unique Transaction ID" from Sheet 2, the other ranges would start at "B" I think.

And the merged sheet should therefore be the range: A to BM

When horizontally merged the ranges for the sheets would be:

Sheet 2: A to AU
Sheet 3: AV to BC
Sheet 4: BD to BJ
Sheet 5: BK to BM

The result of the merge should produce a sheet that looks like this:

A
Unique Transaction ID | some_header | another_header | x_header | z_header | 
321                   | d1          |                | h        |          |
123                   | d2          |                | t        |          |
333                   | d3          | q              |          |          |
231                   | d4          | w              |          |          |
908                   | d5          | e              |          |          |
111                   | d6          |                |          | b_2      |
367                   | d7          |                |          | a_1      |

And of course there will be many columns in between those columns.

Is there an error in my reasoning? A more straight-forward approach?

Any help appreicated Thank you

Here is what Ive tried, none seems to fully do the merge correctly. I can get to the point where I have a copy of sheet 2 and all its columns/data but nothing from sheet 3,4,5.

Example:

    `Public Sub Init(filePath As Variant)
        ' Connect to original file
        Dim xlApp As Excel.Application, objFile As Excel.Workbook
        Set xlApp = CreateObject("Excel.Application")
        Set objFile = xlApp.Workbooks.Open(filePath)
        
        ' Get the number of sheets
        numSheets = objFile.Worksheets.Count
        
        If numSheets = 9 Then
            ' Define variables for Sheet 2 and the other sheets
            Dim sht2 As Worksheet, sht3 As Worksheet, sht4 As Worksheet, sht5 As Worksheet
            Dim lastCol As Long, copyRange As Range, pasteRange As Range
            
            ' Set variables to the correct worksheets
            Set sht2 = objFile.Worksheets("Sheet2")
            Set sht3 = objFile.Worksheets("Sheet3")
            Set sht4 = objFile.Worksheets("Sheet4")
            Set sht5 = objFile.Worksheets("Sheet5")
            
            ' Get the last column in Sheet 2
            lastCol = sht2.Cells(1, sht2.Columns.Count).End(xlToLeft).Column
            
            ' Loop through each column in Sheet 3, 4, and 5 and paste the values into Sheet 2
            For i = 1 To lastCol
                ' Set the copy and paste ranges for each column
                Set copyRange = Union(sht3.Cells(1, i), sht4.Cells(1, i), sht5.Cells(1, i)).EntireColumn
                Set pasteRange = sht2.Cells(1, sht2.Columns.Count).End(xlToLeft).Offset(0, 1)
                ' Copy and paste the values
                pasteRange.Resize(copyRange.Rows.Count, copyRange.Columns.Count).Value = copyRange.Value
            Next i
        End If
        
        ' Close the original file and clean up
        objFile.Close SaveChanges:=False
        xlApp.Quit
        Set objFile = Nothing
        Set xlApp = Nothing
    End Sub`

I tried this, but cant use the Union feature in vba.

This one adds everything from sheet 2, but columns/data from sheet 3,4,5 are not there:

' Initialize object and set default values
Public Sub Init(filePath As Variant)
    
    ' Connect to original file
    Dim xlApp As Excel.Application, objFile As Excel.Workbook
    Set xlApp = CreateObject("Excel.Application")
    Set objFile = xlApp.Workbooks.Open(filePath)
    
    ' Get the number of sheets
    numSheets = objFile.Worksheets.Count
    
    If numSheets = 9 Then
        ' Get references to the relevant sheets
        Dim sheet2 As Excel.Worksheet, sheet3 As Excel.Worksheet, sheet4 As Excel.Worksheet, sheet5 As Excel.Worksheet
        Set sheet2 = objFile.Worksheets("sheet2")
        Set sheet3 = objFile.Worksheets("sheet3")
        Set sheet4 = objFile.Worksheets("sheet4")
        Set sheet5 = objFile.Worksheets("sheet5")
        
        ' Make a copy of sheet 2 and set it as the active sheet
        sheet2.Copy After:=objFile.Worksheets(numSheets)
        Dim mergedSheet As Excel.Worksheet
        Set mergedSheet = objFile.Worksheets(numSheets + 1)
        mergedSheet.Activate
        
        ' Add a header row to the merged sheet
        Dim headerRange As Excel.Range
        Set headerRange = Range("A1:AU1")
        headerRange.Copy
        Range("AV1").PasteSpecial xlPasteValues
        Range("BD1").PasteSpecial xlPasteValues
        Range("BK1").PasteSpecial xlPasteValues
        
        ' Loop through the unique transaction IDs in sheet 2 and find matching rows in sheets 3, 4, and 5
        Dim lastRow As Long, i As Long
        lastRow = sheet2.Cells(sheet2.Rows.Count, "A").End(xlUp).Row
        For i = 2 To lastRow ' Start at row 2 to skip the header row
            
            ' Get the unique transaction ID from sheet 2
            Dim uniqueID As String
            uniqueID = sheet2.Cells(i, "A").Value
            
            ' Find matching row in sheet 3 and copy values to merged sheet
            Dim matchRange As Excel.Range
            Set matchRange = sheet3.Columns("A").Find(uniqueID)
            If Not matchRange Is Nothing Then
                matchRange.Resize(1, 8).Copy
                mergedSheet.Cells(i, "AV").PasteSpecial xlPasteValues
            End If
            
            ' Find matching row in sheet 4 and copy values to merged sheet
            Set matchRange = sheet4.Columns("A").Find(uniqueID)
            If Not matchRange Is Nothing Then
                matchRange.Resize(1, 7).Copy
                mergedSheet.Cells(i, "BD").PasteSpecial xlPasteValues
            End If
            
            ' Find matching row in sheet 5 and copy values to merged sheet
            Set matchRange = sheet5.Columns("A").Find(uniqueID)
            If Not matchRange Is Nothing Then
                matchRange.Resize(1, 3).Copy
                mergedSheet.Cells(i, "BK").PasteSpecial xlPasteValues
            End If
        Next i
        
        ' Auto-fit the columns in the merged sheet and save the file
        mergedSheet.Columns.AutoFit
        objFile.Save
    End If
    
    ' Close the file and quit Excel
    objFile.Close SaveChanges:=True
    xlApp.Quit`

Solution

  • First procedure will not compile. It triggers 'Method or data member not found.' error for copyRange.Value. Second procedure works. Data is copied but column headers are just Sheet 2 repeated. If you want headers from other sheets, then reference each sheet header and copy before each paste. However, select/copy/paste is not necessary. Consider:

            ' Add a header row to the merged sheet
            Range("AV1:BC1").Value = sheet3.Range("A1:I1").Value
            Range("BD1:BJ1").Value = sheet4.Range("A1:H1").Value
            Range("BK1:BM1").Value = sheet5.Range("A1:D1").Value