Filtering values and copying data to new sheet - excel

I'm looking to filter and move data from a main excel spreadsheet (sheet 1) into a new sheet (sheet 2) but all the advice I've found so far relates to filtering just one column of data and I want to move two. I also need to filter by a wildcard.
I've attached an image of my sheet 1, and what I'd ideally want to create in sheet 2.
Column A is date; column B is animal type; column C is weight.
I need to filter by a wildcard to find all the 'horses' in column B and then move the date, the animal type and the weight to spreadsheet 2.
I've managed to do the first part using
=IF(COUNTIF(Sheet1!B2,"*horse*"),Sheet1!B2,"")
but I'm stuck on the 2nd part of removing all the blank rows.
Animal weights

try this
Option Explicit
Sub horses()
With Worksheets("Sheet1").Range("B2:D100") '<== range containing data, headers included
.Sort key1:=.Columns(1), Order1:=xlAscending, Orientation:=xlTopToBottom, Header:=xlYes
.AutoFilter field:=2, Criteria1:="*Horse"
If WorksheetFunction.Subtotal(103, .Cells) > .Columns.Count Then
.SpecialCells(xlCellTypeVisible).Copy Destination:=Worksheets("Sheet2").Range("A1") '<== copying form cell "A1" of "Sheet2"
End If
End With
End Sub
adapt commented lines as per you needs

Use the below function to get your result. You can parse any content to this function to get the result in Sheet2.
Private Function filtercontent(content As String) As String
Lastrow = Worksheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To Lastrow
If InStr(Cells(i, 2), content) > 0 Then
Worksheets("Sheet1").Range("A" & i, "C" & i).Copy
With Worksheets("Sheet2")
.Range("A" & .Range("A" & Rows.Count).End(xlUp).Row + 1).PasteSpecial Paste:=xlPasteValues
End With
End If
Next i
End Function
or
Private Function filtercontent(content As String) As String
Dim Lastrow As Long
Dim i As Integer
Lastrow = Worksheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To Lastrow
If InStr(Cells(i, 2), content) > 0 Then
Worksheets("Sheet1").Range("A" & i, "C" & i).Copy Worksheets("Sheet2").Range("A" & Worksheets("Sheet2").Range("A" & Rows.Count).End(xlUp).Row + 1)
End If
Next i
End Function
for example if you want the apply the filter for Horse then
Sub testing()
filtercontent ("Horse")
End Sub

Related

Find duplicates in Column A and combine and separate all text values in column D then remove all duplicate rows

I have a script but it only takes the first value in column D then removes all duplicates. I'm sorry but I'm just learning VBA and need some help. Can this be adjusted or programmed differently to combine all the text values in column D separated by a colon?
To explain we are exporting ticket data and importing to a new tool but their import won't accept duplicates of ticket IDs (numbers, 1000-9000). Our thought is if we can combine the labor descriptions which contains our labor notes then we can retain the data we need and ignore the other info we do not need.
Sub foo()
Dim ws As Worksheet
Dim lstrow As Long
Set ws = Sheets("g1") ' Change to your sheet
With ws
lstrow = .Range("A" & .Rows.Count).End(xlUp).Row
With .Range("B4:M" & lstrow)
.Offset(, 26).FormulaR1C1 = "=IFERROR(INDEX(R4C[-26]:R" & lstrow & "C[-26],MATCH(1,INDEX((R4C1:R" & lstrow & "C1 = RC1)*(R4C[-26]:R" & lstrow & "C[-26] <>""""),),0)),"""")"
ws.Calculate
.Value = .Offset(, 26).Value
.Offset(, 26).ClearContents
End With
With .Range("A4:M" & lstrow)
.Value = .Value
.RemoveDuplicates 1, xlGuess
End With
End With
End Sub
This definitely removes all duplicates but only keeps the first cell value it finds in the secondary column.

Deleting Rows Based on Text Values in Specific Column

