Looping incorrectly Excel VBA - vba

I'm trying to run a code that will search through a column, find keywords, then copy and paste those rows into another sheet. Unfortunately, when I run the code step-by-step I can see that the first time it attempts to copy and paste a row, it copies the active cell and pastes that value across the row in the next sheet, and disregards the "If Then" statement searching for the keywords. After it pastes the active cell value it works fine and pastes the correct rows, but I can't figure out why it pastes the active cell first.
Sub CompletedJob()
'Looks through the status column (N) of the Projects Overview table and moves them to Completed table, then deletes row from projects list
Dim Firstrow As Long
Dim lastRow As Long
Dim LrowProjectsOverview As Long
With Sheets("Projects Overview")
.Select
Firstrow = .UsedRange.Cells(1).Row
lastRow = .UsedRange.Rows(.UsedRange.Rows.Count).Row
For LrowProjectsOverview = lastRow To Firstrow Step -1
With .Cells(LrowProjectsOverview, "N")
If Not IsError(.Value) Then
If ((.Value = "Complete - Design") Or (.Value = "P4P") Or (.Value = "Ready for Setup")) Then .EntireRow.Select
Selection.Copy
Range("A600:Q600").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
If Sheet9.Range("B2").Value = "" Then
Sheet9.Range("A2:Q2").Value = Sheet1.Range("A600:Q600").Value
Sheet1.Range("A600:Q600").ClearContents
Else
Sheet9.Range("B2").EntireRow.Insert
Sheet9.Range("A2:Q2").Value = Sheet1.Range("A600:Q600").Value
Sheet1.Range("A600:Q600").ClearContents
Sheet9.Range("B2:Q2").Interior.Color = xlNone
Sheet9.Range("B2:Q2").Font.Bold = False
Sheet9.Range("B2:Q2").Font.Color = vbBlack
Sheet9.Range("B2:Q2").RowHeight = 14.25
End If
If Sheet9.Range("B2").Value = "" Then
Sheet9.Range("B2").EntireRow.Delete
End If
If ((.Value = "Complete - Design") Or (.Value = "P4P") Or (.Value = "Ready for Setup")) Then .EntireRow.Delete
End If
End With
Next LrowProjectsOverview
End With
End Sub

I tried to recreate your problem. My code is not a direct solution for you. You need to adapt it to your problem. This is important because this is how you learn to code.
I tried my very best to comment my code as heavily as possible. I am not referencing sheets, please add this since you are trying to copy from one sheet to another.
I don't need any select statement.
This is my vba code.
Option Explicit
Sub SearchKeyandCopy()
Dim LastLine As Long
Dim i As Long
Dim j As Long
'Find Number of Rows in Status column (column D)
LastLine = Columns("D").Find("*", , , , xlByColumns, xlPrevious).Row
'Set row where it should start pasting
j = 2
'Iterate over all cells with status
For i = 2 To LastLine
'Check if the Keyword (Key) is in Status column
'InStr returns the position and 0 if not found
'code checks if position is different from 0
If InStr(Cells(i, "D").Value, "key") <> 0 Then
'Copy values
Range(Cells(i, "A"), Cells(i, "D")).Copy Destination:=Range(Cells(j, "F"), Cells(j, "I"))
'increase counter for where to paste
j = j + 1
End If
Next i
End Sub
This is how it looks before running the code
This is how it looks after running the code

Related

macro: copy paste cell if condition met

