Why does my code only copy the latest row in the loop as many times as the loop has met the condition, instead of every row that meets the condition - excel

Sub CopyRow()
'Declare variables
Dim sheetNo1 As Worksheet
Dim sheetNo2 As Worksheet
Dim FinalRow As Long
Dim Cell As Range
'Set variables
Set sheetNo1 = Sheets("EA Log")
Set sheetNo2 = Sheets("Commitments")
' Define destination sheets to move row
FinalRow1 = sheetNo2.Range("A" & sheetNo2.Rows.Count).End(xlUp).Row + 1
'Apply loop for column P until last cell with value
For Each Cell In sheetNo1.Range("P4:P" & sheetNo1.Cells(sheetNo1.Rows.Count, "P").End(xlUp).Row)
'Apply condition to match the "Signed" value
If Cell.Value = "Signed" Then
'Command to Copy and move to a destination Sheet "Commitments"
sheetNo1.Range(sheetNo1.Cells(Cell.Row, 2), sheetNo1.Cells(Cell.Row, 3)).Copy _
Destination:=sheetNo2.Range("A4:A" & FinalRow1)
sheetNo1.Range(sheetNo1.Cells(Cell.Row, 14), sheetNo1.Cells(Cell.Row, 14)).Copy _
Destination:=sheetNo2.Range("C4:C" & FinalRow1)
sheetNo1.Range(sheetNo1.Cells(Cell.Row, 1), sheetNo1.Cells(Cell.Row, 1)).Copy _
Destination:=sheetNo2.Range("E4:E" & FinalRow1)
sheetNo1.Range(sheetNo1.Cells(Cell.Row, 25), sheetNo1.Cells(Cell.Row, 25)).Copy _
Destination:=sheetNo2.Range("D4:D" & FinalRow1)
FinalRow1 = FinalRow1 + 1
End If
Next Cell
Application.ScreenUpdating = True
End Sub

Related

Looping Through 2 Columns & Copying 2nd Column's Data Under the First

I am trying to create a list with 2 columns by placing the values from the 2nd column under the first on a new tab. In my screenshot I have column A "Data 1" and column B "Data 2". Each value under Data 1 has a corresponding value under Data 2. I am trying to make it look like the Second Tab column where the value under Data 1 is copied over first then Data 2 is Copied underneath. There are blanks in between values so im trying to figure out a way to capture all the data excluding the blanks so its 1 organized list. I have tried the following so far but i cant figure it out:
Sub MoveData()
Dim wb As Workbook: Set wb = ThisWorkbook
For i = 1 To 15
wb.Sheets("Sheet1").Range("A2:A" & i).Copy Destination:=wb.Sheets("Sheet2").Range("A1")
wb.Sheets("Sheet1").Range("A2:A" & i).Offset(0, 1).Copy _
Destination:=wb.Sheets("Sheet2").Range("A2" & lastrow).Offset(1, 0)
wb.Sheets("Sheet1").Range("A2:A" & i).Offset(0, 1).Copy _
Destination:=wb.Sheets("Sheet2").Range("A2:A" & i).Offset(1, 0)
Next i
End Sub
With the help of the following function you will find the last non empty row in column 1
Function FindLastRow(rg As Range) As Long
On Error GoTo EH
FindLastRow = rg.Find("*", , Lookat:=xlPart, LookIn:=xlFormulas _
, searchorder:=xlByRows, searchdirection:=xlPrevious).Row
Exit Function
EH:
FindLastRow = rg.Cells(1, 1).Row
End Function
Then you can copy the data into worksheet 2 with the following code
Sub pasteData()
Dim wks1 As Worksheet
Set wks1 = Worksheets("Sheet1")
Dim lastRow As Long
lastRow = FindLastRow(wks1.Columns(1)) ' last non empty row in column 1
Dim rg As Range
Set rg = wks1.Range("A1:B" & lastRow) 'range with the data in question
Dim vdat As Variant
vdat = rg.Value ' copy the data into an arry
' dim array which is big enough for the result
Dim rDat As Variant
ReDim rDat(0 To 2 * lastRow)
' copy the data from the 2-dim array into 1-dim array
Dim i As Long, j As Long
For i = LBound(vdat) To UBound(vdat)
' copy only data where the first column contains data
If Len(vdat(i, 1)) > 0 Then
rDat(j) = vdat(i, 1)
rDat(j + 1) = vdat(i, 2)
j = j + 2
End If
Next i
Dim wks2 As Worksheet
Set wks2 = Worksheets("Sheet2")
' prepare the second range (bigger than needed but does not harm)
Set rg = wks2.Range("A1:A" & 2 * lastRow)
' copy the data into the second sheet
rg = WorksheetFunction.Transpose(rDat)
End Sub

