VBA vlookup to copy specific columns from multiple sheets to master sheet - vba

I am using Excel to produce reports for a billing system and I would like to use VBA to simplify the process of updating the excel. What I want to do is to use vlookup function to reflect columns (G:AI) from respective Named worksheets back to mastersheet. All sheets starts from row 4. (Row 3 is header)
So I'll further simplify the process as such:
VLOOKUP VBA (When changes made in the Named worksheets)
1. To enable Vlookup function in column (G:AI) in Mastersheet from Named worksheets ("John", "Charlie", "George")
2. As Mastersheet is a mixed data of John, Charlie and George, to input Vlookup formulas across column (G:AI) accordingly, then till last row of Mastersheet
3. My vlookup range will be from Named worksheets (John, Charlie, George), range (A1:AI) starting from column 7, row 4 till the end of the data.
ws1.Cells(r, c).Value = Application.VLookup(ws1.Cells(r, 1).Value, wsNames.Range("A1:AI500"), colnum, False)
Here are the codes I have so far. It's all I worked out (with help) as of now. Any help would be greatly appreciated.
My issue is, when running the code, vlookup values for ws11 is in the right place. However, vlookup values for ws12 and ws13 are shifted towards further left of the worksheet. For example,
while vlookup values for ws11 is in columns (A:AI) - the right columns
vlookup values for ws12 is in columns (AP:BR) - 7 columns from column AI and
vlookup values for ws13 is in columns (BY:DA) - 7 columns from column BR
Is there a line of code that I can insert to fix this?
Sub green_update()
Dim wb As Workbook, ws1 As Worksheet, ws11 As Worksheet, ws12 As Worksheet, ws13 As Worksheet
Set wb = ThisWorkbook
Set ws1 = wb.Sheets("Sheet1")
Set ws11 = wb.Sheets("Sheet11")
Set ws12 = wb.Sheets("Sheet12")
Set ws13 = wb.Sheets("Sheet13")
Dim colNo As Long, ARowNo as Long
Dim for_col As Long, i As Long, r As Long, c As Long, colnum As Long
r = 4: c = 7: colnum = 7
Dim wsNames As Variant
For Each wsNames In Sheets(Array("sheet11", "sheet12", "sheet13"))
colNo = wsNames.Cells("4", Columns.Count).End(xlToLeft).Column
For for_col = 1 To colNo
ARowNo = wsNames.Cells(Rows.Count, "A").End(xlUp).row
For i = 1 To ARowNo
ws1.Cells(r, c).Value = Application.VLookup(ws1.Cells(r, 1).Value, wsNames.Range("A1:AI500"), colnum, False)
If IsError(ws1.Cells(r, c).Value) Then
ws1.Cells(r, c).Value = 0
End If
r = r + 1
Next
r = 4
colnum = colnum + 1
c = c + 1
Next
colnum = 7
Next wsNames
End Sub

I honestly can't see what can be causing the problem you describe based on the code posted. There is nothing substantially different in the code below - I have tidied up a couple of the loops and incorporated the last row variable. Let me know how you get on.
Sub green_update()
Dim wb As Workbook, ws1 As Worksheet
Set wb = ThisWorkbook
Set ws1 = wb.Sheets("Sheet1")
Dim colNo As Long, ARowNo As Long
Dim for_col As Long, i As Long, r As Long, c As Long, colnum As Long
r = 4: c = 7: colnum = 7
Dim wsNames As Variant
For Each wsNames In Sheets(Array("sheet11", "sheet12", "sheet13"))
colNo = wsNames.Cells("4", Columns.Count).End(xlToLeft).Column
ARowNo = wsNames.Cells(Rows.Count, "A").End(xlUp).Row
For for_col = 1 To colNo
For i = 1 To ARowNo
ws1.Cells(r, c).Value = Application.VLookup(ws1.Cells(r, 1).Value, wsNames.Range("A1:AI" & ARowNo), colnum, False)
If IsError(ws1.Cells(r, c).Value) Then
ws1.Cells(r, c).Value = 0
End If
r = r + 1
Next i
r = 4
colnum = colnum + 1
c = c + 1
Next for_col
colnum = 7
Next wsNames
End Sub