There’s one step that’s stuck, to update the stock number (column "D") in the database_ gudang (stock in the database_ gudang is added to the amount of receipt (column "K") from form_penerimaan)
The update is based on the name of the item (nama barang), so if the name of the item (column "C") in the form_penerimaan is the same as the name of the item (column "B") in the database_ gudang, the stock in database_ gudang will be updated.
but there’s a problem, which is updated only in rows 2,9,10 (yellow cell). A row of 3,4,5 should also be updated.
Thank you very much for your help.
Regards.
Sub Module1()
s = 10
OT1 = Sheets("Database_Gudang").Cells(Rows.Count, "D").End(xlUp).Row
For j = 2 To OT1
NB1 = Sheets("Database_Gudang").Cells(j, "B").Value
Sheets("Form_Penerimaan").Activate
If Cells(s, "C").Value = NB1 And Cells(s, "C").Value <> "" Then
Sheets("Form_Penerimaan").Cells(s, "Q").Copy
Sheets("Database_Gudang").Activate
Sheets("Database_Gudang").Cells(j, "G").Select
Selection.PasteSpecial Paste:=xlPasteValues
s = s + 1
End If
Next j
End Sub
Hi and Welcome to stackoverflow :)
Avoid the use of .Select and .Activate. Directly work with variables and objects. You may want to see How to avoid using Select in Excel VBA
You are facing that issue because you are not looping through the cells of the 2nd sheet.
Is this what you are trying? (UNTESTED)
I have commented the code so you may not have a problem in understanding it. If you do then share the exact error message and we will take it from there.
Sub Sample()
Dim wsThis As Worksheet, wsThat As Worksheet
Dim i As Long, j As Long
Dim wsThisLRow As Long, wsThatLRow As Long
'~~> Set your worksheets
Set wsThis = ThisWorkbook.Sheets("Database_Gudang")
Set wsThat = ThisWorkbook.Sheets("Form_Penerimaan")
'~~> Find relevant last row in both sheets
wsThisLRow = wsThis.Range("D" & wsThis.Rows.Count).End(xlUp).Row
wsThatLRow = wsThat.Range("C" & wsThat.Rows.Count).End(xlUp).Row
With wsThis
'~~> Loop through cell in Database_Gudang
For i = 2 To wsThisLRow
'~~> Loop through cell in Form_Penerimaan
For j = 10 To wsThatLRow
'~~> Compare values and get values across if applicable
If .Range("B" & i).Value = wsThat.Range("C" & j).Value Then
.Range("G" & i).Value = wsThat.Range("Q" & j).Value
Exit For
End If
Next j
Next i
End With
End Sub

Creating a loop for a range of rows for a code that runs for a single row