copy, paste, transpose rows with pictures

I have a macro that copies and pastes rows from input sheet to output sheet. I find PRODUCT NAME and END DATE, then copy the whole row and transpose when pasting it. I am using transpose because I want to have vertical table.
I have a problem with images because I don't know how to copy them to proper cell so they match with Name and Date. I've managed to write a script that is copying and pasting images but it puts all of them in cell A1. When I want to add range to target_sheet.Paste I am getting vba method intersect of object _application failed error.
Below you can see how input and output sheets look.
Input sheet:
Expected output sheet (with only 3 columns) :
It is very important to know that 'input' sheet contains many products with names, prices and images and there is always a blank row between them. The number of images in each row can be different (from 1 to 25).
Sub copy_paste()
Dim Cell As Range
Dim src_rng As String
Dim LR As Long
Dim source_sheet As Worksheet
Dim target_sheet As Worksheet
Dim pic As Shape
'worksheet with source data
Set source_sheet = ThisWorkbook.Sheets("input")
'worksheet with newly created template
Set target_sheet = ThisWorkbook.Sheets("output")
'range of cells I want to check
src_rng = "A14:A26"
Application.ScreenUpdating = False
target_sheet.Cells.Delete
'copy paste, transpose product line rows
For Each Cell In source_sheet.Range(src_rng)
LR = target_sheet.Range("A10000").End(xlUp).Row + 1
If Cell.Value = "Name" Then
Cell.EntireRow.Copy
target_sheet.Range("A" & LR).PasteSpecial Paste:=xlPasteValues, Transpose:=True
End If
Next
'copy paste, transpose end line rows
For Each Cell In source_sheet.Range(src_rng)
LR = target_sheet.Range("B10000").End(xlUp).Row + 1
If Cell.Value = "Date" Then
Cell.EntireRow.Copy
target_sheet.Range("B" & LR).PasteSpecial Paste:=xlPasteValues, Transpose:=True
End If
Next
'copy paste image
For Each Cell In source_sheet.Range(src_rng)
LR = target_sheet.Range("C10000").End(xlUp).Row + 1
If Cell.Value = "Image" Then
For Each pic In source_sheet.Shapes
If Not Application.Intersect(pic.TopLeftCell, Range(src_rng)) Is Nothing Then
pic.CopyPicture
target_sheet.Paste
End If
Next pic
End If
Next
Application.ScreenUpdating = True
End Sub
Please, try the next code. It follows the logic deduced from your last question edit, respectively: the former "Name" becomes "Product Name", "Date" becomes "End Date" and the row keeping the pictures is the one below "Product Name" row. It is able to process two or three product names/pictures per group:
Sub copy_paste()
Dim Cell As Range, src_rng As String, LR As Long
Dim source_sheet As Worksheet, target_sheet As Worksheet
Dim pic As Shape, arrPAddr, rngTr As Range, k As Long
Dim cellRHeight As Range, nrShapesPerRange As Long 'to be 2 or 3
nrShapesPerRange = 2 'Choose here initial number of shapes per row (2 or 3)
'worksheet with source data
Set source_sheet = ThisWorkbook.Sheets("input")
'worksheet with newly created template
Set target_sheet = ThisWorkbook.Sheets("output")
'range of cells I want to check
src_rng = "A14:A26"
Application.ScreenUpdating = False
ReDim arrPAddr(1 To 2, 1 To source_sheet.Shapes.count): k = 1
target_sheet.cells.Delete: For Each pic In target_sheet.Shapes: pic.Delete: Next
'copy paste, transpose product line rows
For Each Cell In source_sheet.Range(src_rng)
LR = target_sheet.Range("A" & rows.count).End(xlUp).row + 1
If Cell.value = "Product Name" Then
source_sheet.Range(Cell.Offset(, 1), Cell.Offset(, 3)).Copy
Set rngTr = target_sheet.Range("A" & LR)
rngTr.PasteSpecial Paste:=xlAll, Transpose:=True
arrPAddr(1, k) = Cell.Offset(1, 1).Address
arrPAddr(2, k) = rngTr.Offset(, 2).Address: k = k + 1
arrPAddr(1, k) = Cell.Offset(1, 2).Address
arrPAddr(2, k) = rngTr.Offset(1, 2).Address: k = k + 1
If nrShapesPerRange = 3 Then
arrPAddr(1, k) = Cell.Offset(1, 3).Address
arrPAddr(2, k) = rngTr.Offset(2, 2).Address: k = k + 1
End If
If cellRHeight Is Nothing Then Set cellRHeight = Cell.Offset(1)
End If
LR = target_sheet.Range("B" & rows.count).End(xlUp).row + 1
If Cell.value = "End Date" Then
source_sheet.Range(Cell.Offset(, 1), Cell.Offset(, 3)).Copy
Set rngTr = target_sheet.Range("B" & LR)
rngTr.PasteSpecial Paste:=xlAll, Transpose:=True
End If
Next
ReDim Preserve arrPAddr(1 To 2, 1 To k - 1)
'Making the row height in target_sheet equal to source_sheet column with:
target_sheet.Range("2:" & LR + 3).EntireRow.RowHeight = source_sheet.Range("A16").EntireRow.RowHeight
target_sheet.Range("A:C").EntireColumn.AutoFit
target_sheet.Range("C1").EntireColumn.ColumnWidth = cellRHeight.EntireColumn.ColumnWidth
'copy paste image:
Dim i As Long
For Each pic In source_sheet.Shapes
For i = 1 To UBound(arrPAddr, 2)
If pic.TopLeftCell.Address = arrPAddr(1, i) Then
pic.Copy: target_sheet.Paste
With target_sheet.Shapes(target_sheet.Shapes.count)
.top = target_sheet.Range(arrPAddr(2, i)).top + (target_sheet.Range(arrPAddr(2, i)).RowHeight - pic.height) / 2
.left = target_sheet.Range(arrPAddr(2, i)).left
End With
Exit For
End If
Next i
Next
Application.ScreenUpdating = True
target_sheet.Activate
MsgBox "Ready..."
End Sub
Plese, test the code and send some feedback

