I have source data which are not aligned to table.
I want to find text (e.g. Account), copy the two whole lines below the cell with the found text (Account) and paste them on a different Sheet. Then search down and do again until the data ends. Data should be pasted in the order it is reached.
The cell with word "Account" will be always in the column A. The search should be for the exact word "Account", because in the column can be cells which contain e.g. "Payer account".
This code shows me an error msg
"Run-time error 438 - object doesnt support this property or method"
Private Sub Search_n_Copy()
Dim LastRow As Long
Dim rng As Range, C As Range
With Worksheets("INPUT_2") ' <-- here should be the Sheet's name
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row ' last row in column A
Set rng = .Range("A1:A" & LastRow) ' set the dynamic range to be searched
' loop through all cells in column A and copy below's cell to sheet "Output_2"
For Each C In rng
If C.Value = "Account" Then
C.Offset(-1, 0).Copy C.Offset.OUTPUT_2(-7, -1) ' use offset to put value in sheet "Output_2", column E
End If
Next C
End With
End Sub
This post doesn't point out what the error in your original code is. Ron Rosenfeld has already covered that in the comment.
Here is another faster way (as compared to looping) which uses .Find/.FindNext to achieve what you want. It also doesn't copy the rows in a loop but copies in the end.
Private Sub Search_n_Copy()
Dim ws As Worksheet
Dim rngCopy As Range, aCell As Range, bcell As Range
Dim strSearch As String
strSearch = "Account"
Set ws = Worksheets("INPUT_2")
With ws
Set aCell = .Columns(1).Find(What:=strSearch, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
Set bcell = aCell
If rngCopy Is Nothing Then
Set rngCopy = .Rows((aCell.Row + 1) & ":" & (aCell.Row + 2))
Else
Set rngCopy = Union(rngCopy, .Rows((aCell.Row + 1) & ":" & (aCell.Row + 2)))
End If
Do
Set aCell = .Columns(1).FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bcell.Address Then Exit Do
If rngCopy Is Nothing Then
Set rngCopy = .Rows((aCell.Row + 1) & ":" & (aCell.Row + 2))
Else
Set rngCopy = Union(rngCopy, .Rows((aCell.Row + 1) & ":" & (aCell.Row + 2)))
End If
Else
Exit Do
End If
Loop
Else
MsgBox SearchString & " not Found"
End If
'~~> I am pasting to Output sheet. Change as applicable
If Not rngCopy Is Nothing Then rngCopy.Copy Sheets("Output").Rows(1)
End With
End Sub
Screenshot
The codle would be like this. This code Use variant.
Private Sub Search_n_Copy()
Dim LastRow As Long
Dim rng As Range, C As Range
Dim vR(), n As Long, k As Integer, j As Integer
Dim Ws As Worksheet
With Worksheets("INPUT_2") ' <-- here should be the Sheet's name
.Columns("e").ClearContents
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row ' last row in column A
Set rng = .Range("A1:A" & LastRow) ' set the dynamic range to be searched
' loop through all cells in column A and copy below's cell to sheet "Output_2"
For Each C In rng
If C.Value = "Account" Then
For j = 1 To 2
n = n + 1
ReDim Preserve vR(1 To 6, 1 To n)
For k = 1 To 6
vR(k, n) = C.Offset(j, k - 1) ' use offset to put value in sheet "Output_2", column E
Next k
End If
Next C
If n > 0 Then
Set Ws = Sheets.Add '<~~~ Sheets("your sheet name")
With Ws
.Range("a1").Resize(n, 6) = WorksheetFunction.Transpose(vR)
End With
End If
End With
End Sub
Related
I would like to compare 2 columns in the same worksheet, search for non-matching values in column A when compared to column D and copy the entire rows of these non-matching values in column A to another worksheet.
Here is a sample of the worksheet:
Therefore, I would like to compare column A with column D, find the values which do not match and copy the entire corresponding rows from Columns A and B to a new worksheet.
*Edit, I forgot to include my code
Dim CopyToRow As Integer
Dim rng1 As Range
Dim rng2 As Range
Dim cell As Range
Dim found As Range
'Start copying data to row 2 in Sheet2 (row counter variable)
CopyToRow = 2
Set rng1 = Range(ActiveSheet.Cells(2, 1), ActiveSheet.Cells(2, 1).End(xlDown))
Set rng2 = Range(ActiveSheet.Cells(4, 2), ActiveSheet.Cells(4, 2).End(xlDown))
For Each cell In rng1
Set found = rng2.Find(what:=cell, LookIn:=xlValues, lookat:=xlWhole, MatchCase:=False)
If Not found Is Nothing Then
cell.EntireRow.Copy Destination:=Sheets("Sheet2").Range("A" & CopyToRow)
CopyToRow = CopyToRow + 1
End If
Next cell
Many thanks and much appreciated!
I agree with Ron Rosenfeld that you should have demonstrated your own attempt. That being said, perhaps this will be of some help to you. Not the most elegant but should work provided you update references to your own sheet names.
Sub SOPractice()
Dim SearchCell As Range 'each value being checked
Dim SearchRng As Range 'column A
Dim LastRow As Long
Dim MatchFound As Range
Dim i As Long: i = 1
LastRow = YourSheet.Range("A" & Rows.Count).End(xlUp).Row
With YourSheet
Set SearchRng = .Range(.Cells(2, 1), .Cells(LastRow, 1))
Application.ScreenUpdating = False
For Each SearchCell In SearchRng
Set MatchFound = .Range("D:D").Find _
(What:=SearchCell.Value, LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=False)
If MatchFound Is Nothing Then 'No match hence copy to other sheet
.Range(SearchCell.Address, SearchCell.Offset(, 1)).Copy
YourCopyToSheet.Cells(i, 1).PasteSpecial xlPasteAll
i = i + 1
End If
Next SearchCell
End With
Application.ScreenUpdating = True
Application.CutCopyMode = False
End Sub
I have also found a solution, using a Dictionary object:
Dim Cl As Range, Rng As Range, Dic As Object
Set Dic = CreateObject("scripting.dictionary")
With Dic
For Each Cl In MyWorksheet1Name.Range("D2", MyWorksheet1Name.Range("D" & Rows.Count).End(xlUp))
.Item(Cl.Value) = Empty
Next Cl
For Each Cl In MyWorksheet1Name.Range("A2", MyWorksheet1Name.Range("A" & Rows.Count).End(xlUp))
If Not .Exists(Cl.Value) Then
If Rng Is Nothing Then Set Rng = Cl Else Set Rng = Union(Rng, Cl)
End If
Next Cl
End With
If Not Rng Is Nothing Then
Rng.EntireRow.Copy MyWorksheet2Name.Range("A" & Rows.Count).End(xlUp)
End If
Cheers!
For each value in Sheet("Scrap2") Column A.
find all matching instances of this value in column A of Sheet("VA_Data"). copy entire row and paste to first empty Row on sheet("List")
My code right now basically only copys the first instance it comes to of the match and then moves to the next value in Sheet("Scrap2").
If there are 10 cells in col A of sheet "VA_Data" that match the first value of Scrap2, then those 10 rows need to copy entire row and paste to first empty rows on sheet "List".
any help is appreciated.
Option Explicit
Public Sub Loop_VA_Data()
Dim wsa As Worksheet
Dim wsb As Worksheet
Dim wsc As Worksheet
Dim a As Integer
Dim b As Integer
Dim c As Integer
Dim stra As String
Dim rng As Range
On Error GoTo errLoop_VA_Data
Application.ScreenUpdating = False
Set wsa = ThisWorkbook.Worksheets("Scrap2")
Set wsb = ThisWorkbook.Worksheets("VA_Data")
Set wsc = ThisWorkbook.Worksheets("List")
wsa.Range("B:B").Clear
wsc.Rows("2:" & wsc.Range("A1").CurrentRegion.Rows.Count + 1).Clear
a = 2
Do
If Trim(wsa.Cells(a, 1).Value) = "" Then
Exit Do
End If
stra = Trim(wsa.Cells(a, 1).Value)
Set rng = wsb.Range("A:A").Find(What:=stra, LookIn:=xlValues, LookAt:=xlWhole)
If Not (rng Is Nothing) Then
b = rng.Row
c = wsc.Range("A1").CurrentRegion.Rows.Count + 1
wsb.Rows(b).Copy wsc.Rows(c)
wsa.Cells(a, 2).Value = "Found on row " & b
Else
wsa.Cells(a, 2).Value = "Not Found"
End If
If Not (rng Is Nothing) Then
Set rng = Nothing
End If
a = a + 1
Loop
MsgBox "Complete!", vbInformation
GoTo closeout
Exit Sub
errLoop_VA_Data:
MsgBox "Err Number is: " & Err.Number & " / Err Desc is: " & Err.Description & " in sub Loop_VA_Data!", vbCritical
closeout:
If Not (wsa Is Nothing) Then
Set wsa = Nothing
End If
If Not (wsb Is Nothing) Then
Set wsb = Nothing
End If
If Not (wsc Is Nothing) Then
Set wsc = Nothing
End If
If Not (rng Is Nothing) Then
Set rng = Nothing
End If
Exit Sub
End Sub
I think #urdearboy has the right idea - using a filter & copying en masse. The following code assumes the data on your VA_Data sheet is contiguous. Let me know how you go with it.
Option Explicit
Sub Filter_Copy()
Application.ScreenUpdating = False
Dim c As Range
Dim LastRow As Long, PasteRow As Long
Dim ws1 As Worksheet, ws2 As Worksheet, ws3 As Worksheet
Set ws1 = Sheets("Scrap2")
Set ws2 = Sheets("VA_Data")
Set ws3 = Sheets("List")
LastRow = ws1.Cells(Rows.Count, 1).End(xlUp).Row
For Each c In ws1.Range(ws1.Cells(1, 1), ws1.Cells(LastRow, 1))
With ws2.Cells(1, 1).CurrentRegion
.AutoFilter 1, c.Value
PasteRow = ws3.Cells(Rows.Count, 1).End(xlUp).Row + 1
.Offset(1).Resize(.Rows.Count - 1).Copy ws3.Range("A" & PasteRow)
.AutoFilter
End With
Next c
End Sub
There are two sheets - Source and Target. There is a unique ID in both sheets in Column-A.
In TargetSheet based on the uniqueID (Column-A), I want to fetch values from SourceSheet(Column-B) to TargetSheet(Column-B).
There are unique IDs in TargetSheet(Column-A) which are not in SourceSheet(Column-A), hence they should be left blank.
Sub Recon()
Dim lrow, i, j As Long
lrow = Range("A1048576").End(xlUp).Row
TargetSheet.Activate
Range("A1").Select
j = 1
For i = 3 To lrow
Do
j = j + 1
If Range("A" & i) = SourceSheet.Range("A" & j) Then
Cells(i, 2) = SourceSheet.Range("B" & j).Value
End If
Loop Until Range("A" & i) = SourceSheet.Range("A" & j)
Next i
End Sub
You can do it combining VLOOKUP trapped into an IFERROR to handle missing ids. VLOOKUP will look a value in a column and if found, will return a value in same row but different custom column. If there is no coincidence, it will raise an error, so we combine it with IFERROR to transform that error into blank value, which means that id is not found.
VLOOKUP function
IFERROR function
My fake data is just 2 sheets like yours:
The code I've used:
Sub test()
Dim WKsource As Worksheet
Dim WKTarget As Worksheet
Dim UF As Long
Set WKsource = ThisWorkbook.Worksheets("SourceSheet")
Set WKTarget = ThisWorkbook.Worksheets("TargetSheet")
With WKTarget
UF = .Range("A" & .Rows.Count).End(xlUp).Row
.Range("B2:B" & UF).FormulaR1C1 = "=IFERROR(VLOOKUP(RC[-1]," & WKsource.Name & "!C1:C2,2,FALSE),"""")" 'get values
.Range("B2:B" & UF) = .Range("B2:B" & UF).Value 'paste formula results as values
End With
Set WKTarget = Nothing
Set WKsource = Nothing
End Sub
My final output:
Try this:
`Sub Test()
Dim Source As Range
Set Source = ThisWorkbook.Worksheets("Source").Range("A2:A5")
Dim Target As Range
Set Target = ThisWorkbook.Worksheets("Target").Range("A2:A6")
Dim TargetCell As Range
Dim FoundCell As Range
For Each TargetCell In Target
Set FoundCell = Source.Find(TargetCell.Value, _
Source.Cells(1, 1), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchDirection:=xlNext)
If Not FoundCell Is Nothing Then
TargetCell.Offset(, 1) = FoundCell.Offset(, 1)
End If
Next TargetCell
End Sub`
I have an excel sheet that I want to select some cells based on their values then copy these cells to another sheet using VBA.
I have a chunk of code that go through all the excel sheetd and search for a specific value then return the total of this cells.
I need to copy right now just the cells in column H that have values "name" & "contact" and copy all these values to the sheet2 in the same workbook.
Then I to copy the cells that are next to the name and contact.
The end result is a new table that contain 2 columns name and contact and under each column the values of each name and contact that belong to it
Sample Data
Scan:
Private Sub CommandButton1_Click()
row_number = 4
count_of_str = 0
Do
DoEvents
row_number = row_number + 1
item_in_review = Sheets("Sheet1").Range("H" & row_number)
If InStr(item_in_review, "name") Then
count_of_str = count_of_str + 1
End If
Loop Until item_in_review = ""
MsgBox "the str occured: " & count_of_str & " times."
End Sub
Utilise the Find / FindNext methods
It's not entirely clear which columns your data is in. I have assumed the labels name and contact are in H, and the actual data in I
Also, I have assumed that every name will have a contact, and have not included any checks for that.
Sub Demo()
Dim row_number As Long, count_of_str As Long
Dim rToSearch As Range, rFound As Range, rng As Range
Dim strSearchTerm As String
Dim FirstAddr As String
Dim ws As Worksheet, rDest As Range
Dim cl As Range, ar As Range
strSearchTerm = "name"
With Sheets("Sheet1")
Set rToSearch = .Range(.Cells(5, 8), .Cells(.Rows.Count, 8).End(xlUp))
End With
Set rng = rToSearch.Find( _
What:=strSearchTerm, _
After:=rToSearch.Cells(rToSearch.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False, _
SearchFormat:=False)
If Not rng Is Nothing Then
FirstAddr = rng.Address
Do
count_of_str = count_of_str + 1
If rFound Is Nothing Then
Set rFound = rng.Offset(0, 1)
Else
Set rFound = Union(rFound, rng.Offset(0, 1))
End If
Set rng = rToSearch.FindNext(rng)
Loop Until rng.Address = FirstAddr
End If
MsgBox "the str occured: " & count_of_str & " times."
' rFound now refers to all found cells
' Copy to somewhere
Set ws = Worksheets("YourDestinationSheet") '<~~Update as required
Set rDest = ws.Range("YourDestinationRange") '<~~Update as required
If Not rFound Is Nothing Then
rFound.Copy rDest '<~~ copy names
rFound.Offset(1, 0).Copy rDest.Offset(0, 1) '<~~ copy contacts
End If
' Process found cells
' eg
If Not rFound Is Nothing Then
For Each ar In rFound.Areas
For Each cl In ar.Cells
Debug.Print cl.Address
Next cl, ar
End If
End Sub
Untested:
Private Sub CommandButton1_Click()
Dim count_of_str As Long
Dim c as Range, d As Range
count_of_str = 0
Set c = Sheets("Sheet1").Range("H4") 'cell to check
Set d = Sheets("Sheet2").Range("A2") 'destination to copy to
Do While Len(c.Value) > 0
If InStr(c.Value, "name") > 0 Then
count_of_str = count_of_str + 1
c.Copy d
Set d = d.Offset(1, 0) 'next destination row
End If
Set c = c.Offset(1, 0) 'next cell to check
Loop
MsgBox "the str occured: " & count_of_str & " times."
End Sub
The workbook contains three sheets:
Item-style (contains in colA the item no., colB the style of the item)
Style (List of styles we want)
Style template (List of items within the styles specified in the cols)
I need a macro that does three things:
Copy the list of styles from the Style sheet and paste & transpose in Style template starting from row 2. Row 1 of all columns needs to be left blank.
The macro needs to select each style in style template one by one, which is now in different columns. These will be the search criteria.
On the basis of style selected in step 2, the macro needs to do a search in item-style sheet and select all the items that have the selected style and paste all these items beneath the corresponding style in style-template sheet. If there are no items corresponding to the selected style, then it should mention "No items" beneath the corresponding style.
Here's a link to the workbook for easy understanding
StyleProject
Though the workbook mentions only three styles the macro should have the capability of working with more than 50 styles.
Here's the code I have:
Sub StyleProject()
Application.ScreenUpdating = False
Dim ws As Worksheet
Dim ws2 As Worksheet
Dim ws3 As Worksheet
Set ws = Sheets("Item-Style")
Set ws2 = Sheets("Style")
Set ws3 = Sheets("Style Template")
Dim rng As Range, secRng As Range
Dim i, j, k
Sheets("Style Template").Activate
finalcol = Cells(2, 50).End(x1toleft).Column
For i = 2 To finalcol
j = Cells(2, i).Value
lr = ws.Range("A" & Rows.Count).End(xlUp).Row
For k = 2 To lr
Set rng = ws.Range("B" & i)
If StrComp(CStr(rng.Text), j, 1) = 0 Then
ws.Rows(k & ":" & k).Copy
nxtRow = ws3.Range(i & Rows.Count).End(xlUp).Row + 1
ws2.Rows(nxtRow & ":" & nxtRow).PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Set rng = Nothing
End If
Next k
Next i
Application.ScreenUpdating = True
End Sub
It ends up in error trying to figure out nextrng I believe.
Sub StyleProject()
Dim wsStyle As Worksheet
Dim wsData As Worksheet
Dim wsTemplate As Worksheet
Dim StyleCell As Range
Dim rngFound As Range
Dim arrResults() As Variant
Dim strFirst As String
Dim ResultIndex As Long
Dim StyleIndex As Long
Set wsStyle = Sheets("Style")
Set wsData = Sheets("Item Data")
Set wsTemplate = Sheets("Style Template")
With wsStyle.Range("A2", wsStyle.Cells(Rows.Count, "A").End(xlUp))
If .Row < 2 Then Exit Sub 'No data
ReDim arrResults(1 To 1 + Evaluate("MAX(COUNTIF(" & wsData.Columns("B").Address(External:=True) & "," & .Address(External:=True) & "))"), 1 To .Cells.Count)
For Each StyleCell In .Cells
StyleIndex = StyleIndex + 1
ResultIndex = 1
arrResults(ResultIndex, StyleIndex) = StyleCell.Text
Set rngFound = wsData.Columns("B").Find(StyleCell.Text, wsData.Cells(Rows.Count, "B"), xlValues, xlWhole)
If Not rngFound Is Nothing Then
strFirst = rngFound.Address
Do
ResultIndex = ResultIndex + 1
arrResults(ResultIndex, StyleIndex) = wsData.Cells(rngFound.Row, "A").Text
Set rngFound = wsData.Columns("B").Find(StyleCell.Text, rngFound, xlValues, xlWhole)
Loop While rngFound.Address <> strFirst
End If
Next StyleCell
End With
If UBound(arrResults, 1) > 1 Then
wsTemplate.Range("B2", wsTemplate.Cells(Rows.Count, Columns.Count)).Clear
wsTemplate.Range("B2").Resize(UBound(arrResults, 1), UBound(arrResults, 2)).Value = arrResults
With wsTemplate.Range("B2").Resize(, UBound(arrResults, 2))
.Font.Bold = True
.Borders(xlEdgeBottom).LineStyle = xlContinuous
.EntireColumn.AutoFit
End With
End If
Set wsStyle = Nothing
Set wsData = Nothing
Set wsTemplate = Nothing
Set StyleCell = Nothing
Set rngFound = Nothing
Erase arrResults
End Sub