Search for partial text within a row of data in a cell and extract whole string and row underneath - excel

I'm trying to clean up some data in a column in Excel but it has too many rows to do it manually and the data I want is mixed up with irrelevant values.
Essentially, I need a VBA macro to search each cell in column A of Sheet1 for any row that contains the partial string "SAAM" and then copy both the full string attached to it and the next row of data directly underneath each instance to a separate sheet (Sheet2).
I expect the output to show what is shown in the attached image. I put the expected result in column B for clarity but I really want it in Sheet2 Column A.
My script currently ends up moving the full contents of the cell to Sheet2.
Sub Test()
For Each Cell In Sheets(1).Range("A:A")
If InStr(Cell.Value, "SAAM") > 0 Then
matchRow = Cell.Row
Rows(matchRow & ":" & matchRow + 1).Select
Selection.Copy
lastRow = ActiveSheet.UsedRange.Rows.Count
If lastRow > 1 Then lastRow = lastRow + 1
ActiveSheet.Range("B" & lastRow).Select
ActiveSheet.Paste
Sheets("Sheet1").Select
End If
Next
End Sub

Something like this (note this was based on looking at your code, not at the screenshot, which tells a different story...)
Sub Test()
For Each Cell In Sheets(1).UsedRange.Columns(1).Cells
If Not IsError(Cell.Value) Then
If InStr(Cell.Value, "SAAM") > 0 Then
'copy to first empty row
Cell.Resize(2,1).Entirerow.copy _
Sheets(2).Cells(rows.count, 1).end(xlup).offset(1,0)
End If 'has substring
End If 'not error
Next
End Sub
Edit: seem like you want something more like this, based on your screenshot (untested)
Sub Test()
Dim arr, i as long, sep
For Each Cell In Sheets(1).UsedRange.Columns(1).Cells
If Not IsError(Cell.Value) Then
If InStr(Cell.Value, "SAAM") > 0 Then
arr = Split(Cell.Value, vbLf) 'split cell content on newline
sep = ""
For i = lbound(arr) to ubound(arr)-1
if arr(i) like "*SAAM*" then
with cell.offset(0, 1)
.value = .value & sep & arr(i) & vbLf & arr(i+1)
sep = vbLf & vbLf
end with
end if
Next i
End If 'has substring
End If 'not error
Next
End Sub

Based on your code I’ll modify it this way:
Sub Test()
For Each Cell In Sheets(1).Range("A:A")
If InStr(Cell.Value, "SAAM") > 0 Then
matchRow = Cell.Row
Sheets(1).Cells(matchRow,1).Copy
lastRow = Sheets(2).Cells(Rows.Count,1).End(xlUp).Row + 1
Sheets(2).Range("B" & lastRow).Select
Sheets(2).PasteSpecial Paste:=xlPasteValues
Sheets(1).Select
End If
Next
End Sub

Related

If blank in A, delete cells in column A to J

I'm struggling to adapt my code now I've built out my sheet.
My code to clear the whole row is
Sub dontdeleteallrows()
Dim a
a = [MATCH(TRUE,INDEX(ISNUMBER(A1:A10000),0),0)]
If Not IsNumeric(x) Then Exit Sub
Rows(a & ":" & Rows.Count).Delete
End Sub
What can I replace Rows(a & ":" & Rows.Count).Delete with to delete cells AA to JA?
Do you want to delete the cells or clear them of content?
If you want to delete the cells, other content may need to move left or up. Where do you want it to go?
You might do something like
Range("Aa" & a & ":Ja" & a).clear
If you want to check Column A for empty cell value and delete the entire row you could use the below:
Option Explicit
Sub Delete()
Dim LastRow As Long, i As Long
With ThisWorkbook.Worksheets("Sheet1")
'Find the last row
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
'Loop column A
For i = LastRow To 1 Step -1
'Check if cell is empty
If .Range("A" & i).Value = "" Then
'Delete row
.Rows(i).EntireRow.Delete
End If
Next i
End With
End Sub

Copy and paste if one cell is blank and the other is not