how to fix Object variable or with block variable not set

Am newbie to VBA and trying to find dupliactes on column A and copy Column A, G and I to another sheet and used below code
Dim wstSource As Worksheet, _
wstOutput As Worksheet
Dim rngMyData As Range, _
helperRng As Range, _
unionRng As Range
Dim i As Long, iOld As Long
Set wstSource = Worksheets("Final Product List")
Set wstOutput = Worksheets("INN Working")
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
With wstSource
Set rngMyData = .Range("A2:A" & .Range("A" & .Rows.Count).End(xlUp).Row)
End With
With rngMyData
Set helperRng = .Offset(, rngMyData.Columns.Count - 1).Resize(, 1)
Set unionRng = .Cells(1000, 1000) 'set a "helper" cell to be used with Union method, to prevent it from failing the first time
End With
With helperRng
.FormulaR1C1 = "=row()" 'mark rows with ad ascending number (its own row number)
.Value = .Value
End With
With rngMyData.Resize(, rngMyData.Columns.Count + 1) 'enclose "helper" column
.Sort key1:=.Columns(1), Order1:=xlAscending, Orientation:=xlTopToBottom, Header:=xlNo ' sort data to have all same columnA values grouped one after another
i = .Rows(1).Row 'start loop from data first row
Do While i < .Rows(.Rows.Count).Row
iOld = i 'set current row as starting row
Do While .Cells(iOld + 1, 1) = .Cells(iOld, 1) 'loop till first cell with different value
iOld = iOld + 1
Loop
If iOld - i > 0 Then Set unionRng = Union(unionRng, .Cells(i, 1).Resize(iOld - i + 1)) 'if more than one cell found with "current" value, then add them to "UnionRng" range
i = iOld + 1
Loop
Intersect(unionRng, rngMyData).EntireRow.Copy Destination:=wstOutput.Cells(1, 1) 'get rid of the "helper" cell via Intersect method
wstOutput.Columns(helperRng.Column).Clear 'delete "Helper" column pasted in wstOutput sheet
.Sort key1:=.Columns(4), Order1:=xlAscending, Orientation:=xlTopToBottom, Header:=xlNo ' sort data in wstSource back
End With
helperRng.Clear 'delete "helper" column, not needed anymore
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
The above code is throwing RunTime error '91'
Object variable or with block variable not set
If iOld - i > 0 Then Set unionRng = Union(unionRng, .Cells(i, 1).Resize(iOld - i + 1)) 'if more than one cell found with "current" value, then add them to "UnionRng" range
i = iOld + 1
End If
The End If was missing and VBA gives a poor message.