Related

How to copy a range of cells to another column in VBA?

Working Environment: Excel 2013
Target: Copy C1:C9 to B11:B19. D1:D9 to B21:B29. E1:E9 to B31:B39.....
After copying all the range to column B, copy A1:A9 to A11:A19(A21:A29....)
My idea is that:
1. select a range by using something like
range.end()
because in some of my sheets, there are only 4 test steps. so I need a syntax which can self inspect the used cells in a column.
do a range copy to column B.
leave 1 row in between considering about the page layout.
My piece of code is:
Worksheets("Master").Columns(3).UsedRange.Copy
Worksheets("Master").Range("B11").PasteSpecial
but seems like the Columns(i).UsedRange.Copy doesn't work. the pastespecial works.
My question is:
How to select the used range in columns? The number of columns are not fixed which means some of the sheets have 40 columns, but some of the other have maybe 30.
Thanks!
I attached one screenshot of the sheet for your reference.
Assuming you do not have more data in the columns to be copied, this should work
Sub copyToOneColumn()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Master")
Dim startCol As Integer
startCol = 3
Dim endCol As Integer
endCol = 10
Dim startRange As Range
Dim ra As Range
For i = startCol To endCol
Set startRange = ws.Range("A1").Offset(0, i - 1)
Set ra = ws.Range(startRange, ws.Cells(Rows.Count, startRange.Column).End(xlUp))
ra.Copy Destination:=ws.Range("B" & Rows.Count).End(xlUp).Offset(2, 0)
Next i
End Sub
You can do a copy (not technically a copy as it doesn't use the clipboard) directly like so:
Range("B1").Resize(Range("A1:A" & range("A" & Rows.Count).End(xlUp).Row).Rows.Count,1) = Range("A1:A" & range("A" & Rows.Count).End(xlUp).Row).Value
Effectively you are looking at B1 then resizing that to a range to be the number of columns in column A that are used with this: Range("A1:A" & range("A" & Rows.Count).End(xlUp).Row).Rows.Count
Then you are making this new range in column B = to the values of the same range in column A.
Note, this can be shortened if you are always starting at row 1 but the code I have given you will suffice if you start at a different row.
You may try something like this...
Sub CopyData()
Dim wsMaster As Worksheet
Dim lr As Long, lc As Long, r As Long, c As Long
Application.ScreenUpdating = False
Set wsMaster = Sheets("Master")
lr = wsMaster.Cells(Rows.Count, 1).End(xlUp).Row
lc = wsMaster.Cells(1, Columns.Count).End(xlToLeft).Column
r = lr + 2
If lr <= 9 Then
For c = 3 To lc
wsMaster.Range(wsMaster.Cells(1, c), wsMaster.Cells(lr, c)).Copy wsMaster.Range("B" & r)
wsMaster.Range("A1:A" & lr).Copy wsMaster.Range("A" & r)
r = wsMaster.Cells(Rows.Count, 2).End(xlUp).Row + 2
Next c
End If
Application.ScreenUpdating = True
End Sub

Excel vba copying and pasting based on cell value code not working

So im pretty new to VBA coding, and I'm trying to setup a commandbutton that when activated copys everything from sheet "Opties" to the sheet "BOM" from the column D and F that has a 1 in column with the titel "Totaal" and remove blanks.
So far this is my code
Sub Copy()
Dim c As Integer
Dim x As Integer
Dim y As Integer
Dim ws1 As Worksheet: Set ws1 = Sheets("Optie")
Dim ws2 As Worksheet: Set ws2 = Sheets("BOM")
Dim colNum As Integer
colNum = Worksheetfuntion.Match("Totaal", ws1.Range("A1:ZZ1"), 0)
c = 1
x = -4 + colNum
y = -6 + colNum
Set rng1 = ws1.Column(colNum)
Set rng2 = ws2.Range("C5:C25000")
For Each c In ws1.rng1
rng1.Offset(0, x).Copy
rng2.Offset(0, 1).PasteSpecial xlPasteValues
rng1.Offset(0, y).Copy
rng2.Offset(0, 2).PasteSpecial xlPasteValues
Next c
End Sub
I think the following code should work:
'Try to avoid using names that Excel uses - you will sometimes "block" the
'native function, so call the subroutine "myCopy" or something else, but
'preferably not "Copy"
Sub myCopy()
Dim r1 As Long ' Use Long rather than Integer, because Excel
Dim r2 As Long ' now allows for more than 65536 rows
'Use Worksheets collection for worksheets, and only use the Sheets
' collection if you need to process Charts as well as Worksheets
Dim ws1 As Worksheet: Set ws1 = Worksheets("Optie") 'Should this be "Opties"?
Dim ws2 As Worksheet: Set ws2 = Worksheets("BOM")
Dim colNum As Long
colNum = WorksheetFunction.Match("Totaal", ws1.Range("A1:ZZ1"), 0)
r2 = 5 ' I guessed that 5 is the first row you want to write to
'Loop through every row until the last non-empty row in Totaal column
For r1 = 1 To ws1.Cells(ws1.Rows.Count, colNum).End(xlUp).Row
'See if value in Totaal column is 1
If ws1.Cells(r1, colNum).Value = 1 Then
'I have guessed that your destination columns are D & E based on
'your Offset(0, 1) and Offset(0, 2) from column C
'I have guessed that your source columns are F & D based on the
'question mentioning those columns, and the offsets of -4 and -6
'in your current code - I assume based on "Totaal" being column J
'Change my guesses as necessary
'Copy values to destination from source
ws2.Cells(r2, "D").Value = ws1.Cells(r1, "F").Value
ws2.Cells(r2, "E").Value = ws1.Cells(r1, "D").Value
'Increment row counter for destination sheet
r2 = r2 + 1
End If
Next
End Sub

Excel VBA Runtime Error '424' Object Required when deleting rows

I'm trying to compare cell values between 2 Sheets (Sheet1 & Sheet2) to see if they match, and if they match move the matching values in Sheet1 to a pre-existing list (Sheet3) and delete the values in Sheet1 afterwards.
I'm using the reverse For Loop in Excel VBA, but everything works until the part where I start deleting the row using newrange1.EntireRow.Delete.
This throws a '424' Object Required Error in VBA and I've spent hours trying to solve this, I'm not sure why this is appearing. Am I selecting the row incorrectly? The object?
Would appreciate if anyone can point me to the correct direction.
Here's my code:
Sub Step2()
Sheets("Sheet1").Activate
Dim counter As Long, unsubListCount As Long, z As Long, x As Long, startRow As Long
counter = 0
startRow = 2
z = 0
x = 0
' Count Sheet3 Entries
unsubListCount = Worksheets("Sheet3").UsedRange.Rows.Count
Dim rng1 As Range, rng2 As Range, cell1 As Range, cell2 As Range, newrange1 As Range
' Select all emails in Sheet1 and Sheet2 (exclude first row)
Set rng1 = Worksheets("Sheet1").Range("D1:D" & Worksheets("Sheet1").UsedRange.Rows.Count)
Set rng2 = Worksheets("Sheet2").Range("D1:D" & Worksheets("Sheet2").UsedRange.Rows.Count)
' Brute Loop through each Sheet1 row to check with Sheet2
For z = rng1.Count To startRow Step -1
'Cells(z, 4)
Set cell1 = Worksheets("Sheet1").Cells(z, "D")
For x = rng2.Count To startRow Step -1
Set cell2 = Worksheets("Sheet2").Cells(x, "D")
If cell1.Value = cell2.Value Then ' If rng1 and rng2 emails match
counter = counter + 1
Set newrange1 = Worksheets("Sheet1").Rows(cell1.Row)
newrange1.Copy Destination:=Worksheets("Sheet3").Range("A" & unsubListCount + counter)
newrange1.EntireRow.Delete
End If
Next
Next
End Sub
Here's the error I'm getting:
Your inner loop produces a lot of step-by-step work that is better accomplished with Application.Match. Your use of .UsedRange to retrieve the extents of the values in the D columns is better by looking for the last value from the bottom up.
Option Explicit
Sub Step2()
Dim z As Long, startRow As Long
Dim rng2 As Range, wk3 As Worksheet, chk As Variant
startRow = 2
z = 0
Set wk3 = Worksheets("Sheet3")
' Select all emails in Sheet1 and Sheet2 (exclude first row)
With Worksheets("Sheet2")
Set rng2 = .Range(.Cells(2, "D"), .Cells(.Rows.Count, "D").End(xlUp))
End With
With Worksheets("Sheet1")
For z = .Cells(.Rows.Count, "D").End(xlUp).Row To startRow Step -1
chk = Application.Match(.Cells(z, "D").Value2, rng2, 0)
If Not IsError(chk) Then
.Cells(z, "A").EntireRow.Copy _
Destination:=wk3.Cells(Rows.Count, "A").End(xlUp).Offset(1, 0)
.Cells(z, "A").EntireRow.Delete
End If
Next
End With
End Sub
As noted by Ryan Wildry, your original problem was continuing the loop and comparing after deleting the row. This can be avoided by adding Exit For after newrange1.EntireRow.Delete to jump out of the inner loop once a match was found. I don't think you should 'reset cell1' as this may foul up the loop iteration.
I think what's happening is when you are deleting the row, you are losing the reference to the range Cell1. So I reset this after the deletion is done, and removed the reference to newRange1. Give this a shot, I have it working on my end. I also formatted the code slightly too.
Option Explicit
Sub Testing()
Dim counter As Long: counter = 0
Dim z As Long: z = 0
Dim x As Long: x = 0
Dim startRow As Long: startRow = 2
Dim Sheet1 As Worksheet: Set Sheet1 = ThisWorkbook.Sheets("Sheet1")
Dim Sheet2 As Worksheet: Set Sheet2 = ThisWorkbook.Sheets("Sheet2")
Dim Sheet3 As Worksheet: Set Sheet3 = ThisWorkbook.Sheets("Sheet3")
Dim rng1 As Range: Set rng1 = Sheet1.Range("D1:D" & Sheet1.UsedRange.Rows.Count)
Dim rng2 As Range: Set rng2 = Sheet2.Range("D1:D" & Sheet2.UsedRange.Rows.Count)
Dim unsubListCount As Long: unsubListCount = Sheet3.UsedRange.Rows.Count
Dim cell1 As Range
Dim cell2 As Range
Dim newrange1 As Range
' Brute Loop through each Sheet1 row to check with Sheet2
For z = rng1.Count To startRow Step -1
Set cell1 = Sheet1.Cells(z, 4)
For x = rng2.Count To startRow Step -1
Set cell2 = Sheet2.Cells(x, 4)
If cell1 = cell2 Then
counter = counter + 1
Set newrange1 = Sheet1.Rows(cell1.Row)
newrange1.Copy Destination:=Sheet3.Range("A" & unsubListCount + counter)
newrange1.EntireRow.Delete
Set newrange1 = Nothing
Set cell1 = Sheet1.Cells(z, 4)
End If
Next
Next
End Sub

Multiple Rows and Columns to Single Column Excel

I have different data on multiple rows and columns in Excel and I want all the data to be on a single Column. I tried the Transpose Function but it's not helping me to get what I want.
This is what I have right now:
And this is what I want to get:
Can anyone kindly tell me how I can achieve that? Any built in function or Macro will be helpful. Thanks.
Try this code:
Sub RangetoColumn()
Dim LastRow As Long, LastColumn As Long
Dim CurrentSheet As Worksheet, TargetSheet As Worksheet
Dim i As Long, j As Long, Count As Long
Set CurrentSheet = ThisWorkbook.Worksheets("Sheet1")'-->change Sheet1 to your source sheet
Set TargetSheet = ThisWorkbook.Worksheets("Sheet2")'-->change Sheet2 to your target sheet
LastRow = CurrentSheet.Cells(Rows.Count, "A").End(xlUp).Row
Count = 1
For i = 1 To LastRow
LastColumn = CurrentSheet.Cells(i, Columns.Count).End(xlToLeft).Column
For j = 1 To LastColumn
TargetSheet.Range("A" & Count).Value = CurrentSheet.Cells(i, j).Value
Count = Count + 1
Next j
Next i
End Sub
Code will read Range from Sheet1 and will create a Column in Sheet2.
I think this tutorial should help you : tutorial
you can try that solution for your needs.
Try using & in both cells. Try like this A1&B1 to combine the data in cell A1 and cell B1; copy and paste, then enjoy.
this will have all current sheet cells listed down its column A and cleared all other adjacent columns
Option Explicit
Sub RangeToOneColumn()
Dim lastRow As Long, i As Long, j As Long
Dim rng As Range
Dim myArr As Variant
With ThisWorkbook.Worksheets("Sheet1") '<== change it to your needs
lastRow = .Cells(.rows.Count, "A").End(xlUp).Row
ReDim myArr(0 To lastRow - 1)
For i = 1 To lastRow
Set rng = .Range(.Cells(i, 1), .Cells(i, .Columns.Count).End(xlToLeft))
myArr(i - 1) = Application.Transpose(Application.Transpose(rng))
Next i
.Cells(1, 1).CurrentRegion.ClearContents
j = 1
For i = LBound(myArr) To UBound(myArr)
.Cells(j, 1).Resize(UBound(myArr(i))) = Application.Transpose(myArr(i))
j = j + UBound(myArr(i))
Next i
End With
End Sub
since it uses array, it runs faster than iterating a coping&pasting through cells

Compare content of rows in two different sheets if content of the first cell is true

What I am trying to do is coding a macro that compares the rows in sheet1 and sheet2 and highlights the differences. You can see the macro for that below.
My problem is that in case a row or more is added or deleted in the first sheet, all other rows shift up/down which results in a lot of cells being marked in the second sheet.
Since I have an identifier in column A I try to implement an extra line which first looks for the same identifier in sheet 1 and once found, compares the rows of sheet 1 and sheet two, which have the same identifier and then marks potential differences.
Since all my ideas have failed so far, or made the file very slow, I hope you can help me out.
Thank you very much!
Sub comparing()
Dim sh1 As Worksheet, sh2 As Worksheet
Dim rCount As Long, cCount As Long
Set sh1 = Worksheets(ActiveWorkbook.Worksheets.Count() - 1)
Set sh2 = Worksheets(ActiveWorkbook.Worksheets.Count)
rCount = sh1.Cells(Rows.Count, 1).End(xlUp).Row
cCount = sh1.Cells(1, Columns.Count).End(xlToLeft).Column
Dim r As Long, c As Integer
For r = 1 To rCount
For c = 1 To cCount
If sh1.Cells(r, c) <> sh2.Cells(r, c) Then
sh2.Cells(r, c).Interior.ColorIndex = 6
End If
Next c
Next r
Worksheets(Worksheets.Count).Select
End Sub
I haven't fully tested this, but you could use the worksheetfunction match inside your first for loop to find the corresponding Row in the second sheet:
Sub comparing()
Dim sh1 As Worksheet, sh2 As Worksheet
Dim rCount As Long, cCount As Long
Set sh1 = Worksheets(ActiveWorkbook.Worksheets.Count() - 1)
Set sh2 = Worksheets(ActiveWorkbook.Worksheets.Count)
rCount = sh1.Cells(Rows.Count, 1).End(xlUp).row
cCount = sh1.Cells(1, Columns.Count).End(xlToLeft).Column
Dim r As Long, c As Integer, sh2Row As Long
For r = 1 To rCount
'Find the matching row in Sheet2 by using the value in Column A from both sheets
sh2Row = Application.WorksheetFunction.Match(sh1.Cells(r, 1).Value, sh2.Range("A:A"))
For c = 1 To cCount
If sh1.Cells(r, c) <> sh2.Cells(sh2Row, c) Then
sh2.Cells(sh2Row, c).Interior.ColorIndex = 6
End If
Next c
Next r
Worksheets(Worksheets.Count).Select
End Sub