So data gets pasted in to column B as the code keeps running it'll do a condition check to see there's any values in column B and paste a value in to the adjacent column A. I need to make it so it does two condition checks:
If there's values in column b, but then to check if there's values in column A before pasting so it doesn't overwrite different data that's been pasted already.
For Each Cell In y.Sheets("Compiled").Range("A:B")
If Range("B:B").Value <> "" And Range("A:A").Value = "" Then
Cell.Offset(0, -1).PasteSpecial xlPasteValues
End If
Next
You were close, don't try to loop over a multiple column range:
Sub Test()
For Each Cell In y.Sheets("Compiled").Range("B:B")
If Cell.Value <> "" And Cell.Offset(0, -1).Value = "" Then
Cell.Offset(0, -1).Value = Cell.Value
End If
Next
End Sub
NOTE: You are looping through every cell in Range("B:B") which is probably unnecessary. It'd be better if you use a lastrow value, or a static range like Range("B2:B1000"). Or you could use a criteria to exit your loop like If Cell.Value = "" Then Exit For.
Here's a version of the code that implements the lastrow value that dwirony mentioned in their answer. This also throws everything in arrays, so it might go a bit faster if you have a really large dataset.
Option Explicit
Sub test()
Dim ACol As Variant
Dim BCol As Variant
Dim lastrow As Long
Dim i As Long
lastrow = Range("B:B").Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).row
BCol = Range("B1:B" & lastrow).Value
ACol = Range("A1:A" & lastrow).Value
For i = LBound(BCol) To UBound(BCol)
If IsEmpty(ACol(i, 1)) And Not IsEmpty(BCol(i, 1)) Then
ACol(i, 1) = BCol(i, 1)
End If
Next i
Range("A1:A" & lastrow).Value = ACol
End Sub

Applying a different formula every nth row