Copying values from one sheet based on condition to another workbook

I've written some code that assigns each item in a list a code based on row #. What I want to do from there is choose a copy all information from each row that corresponds with a chosen code, then paste it to another workbook. I've been having some trouble. Here's the code:
Sub LSHP_Distribute()
Dim wbLSHP As Workbook
Dim wsLSHP As Worksheet
Dim CodeRange As Range
Dim FirstRow As Long
Dim LastRow As Long
Dim wbTEST As Workbook
Set wbLSHP = ActiveWorkbook
Set wsLSHP = wbLSHP.Sheets("Sheet1")
'Generate codes for newly added items
Application.ScreenUpdating = False
'Turn off screen updating
With wsLSHP
FirstRow = .Range("F3").End(xlDown).Row + 1
LastRow = .Range("B6", .Range("B6").End(xlDown)).Rows.Count + 5
Set CodeRange = .Range("$F$" & FirstRow, "$F$" & LastRow)
End With
For Each cell In CodeRange
If cell = "" Then
If cell.Row Mod 3 = 0 Then
cell.Value = "1"
ElseIf cell.Row Mod 3 = 1 Then
cell.Value = "2"
ElseIf cell.Row Mod 3 = 2 Then
cell.Value = "3"
Else
End If
End If
Next cell
'Open Spreadsheets to Distribute Items
Dim PasteRow As Long
Dim i As Integer
Set wbTEST = Workbooks.Open(Filename:="V:\Test.xlsx")
PasteRow = wbTEST.Sheets("Sheet1").Range("B6").End(xlDown).Row + 1
Below is where I'm having the problem
wbLSHP.Activate
For Each cell In CodeRange
If cell = "1" Then
Range(ActiveCell.Offset(0, -5), ActiveCell.Offset(0, 20)).Select
Selection.Copy
wbTEST.Sheets("Sheet1").Cells(PasteRow, 1).PasteSpecial xlPasteValues
PasteRow = PasteRow + 1
Else
End If
Next cell
End Sub
First problem is the For loop isn't copying the correct range in "CodeRange", the second problem is it only copies once before I get an Automation Error. Let me know if you have any questions, or know of a more efficient way to write this code.
Thanks so much for your time!
Your range is defined to Start in F3 and end in BSomething, but you store to CodeRange only the F column.
Set CodeRange = .Range("$F$" & FirstRow, "$F$" & LastRow)
Try using:
Set CodeRange = .Range("$B$" & FirstRow, "$F$" & LastRow)
I suggest instead of Copy and Paste, assign the value to a variable and put the value of the variable on wbTEST.