I am building a macro which will create an automatic report (the name of the report sheet is "RCCP INPUT"), by extracting data from another worksheet (source which is named "CW33 17"). I have build the code that runs for a single row of the source sheet, so it creates the report for only one row (every row represents an order). I want to have a report for a range of rows so I need to extend my code to apply for a range of rows. So, lets say that this range is called myRange and it includes rows 2 to 70. So, my report must have all these rows. My code is provided below. I have included the headers too, so the report starts from row 2. The row that the macro runs for, for now is row 2. Just to clarify it more, the report must have each row that is selected from the source multiplied by 6 (6 copies, one below the other) as it can be seen from the macro below, because in the Forecast column and Forecast Quantity column, each order(row) must have values for 6 weeks. I hope I have clarified it well! Any ideas how to make it work?.. I have failed miserably so far.. Much appreciated!
The report looks like this (for one row - as it is multiplied by 6) and the other rows should be placed in the same way underneath.
Sub RCCP_INPUT()
Sheets("RCCP INPUT").Select
range("C1").Value = "T-Lane ID" 'Column C
range("D1").Value = "Week of RCCP" 'Column D
range("E1").Value = "Forecast" 'Column E
range("F1").Value = "Forecast Quantity" 'Column F
Sheets("CW33 17").Select
range("D2:E2").Copy
Sheets("RCCP INPUT").Select
range("A2").Select
ActiveSheet.Paste
Dim rws As Long
With range("A2:B2")
rws = .Rows.Count
.Resize(rws).Copy Destination:=.Offset(rws).Resize(rws * 5)
End With
range("C2").Select
ActiveCell.FormulaR1C1 = "=CONCATENATE(RC[-2],RC[-1])"
ActiveCell.Value = ActiveCell.Value
With range("C2")
rws = .Rows.Count
.Resize(rws).Copy Destination:=.Offset(rws).Resize(rws * 5)
End With
Sheets("CW33 17").Select
range("G2:L2").Select
Selection.Copy
Sheets("RCCP INPUT").Select
range("F2:F7").Select
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:=False, Transpose:=True
Sheets("RCCP INPUT").Select
i = 1
For Each cell In range("E2:E7")
cell.Value = "Week +" & i
i = i + 1
Next cell
Sheets("RCCP INPUT").Select
range("E2").Value = Sheets("CW33 17").range("G2").Value - 1
With range("E2")
rws = .Rows.Count
.Resize(rws).Copy Destination:=.Offset(rws).Resize(rws * 5)
End With
End Sub
In order to generalize your code you need to move away from absolute addresses somehow. One way is to assign ranges and then offset them as needed to get to the positions you need. The code below runs through numNeeded number of times and keeps adding directly below as you mention. I don't know anything about the source data after the first time through so it just repeats the first set of data right now. But you can draw new data from different sheets or use offsets on the source sheet to grab new data for each time through. I've put many r.select statements in the code so that you can step through and easily see what the code is doing, but these should be removed once you understand.
Sub reportGen()
Dim destSh As Worksheet, sourceSh As Worksheet
Dim sourceR1 As Range, sourceR2 As Range
Dim r As Range, pasteR As Range
Const numNeeded = 10
Set sourceSh = Worksheets("CW33 17")
Set sourceR1 = sourceSh.Range("D2:E2")
Set sourceR2 = sourceSh.Range("G2:L2")
Set destSh = Worksheets("RCCP INPUT")
Set r = destSh.Range("A1").Offset(7 * j, 0)
r.Select
r.Offset(0, 2) = "T-Lane ID"
r.Offset(0, 3) = "Week of RCCP"
r.Offset(0, 4) = "Forecast"
r.Offset(0, 5) = "Forecast Quantity"
For j = 0 To numNeeded
Set r = destSh.Range("A2").Offset(j * 6, 0)
r.Select
sourceR1.Copy
destSh.Paste
Set pasteR = Selection
pasteR.AutoFill destSh.Range(pasteR, pasteR.Offset(5, 0))
Set r = r.Offset(0, 2)
r.Select
r.FormulaR1C1 = "=CONCATENATE(RC[-2],RC[-1])"
r = r.Value
r.AutoFill destSh.Range(r, r.Offset(5, 0))
Set r = r.Offset(0, 3)
r.Select
sourceR2.Copy
r.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:=False, Transpose:=True
Set r = r.Offset(0, -1)
r.Select
For i = 1 To 6
r.Offset(i - 1, 0) = "Week +" & i
Next i
r = sourceR2(1) - 1
r.AutoFill destSh.Range(r, r.Offset(5, 0))
r.Select
Next j
End Sub
(By the way, I think there might be a mistake starting after your For Each cell... loop since it writes over data, but I wasn't sure so just kept it the way you have it)

Excel/VBA - Extracting a range of rows from a selected sheet to a new book

I'm trying to build a new VBA function for Excel. I've got a book of sheets with a front page that always loads first, on this page I've got a combo box that lists all the other sheets in the book and a nice extract button that will pull out the chosen sheet to a new book. (Thanks to those here who helped with that). Now I need a new function that will use the same combo box, but instead only extract a small subset of the chosen sheet.
Unfortunately, that subset isn't on the same rows for every sheet, nor is the number of rows the same (so one sheet, the subset might be 10 rows, on another it might be 12, on another it might be 20, etc etc etc).
On the plus side, there are merged rows (from column A to G) at the start and end of each subset - with specific text, which could be used to search for.
After some back and forth, I've got a better bit of code that I think is almost working:
Sub ZCPS_Extract()
Dim StartRow
Dim EndRow
Dim Zws As Worksheet
Dim wbkOriginal As Workbook
Set wbkOriginal = ActiveWorkbook
StartRow = 1
EndRow = 1
'sets site details into the header of the ZCPS checksheet
Worksheets(Sheet1.CmbSheet.Value).Range("B3").Value = Worksheets("front page").Range("E6")
Worksheets(Sheet1.CmbSheet.Value).Range("D3").Value = Worksheets("front page").Range("N6")
Worksheets(Sheet1.CmbSheet.Value).Range("F3").Value = Worksheets("front page").Range("K6")
Set Zws = Sheets(Sheet1.CmbSheet.Value)
'selects ZCPS block from select estate sheet
StartRow = (Zws.Cells.Find("**** ZCPS Installation").Row) + 1
EndRow = (Zws.Cells.Find("**** Aztec Hotfixes").Row) - 1
'copy above block and paste into Z-MISC starting at row 5
Worksheets(Sheet1.CmbSheet.Value).Range(Cells(StartRow, 1), Cells(EndRow, 7)).Copy Worksheets("Z-MISC").Range("A5")
With ActiveWorkbook.Sheets("Z-MISC")
.Copy
ActiveWorkbook.SaveAs _
"C:\temp\" _
& ActiveWorkbook.Sheets("Z-MISC").Cells(3, 2).Text _
& " ZCPS CheckSheet " _
& Format(Now(), "DD-MM-YY") _
& ".xlsm", _
xlOpenXMLWorkbookMacroEnabled, , , , False
End With
'code to close the original workbook to prevent accidental changes etc
Application.DisplayAlerts = False
wbkOriginal.Close
Application.DisplayAlerts = True
End Sub
It's error on the line for copying, I'm getting a runtime error of "Application-defined or object-defined error" which to my limited knowledge isn't helping me. Any assistance/pointers/suggestions are welcomed.
Sub ismerged()
Dim start As Integer, finish As Integer
For i = 1 To Range("A655").End(3).Row + 1
If Cells(i, "A").MergeCells = True Then
start = i
Exit For
End If
Next
For i = start To Range("A655").End(3).Row + 1
If Cells(i, "A").MergeCells = True Then
finish = i
End If
Next
MsgBox start
MsgBox finish
End Sub
Then I guess you can select your data as you wish.
I'm not sure about the way you reference your sheet. I will assume 'comboboxvalue' contains the name or the number of the sheet you are selecting. Your code should be something like the following.
Sub Z_Extract()
Dim StartRow
Dim EndRow
Dim ws As Worksheet
Set ws = Sheets(comboboxvalue)
StartRow = ws.Cells.Find("**** ZC").Row
EndRow = ws.Cells.Find("****").Row
'Im assuming you have values up to column G
ws.Range(ws.Cells(StartRow, 1), Cells(EndRow, 7)).Copy
'Now that you have the correct Range selected you can copy it to your new workbook
'SelectedRange.Copy Etc.....
'Cleanup
Set ws = Nothing
End Sub
Got it working.
Set Zws = Sheets(Sheet1.CmbSheet.Value)
'selects ZCPS block from selected estate sheet
StartRow = (Zws.Cells.Find("**** ZCPS Installation").Row)
EndRow = (Zws.Cells.Find("**** Aztec Hotfixes").Row) - 1
'copy above block and paste into Z-MISC starting at row 10
Sheets(Sheet1.CmbSheet.Value).Activate
ActiveSheet.Range(Cells(StartRow, 1), Cells(EndRow, 7)).Select
Selection.Copy
Sheets("Z-MISC").Select
Range("A10").Select
ActiveSheet.Paste

VBA: copying the first empty cell in the same row

I am a new user of VBA and am trying to do the following (I got stuck towards the end):
I need to locate the first empty cell across every row from column C to P (3 to 16), take this value, and paste it in the column B of the same row.
What I try to do was:
Find non-empty cells in column C, copy those values into column B.
Then search for empty cells in column B, and try to copy the first non-empty cell in that row.
The first part worked out fine, but I am not too sure how to copy the first non-empty cell in the same row. I think if this can be done, I might not need the first step. Would appreciate any advice/help on this. There is the code:
Private Sub Test()
For j = 3 To 16
For i = 2 To 186313
If Not IsEmpty(Cells(i, j)) Then
Cells(i, j - 1) = Cells(i, j)
End If
sourceCol = 2
'column b has a value of 2
RowCount = Cells(Rows.Count, sourceCol).End(xlUp).Row
'for every row, find the first blank cell, copy the first not empty value in that row
For currentRow = 1 To RowCount
currentRowValue = Cells(currentRow, sourceCol).Value
If Not IsEmpty(Cells(i, 3)) Or Not IsEmpty(Cells(i, 4)) Or Not IsEmpty(Cells(i, 5)) Or Not IsEmpty(Cells(i, 6)) Then
Paste
~ got stuck here
Next i
Next j
End Sub
Your loop is really inefficient as it is iterating over millions of cells, most of which don't need looked at. (16-3)*(186313-2)=2,422,043.
I also don't recommend using xlUp or xlDown or xlCellTypeLastCell as these don't always return the results you expect as the meta-data for these cells are created when the file is saved, so any changes you make after the file is saved but before it is re-saved can give you the wrong cells. This can make debugging a nightmare. Instead, I recommend using the Find() method to find the last cell. This is fast and reliable.
Here is how I would probably do it. I'm looping over the minimum amount of cells I can here, which will speed things up.
You may also want to disable the screenupdating property of the application to speed things up and make the whole thing appear more seemless.
Lastly, if you're new to VBA it's good to get in the habit of disabling the enableevents property as well so if you currently have, or add in the future, any event listeners you will not trigger the procedures associated with them to run unnecessarily or even undesirably.
Option Explicit
Private Sub Test()
Dim LastUsed As Range
Dim PasteHere As Range
Dim i As Integer
Application.ScreenUpdating=False
Application.EnableEvents=False
With Range("B:B")
Set PasteHere = .Find("*", .Cells(1, 1), xlFormulas, xlPart, xlByRows, xlPrevious, False, False, False)
If PasteHere Is Nothing Then Set PasteHere = .Cells(1, 1) Else: Set PasteHere = PasteHere.Offset(1)
End With
For i = 3 To 16
Set LastUsed = Cells(1, i).EntireColumn.Find("*", Cells(1, i), xlFormulas, xlPart, xlByRows, xlPrevious, False, False, False)
If Not LastUsed Is Nothing Then
LastUsed.Copy Destination:=PasteHere
Set PasteHere = PasteHere.Offset(1)
End If
Set LastUsed = Nothing
Next
Application.ScreenUpdating=True
Application.EnableEvents=True
End Sub
Sub non_empty()
Dim lstrow As Long
Dim i As Long
Dim sht As Worksheet
Set sht = Worksheets("Sheet1")
lstrow = sht.Cells(sht.Rows.Count, "B").End(xlUp).Row
For i = 1 To lstrow
If IsEmpty(Range("B" & i)) Then
Range("B" & i).Value = Range("B" & i).End(xlToRight).Value
End If
Next i
End Sub

How to autofilter column 1 and return related results in column 2

This is my first post. I am new to VBA and programming in general. I am still trying to get the hang of when to use variables and everything else. I am writing a basic VBA against a download file that can not be changed. Code is below
Sub KPIMacroFull()
Set sht = ThisWorkbook.Worksheets(Sheet1.Name)
Rows("1:2").Select
Selection.Delete Shift:=xlUp
ActiveCell.Offset(0, 9).Activate
Range("J:J").AutoFilter 1, 20
lr = Cells(Rows.Count, "J").End(xlUp).Row
If lr > 1 Then
Range("A2:A" & lr).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End If
Cells.AutoFilter
Cells.AutoFilter
ActiveCell.Offset(0, 0).Activate
ActiveCell.Offset(0, 20).Activate
Range("AD1").EntireColumn.Insert
Range("AD1").Value = "Rush or Regular"
Range("A1:AK1").Columns.AutoFit
Range("AC:AC").AutoFilter 29, "D"
So basically what I want to do is autofilter column AC for values "D","K","Q","V","U",1,9. then in Column AD excel would return "Regular". For all other values in column AC (there are about 15 more classifications) I want excel to return "Rush". I am thinking a variable to set Regular to the above values and then going from there, but I am lost.
I checked a lot of other autofilter and VBA posts, but my questions seems to be more rudimentary and have not found anything too helpful.
This sniplet is independent from your solution as that relies too much on views.
My sniplet parses through your "AC" column and does all your required fill-in.
It is time-consuming, but not as much as yours (I assume you're not working on 100,000 record datasets, more like couple-hundred line evaluations of MMOs so it really shouldn't matter).
Filtering itself is up to you, add that part to the end of my sub.
Sub ertdfgcvb()
LastRow = Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Dim RegBool As Boolean
Dim ert As String
Dim MyArray(6) As String
MyArray(0) = "D"
MyArray(1) = "K"
MyArray(2) = "Q"
MyArray(3) = "V"
MyArray(4) = "U"
MyArray(5) = "1"
MyArray(6) = "9"
For i = 1 To LastRow
RegBool = False
ert = CStr(Cells(i, 29).Value) 'the CStr is unnecessary
'unless you want to make it case-insensitive, in which case
'you'll want to wrap it in a UCase() function
For j = 0 To 6 'size of your array
If InStr(1, ert, MyArray(j)) <> 0 Then RegBool = True
Next
If RegBool Then
Cells(i, 30) = "Regular"
Else
Cells(i, 30) = "Rush"
End If
Next
End Sub