I have written a short macro to delete all rows that have a value of "Not Applicable" in column I, for the "Budget" tab of my workbook.
The macro does not seem to be doing anything when I run it through my testing:
Sub Remove_NA_Macro_Round_2()
With Sheets("Budget") 'Applying this macro to the "Budget" sheet/tab.
'Establishing our macro range parameters
Dim LastRow As Long
Dim i As Long
'Setting the last row as the ending range for this macro
LastRow = .Range("I50").End(xlUp).Row
'Looping throughout all rows until the "LastRow" ending range set above
For i = LastRow To 1 Step -1
If .Range("I" & i).Value = "Not Applicable" Then
.Range("I" & i).EntireRow.Delete
End If
Next
End With
End Sub
I appreciate any help!
Alternatively, when deleting rows based on a condition, it is faster to use a filter then looping.
Dim rng As Range
Set rng = ThisWorkbook.Sheets("Sheet1").Range("A1:I" & Cells(Rows.Count, "I").End(xlUp).Row)
Application.DisplayAlerts = False
With rng
.AutoFilter
.AutoFilter field:=9, Criteria1:="Not Applicable"
rng.Resize(rng.Rows.Count - 1).Offset(1).SpecialCells(xlCellTypeVisible).Delete 'deletes the visible rows below the first row
.AutoFilter
End With
Application.DisplayAlerts = True
You are not actually referencing the With Sheets("Budget"). Add a period . before each instance of Range, otherwise there's an implicit ActiveSheet, which is not necessarily the Budget tab.
With Sheets("Budget")
...
LastRow = .Range("I50").End(xlUp).Row
...
If .Range("I" & i).Value = "Not Applicable" Then
.Range("I" & i).EntireRow.Delete
End If
...
End With
EDIT:
Based on commentary and your provided screenshot, change how LastRow is determined (get rid of the hard-coded I50):
LastRow = .Cells(.Rows.Count, "I").End(xlUp).Row

Transfer Data Row from Table to the bottom of another Table on different sheet

I am trying to transfer a row of data from one table to a new row at the bottom of another table when a date is entered into the cell(Column "AD").
When I try, data is transferred to the row under the last row of the table.
Sub TRANSFER_DATA()
For Each Cell In Worksheets("Sheet1").Range("AD2:AD1000")
If Cell.Value > 0 Then
matchRow = Cell.Row
Rows(matchRow & ":" & matchRow).Select
Selection.Cut
Sheets("Sheet2").Select
ActiveSheet.Range("A" & Rows.Count).End(xlUp).Offset(1).Select
ActiveSheet.Paste
Sheets("Sheet1").Select
End If
Next Cell
End Sub
If i understood your question you can try this code:
Execute the macro when you have the sheet1 active
Sub TRANSFER_DATA()
Dim lastrow, i As Long
Dim ADCell as Integer
ADCell=30 ' control the column AD
'control how many data there are in column A. If you want count how many rows
'with ColumnAD change 1 in 30 (lastrow = Cells(rows.count,30).End(xlUp).Row)
lastrow = Cells(rows.count, 1).End(xlUp).Row
For i = 2 To lastrow
If Cells(i, ADCell) > 0 Then
rows(i & ":" & i).Select
Selection.Cut Worksheets("Sheet2").Range("A" & rows.count).End(xlUp).Offset(1)
End If
Next i
End Sub
I tried the code and works.
UPDATED THE POST AFTER YOUR COMMENT
Sub TRANSFER_DATA()
Dim lastrow, i, ls As Long
Dim ADCell as Integer
ADCell=30 ' control the column AD
'control how many data there are in column A. If you want count how many rows
'with ColumnAD change 1 in 30 (lastrow = Cells(rows.count,30).End(xlUp).Row)
lastrow = Cells(rows.count, 1).End(xlUp).Row
For i = 2 To lastrow
If Cells(i, ADCell) > 0 Then
rows(i & ":" & i).Select
Selection.Cut Worksheets("Sheet2").Range("A" & rows.count).End(xlUp).Offset(1)
End If
Next i
With Sheets("sheet2")
ls = .Cells(.rows.count, ADCell).End(xlUp).Row
.ListObjects("TableName").Resize Range("$A$1:$AD$" & ls)
End With
End Sub
the updated code have another variable, ls. This variable has the number of not empty rows of sheet2. ListObjects.("name of your table") insert the new data (rows) into the table.
I hope this helps

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.

VBA, how to insert a dynamic / relative cell reference into a .formulaArray method?