So i have this sheet where i'd like to apply a formula every 7th row. But it can't be the same formula, it needs to "offset" the formula as well.
For example, for the first range the formula would be "=(C4+C5)-C3"; for the second range, "=(C11+C12) - C10"; and so on.
This is what i have so far:
Sub ApplyFormula()
ApplyCF Range("C6")
ApplyCF Range("C13")
'and so on, every 7 rows
'is there any other way i can apply these ranges instead of typing them?
'with an offset formula or something like that.
End Sub
Sub ApplyCF(rng As Range)
rng.Formula = "=(C4+C5)-C3"
'i'd like the macro to "offset" the formula,
'so for the C13 Range it would be "=(C11+C12) - C10"
End Sub
For your ApplyCF sub, you could do this:
Sub ApplyCF(rng As Range)
If rng.Count <> 1 Then Exit Sub ' in case your range is more than one cell
Dim prevCell As Range, twoPrevCell As Range, threePreCell As Range
Set prevCell = rng.Offset(-1, 0)
Set twoPrevCell = rng.Offset(-2, 0)
Set threeprevcell = rng.Offset(-3, 0)
rng.Formula = "=(" & twoPrevCell & "+" & prevCell & ")-" & threeprevcell
End Sub
It could definitely be tweaked, for instance, do you need to see the formula in the Formula Bar? We can evaluate that math in VBA and just put the answer in.
Per your comment, try this for every 6th cell (it's the whole macro, no need to split them):
Sub test()
' I assume you want to run this for every 6th cell in column C, starting with C1
Dim lastRow As Long
lastRow = Cells(Rows.Count, 3).End(xlUp).Row ' gets us our last row in column C with data
Dim cel As Range, rng As Range
For i = 6 To lastRow Step 6 'have to start at row 4, since any other row less than that messes up the formula
Cells(i, 3).Select ' because you can't have row 3-3
Cells(i, 3).Formula = "=(" & Cells(i - 2, 3).Address & "+" & Cells(i - 1, 3).Address & ")-" & Cells(i - 3, 3).Address
Next i
End Sub
If the formula needs to be displayed. Edited. Code below will work! you need to use the parmateter "address" to reference a cell. the parameters false or true are here to say if one needs the relative (Set to false) or absolute (set to true) referernce
Sub ApplyCF(rng As Range)
rng.Formula = "=(" & rng.Offset(-2, 0).Address(False, False) & _
"+" & rng.Offset(-1, 0).Address(False, False) & ")-" & rng.Offset(-3, 0).Address(False, False)
End Sub

Q: How to clear cells after archiving?

I have put together a Macro that allows me to archive Data from one sheet to another however I am having trouble having it Clear the info afterwards. The first Column contains numbers that I do not want to clear, right now it is only clearing the data in column B.
If someone could take a look at this I would be very greatful.
'Sub archive()
Dim i, lastrow
Dim mytext As String
lastrow = Sheets("Rooms").Range("A" & Rows.Count).End(xlUp).Row
For i = 1 To lastrow
mytext = Sheets("Rooms").Cells(i, "F").Text
If InStr(mytext, "yes") Then
Sheets("Rooms").Cells(i, "A").EntireRow.Copy Destination:=Sheets("Archive").Range("A" & Rows.Count).End(xlUp).Offset(1)
Sheets("Rooms").Cells(i, "B").Clear
End If
Next i
End Sub'
I've taken the cell on the associated row in column B and extended it to the last cell on the same row containing any value.
Sub archive()
Dim i, lastrow
Dim mytext As String
With WorkSheets("Rooms")
lastrow = .Range("A" & Rows.Count).End(xlUp).Row
For i = 1 To lastrow
mytext = .Cells(i, "F").Text
If InStr(1, mytext, "yes", vbTextCompare) Then
.Cells(i, "A").EntireRow.Copy Destination:=Sheets("Archive").Range("A" & Rows.Count).End(xlUp).Offset(1)
.Range(.Cells(i, "B"), .Cells(i, Columns.Count).End(xlToLeft)).Clear
End If
Next i
End With
End Sub
Additionally, I've used a With ... End With statement to associate WorkSheets("Rooms") with all of its cells to avoid repetitive worksheet referencing.
The Range.Clear command scrubs all values and formatting. If you just want the values to be removed, you may want to switch to Range.ClearContents method.

stop excel do-loop until

I have two columns A and B with numbers as values.
In C1 I want =A1 + B1
In C2 I want =A2 + B2
and so on. I have written the following VBA code - while it works it adds "0" after the end of the last row in range.
Let's assume my last row is A10. It adds "0" in C11 when I run the code.
How do I prevent this?
Sub macro()
Dim R As Long
R = 1
Do
Cells(R, "C").Select
R = R + 1
ActiveCell.Formula = "=sum(" & ActiveCell.Offset(0, -2) & "," &
ActiveCell.Offset(0, -1) & ")"
Loop Until IsEmpty(ActiveCell.Offset(0, -2))
End Sub
Just replace your Until condition to the following string:
Loop Until IsEmpty(ActiveCell.Offset(1, -2))
That will check the right cell for being empty. The rest of your code should remain intact.
Take a look at Do Until and Do While and While.
If you really want to iterate over cells you may go ahead. But here a method using Arrays, this will by all means reduces any performance drops that you would get looping over cells...
Option Explicit
Sub AddToRigh()
Dim i As Integer
Dim vArr As Variant
Dim LastRow As Long
'--assume you are working on Sheet 1
LastRow = Sheets(1).Cells(Rows.Count, Range("A1").Column).End(xlUp).Row
ReDim vArr(1 To LastRow)
For i = LBound(vArr) To UBound(vArr)
vArr(i) = "=Sum(RC[-2]:RC[-1])"
Next i
'--output this entire array with formulas into column C
Sheets(1).Range("C1").Resize(UBound(vArr)) = Application.Transpose(vArr)
End Sub
Output:
I'm by no means an expert in vba, but you could do this:
Sub macro()
Dim R As Long
R = 1
Do While Not IsEmpty(ActiveCell.Offset(0, -2))
Cells(R, "C").Select
R = R + 1
ActiveCell.Formula = "=sum(" & ActiveCell.Offset(0, -2) & "," &
ActiveCell.Offset(0, -1) & ")"
Loop
End Sub
I thought I'd recommend a slightly different course of action, just to give you ideas :):
Sub macro()
Dim found As Range
Set found = Range("A:A").Find("*", after:=Range("A1"), searchdirection:=xlPrevious)
If Not found Is Nothing Then
Range(Range("A1"), found).Offset(0, 2).FormulaR1C1 = "=RC[-2]+RC[-1]"
End If
End Sub

Resources