How do I use a loop to paste my selected "text" into cells?

I'm trying to input text for example "code" into a column, using the Counta formula in two cells in my historic tab.
mystart and mystop both have Counta formulas in the cells and I want to paste the word "code" for example in all the cells between the two values, but I don't how to finish my code.
The text "code" will change thought out my code to something else
Sub MON_ImportHistory()
Sheets("Historic").Range("B2:AZ3000").ClearContents
'
If Worksheets("Help").Cells(18, 9) = "Data already present" Then
MsgBox ("Import aborted: Data for selected date already present")
Else
Dim myRange As Range
Dim NumRows As Integer
Dim myCopyrange As Range
Dim mystart As Range
Dim mystop As Range
m_import = Worksheets("Help").Cells(17, 9)
m_criteria = "=" & m_import
Workbooks.Open Filename:= _
"file on my data base"
Sheets("Historic").Select
If Application.WorksheetFunction.CountIf(Range("A:A"), m_import) > 0 Then
m_Filterrange = "$A$1:$AV$" & Trim(Str(Worksheets("Historic").Cells(1, 18) - 1))
ActiveSheet.Range(m_Filterrange).AutoFilter Field:=1, Criteria1:= _
m_criteria, Operator:=xlAnd
m_extractrange = "$A$90000:$AV$" & Trim(Str(Worksheets("Historic").Cells(1, 18) - 1))
Range(m_extractrange).Select
Selection.Copy
Windows("My File name").Activate
Sheets("Historic").Select
mystart = Worksheets("Historic").Cells(1, 19)
mystop = Worksheets("Historic").Cells(1, 20)
For x = mystart To mystop
myDestination = "B" & Trim(Str(Worksheets("Historic").Cells(1, 19)))
Range(myDestination).Select
ActiveSheet.Paste
Windows("My file name").Activate
There's a lot going on here...First, it looks like you are using CountA formulas in the worksheet to do what you should be doing in VBA. There is a lot of work around being done to make that work. You are probably getting an error on the second line because you are trying to clear the contents of a sheet that has not been opened yet. To find the number of occupied rows in a column you can use LastRow = Sheets("Historic").Cells(Rows.Count,1).End(xlUp).Row. You should try to minimize or eliminate the use of Select and Activate. If you try to clean that up it may make more sense to you and me. Don't forget to end the loop with Next x.
Sub MON_ImportHistory()
Dim LastRow, LastCol As Integer
Dim ws1, ws2 As Worksheet
Dim m_import As String
Dim x As Integer
Set ws1 = Worksheets("Help")
'
If ws1.Cells(18, 9) = "Data already present" Then
MsgBox ("Import aborted: Data for selected date already present")
Exit Sub
Else
Workbooks.Open "C:\Somefile.xlsx" 'Here is where you put your filename
Set ws2 = Workbooks("Somefile.xlsx").Worksheets("Historic")
LastRow = ws2.Cells(Rows.Count, 1).End(xlUp).Row
LastCol = ws2.Cells(1, Columns.Count).End(xlToLeft).Column
ws2.Range(ws2.Cells(2, 2), ws2.Cells(LastRow, LastCol)).ClearContents
m_import = ws1.Cells(17, 9)
For x = 2 To LastRow
ws2.Cells(x, 2) = m_import
Next x
End If
End Sub

Resources