I have the following code:
With Sh.Range("A1:A" & LastRow + 1).Offset(0, 4)
.FormulaArray = "=MAX(IF(A2:A" & LastRow + 1 & "= ** , D2:D" & LastRow + 1 & "))"
.Value = .Value
End With
In the place where I have **, I would want a dynamic cell reference. If I was using .formulaR1C1, I would have inserted RC[-1], but I can't use that with a .formulaArray.
Does anyone know how I can insert a relative cell reference that would change as the formula being pasted within the range?
Thank you
EDIT # 1
The whole code looks like this:
Sub RemoveDuplicates_SumMarketValue()
Dim Sh As Worksheet
Dim LastRow As Long
Dim Rng As Range
Set Sh = Worksheets(1)
Sh.Columns(6).Insert
LastRow = Sh.Range("A65536").End(xlUp).Row
With Sh.Range("A1:A" & LastRow).Offset(0, 5)
.FormulaR1C1 = "=IF(COUNTIF(R1C[-5]:RC[-5],RC[-5])>1,"""",SUMIF(R1C[-5]:R[" & LastRow & "]C[-5],RC[-5],R1C[-1]:R[" & LastRow & "]C[-1]))"
.Value = .Value
End With
Sh.Columns(5).Delete
Sh.Rows(1).Insert
Sh.Columns(5).Insert
With Sh.Range("A1:A" & LastRow + 1).Offset(0, 4)
.FormulaArray = "=MAX(IF(A2:A" & LastRow + 1 & "= A1 , D2:D" & LastRow + 1 & "))"
.Value = .Value
End With
Set Rng = Sh.Range("E1:E" & LastRow + 1)
With Rng
.AutoFilter Field:=1, Criteria1:="="
.SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
End Sub
This purpose of this code, is too look though a sample of data and
find duplicates
sum up values in 5th column associated with duplicates
remove duplicate rows (except the one that carries the sum from 5th column)
Now I also want it to have the max value from column 4th of all the duplicates to be retained in the final version, but I can't get the array formula to reference the row correctly.
EDIT : Try pasting this inside the "ThisWorkbook" code sheet :
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim Sh As Worksheet
Dim LastRow As Long
Dim Rng As Range
Set Sh = Worksheets(1)
LastRow = Sh.Range("A65536").End(xlUp).Row
With Sh.Range("A1:A" & LastRow).Offset(0, 5)
.FormulaR1C1 = "=IF(COUNTIF(R1C[-5]:RC[-5],RC[-5])>1,"""",SUMIF(R1C[-5]:R[" & LastRow & "]C[-5],RC[-5],R1C[-1]:R[" & LastRow & "]C[-1]))"
.Value = .Value
End With
With Sh.Range("A1:A" & LastRow + 1).Offset(0, 4)
.FormulaArray = "=MAX(IF(A2:A" & LastRow + 1 & "= A1 , D2:D" & LastRow + 1 & "))"
.Value = .Value
End With
'This section you might want to remove from this routine
Set Rng = Sh.Range("E1:E" & LastRow + 1)
With Rng
.AutoFilter Field:=1, Criteria1:="="
.SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
End Sub
It basically is the same as your function, but it doesn't remove the columns or add any rows. What will happen is everytime one of your cell's content changes, this macro will run automatically, updating the formulas in the cells.
The closest you can get to achieving that, is having a macro in the background that will be running everytime a change is made to the sheet. If you have tens of thousands of rows, or a REALLY slow computer, this may not be the ideal solution. If this is not the case, however, you may find it very easy to get your code to work with very little changes.
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
'Update your formula here with the new content/reference
' (your code + some changes to update where the last row is)
End Sub
Paste this inside the "ThisWorkbook", and simply place your code inside it.
This is what I came up with to solve the issue of the .formulaArray not accepting RC cell reference notation. I just used a loop to insert the array formula into each cell and reference the target row by using the loop variable i.
Code:
Sub RemoveDuplicates_SumMarketValue()
Dim Sh As Worksheet
Dim LastRow As Long
Dim Rng As Range
Dim targetcell As Range
Set Sh = Worksheets(1)
Sh.Columns(6).Insert
LastRow = Sh.Range("A65536").End(xlUp).Row
With Sh.Range("A1:A" & LastRow).Offset(0, 5)
.FormulaR1C1 = "=IF(COUNTIF(R1C[-5]:RC[-5],RC[-5])>1,"""",SUMIF(R1C[-5]:R[" & LastRow & "]C[-5],RC[-5],R1C[-1]:R[" & LastRow & "]C[-1]))"
.Value = .Value
End With
Sh.Columns(5).Delete
Sh.Rows(1).Insert
Sh.Columns(5).Insert
For i = 2 To LastRow + 1
Cells(i, 5).FormulaArray = "=MAX(IF(A2:A" & LastRow + 1 & "= A" & i & " , D2:D" & LastRow + 1 & "))"
Cells(i, 5) = Cells(i, 5).Value
Next
Sh.Columns(4).Delete
Set Rng = Sh.Range("E1:E" & LastRow + 1)
With Rng
.AutoFilter Field:=1, Criteria1:="="
.SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
Sheets(1).Cells(1, 4) = "Price"
Sheets(1).Cells(1, 5) = "market value"
End Sub
So what this code does, loops for duplicates in Col 1, sums up associated values in col 5 and picks the max associated value in col 4.
Could you use, where you fill a cell and replicate it,
L = LastRow + 1
With Sh.Range("A1:A" & L).Offset(0, 4)
.Cells(1,1).FormulaArray = "=MAX(IF(A$2:A$" & L & "=A1,D$2:D$" & L & "))"
.FillDown
.Value = .Value
End With
Handling A1 vs R1C1 style is easy, with Application.ConvertFormula
Need to be careful about Row/Col Abs/Rel referencing.

Resources