Changing the search from one cell to the entire sheet - vba

I've tried changing everywhere there was a cell to a range and other things but I can't figure it out. I'd like for the code to search the entire sheet, instead of one cell, for these names and paste the information of the cell to the right of it to the other sheet.
Option Explicit
Private Sub CommandButton1_Click()
Dim ws As Worksheet, myCounter As Long
Dim erow As Long, myValue As Long
Dim nextValue As Long
For Each ws In ThisWorkbook.Sheets
With ws
Select Case .Range("C3").Value
Case "David", "Andrea", "Caroline"
myCounter = 1 ' raise flag >> found in at least 1 sheet
' get first empty row in "Report" sheet
erow = Worksheets("Report").Cells(Worksheets("Report").Rows.Count, 1).End(xlUp).Offset(1, 0).Row
Worksheets("Report").Cells(erow, 1) = .Range("C3").Value
End Select ' Select Case .Range("C3").Value
End With
Next ws
If myCounter = 0 Then
MsgBox "None of the sheets contains the names " & Chr(10) & " 'David', 'Andrea', 'Caroline' in cell C3 ", vbInformation, "Not Found"
End If
End Sub

You can use Application.Match with array version. Substitute this for your loop:
Dim ar, r
For Each ws In ThisWorkbook.Sheets
ar = Application.match(Array("David", "Andrea", "Caroline"), ws.Columns("C"), 0)
For Each r In ar
If Not IsError(r) Then
myCounter = 1 ' raise flag >> found in at least 1 sheet
erow = Worksheets("Report").Cells(Worksheets("Report").Rows.Count, 1).End(xlUp).Offset(1, 0).row
Worksheets("Report").Cells(erow, 1) = ws.Range("C" & r).value
Worksheets("Report").Cells(erow, 2) = ws.Range("D" & r).value
End If
Next r
Next ws
Notice though, that this will find you only one match for each word, the first one. If each word can be repeated many times and you want to find all matches, it will need some modification.

Multiple rows and multiple columns would be better served by the Find command.
Option Explicit
Private Sub CommandButton1_Click()
Dim ws As Worksheet, bFound As Boolean, rFound As Range
Dim a As Long, aNames As Variant
aNames = Array("David", "Andrea", "Caroline")
For Each ws In ThisWorkbook.Worksheets
'If ws.Name <> Worksheets("Report").Name Then
If ws.Name = "Sheet7" Then
With ws.Range("A1:E30").Cells
For a = LBound(aNames) To UBound(aNames)
Set rFound = .Find(What:=aNames(a), MatchCase:=False, LookAt:=xlWhole, SearchFormat:=False)
If Not rFound Is Nothing Then
bFound = True
With Worksheets("Report")
.Cells(.Rows.Count, 1).End(xlUp).Offset(1, 0) = rFound.Value
End With
End If
Next a
End With
End If
Next ws
If Not bFound Then
MsgBox "None of the sheets contains the names " & Chr(10) & _
"'" & Join(aNames, "', '") & "' in cells A1:E30.", vbInformation, "Not Found"
End If
End Sub

Related

VBA - Autofilter then copy the result into the new sheet

I am trying to do the macro which can do autofilter and copy the visible row , then paste them into the new sheet by using VBA. my code as below:
Option Explicit
Sub lab()
Dim ws As Worksheet
Dim sh1 As Worksheet
Dim mycoll As Collection
Set mycoll = New Collection
Set sh1 = ThisWorkbook.Sheets(1)
Dim rng As Range
Dim c As Range
Dim lastrow As Long
lastrow = Range("C" & Rows.Count).End(xlUp).Row
On Error Resume Next
Set rng = sh1.Range("B4:F" & lastrow)
With rng
.AutoFilter field:=2, Criteria1:=sh1.Range("I1"), Criteria2:=sh1.Range("I2"), Operator:=xlOr
.AutoFilter field:=3, Criteria1:=sh1.Range("K1"), Criteria2:=sh1.Range("K2"), Operator:=xlOr
.AutoFilter field:=4, Criteria1:=sh1.Range("M1"), Criteria2:=sh1.Range("M2"), Operator:=xlOr
End With
Set ws = Worksheets.Add
ws.Name = sh1.Range("I1").Value & "-" & sh1.Range("I2").Value
rng.SpecialCells(xlCellTypeVisible).Copy ws.Range("A1")
rng.AutoFilter
sh1.Activate
End Sub
my problem is the code only work correctly for the first new sheet. then it always create the sheet with the same content. I tried to find the root issue , could you please help assist on this ?
When there is a problem with your code, you never use On Error Resume Next! It only does not let VBA 'telling' you what problem the code has...
If your code names the newly created sheet using:
ws.Name = sh1.Range("I1").Value & "-" & sh1.Range("I2").Value
second time, if the concatenation of the two cells value is the same, VBA cannot name a sheet with the same name like an existing one. The raised error should have a clear description but your code jumps over it, because of On error Resume Next.
If you really need/want to use a similar sheet name, try placing a sufix. For doing that, you can use the next function:
Function shName(strName As String) As String
Dim ws As Worksheet, arrSh, arrN, maxN As Long, k As Long, El
ReDim arrSh(ActiveWorkbook.Sheets.count - 1)
For Each ws In ActiveWorkbook.Sheets
If ws.Name = strName Then
shName = strName & "_" & 1
Exit Function
End If
If InStr(ws.Name, strName & "_") > 0 Then arrSh(k) = ws.Name: k = k + 1
Next
If k = 0 Then shName = strName: Exit Function 'if no such a name exists
ReDim Preserve arrSh(k - 1)
'determine the bigger suffix:
For Each El In arrSh
arrN = Split(El, "_")
If CLng(arrN(UBound(arrN))) > maxN Then maxN = CLng(arrN(UBound(arrN)))
Next
shName = strName & "_" & maxN + 1
End Function
It should be called from your existing code replacing the line
ws.Name = sh1.Range("I1").Value & "-" & sh1.Range("I2").Value
with
ws.Name = shName(sh1.Range("I1").Value & "-" & sh1.Range("I2").Value)

Conflicting DATA - Duplicated values

I created a macro that fills the missing Data with specific Data from another sheet , the codes works perfectly in copying pasting data from excel of the client and prepare the data needed to start the work but the only problem here below
Code:
With Worksheets("Feuil2")
' reference "target" sheet (change "Target" to our actual target sheet name)
With .Range("B1:B" & .Cells(.Rows.Count, 1).End(xlUp).Row) 'reference
its column B range from row 1 down to last not empty one
If WorksheetFunction.CountBlank(.Cells) > 0 Then
' if any blank cell in referenced range. this check to avoid error thrown by subsequent
statament
.SpecialCells(xlCellTypeBlanks).FormulaR1C1 = "=index(GDC!" & rng.Offset(, 1).Address(, , xlR1C1) & ",match(RC[-1],GDC!" & rng.Address(, , xlR1C1) & ",0))" 'fill blank cells with a lookup (well, sort of) formula
.Value = .Value 'get rid of formulas and leave values only
Cells.Select
End If
End With
End With
This code works perfectly in matching and filling data but when for e.g find a duplicated value it copy only the first value not the second one
See the image below to better understand the main problem :
As you can see in the image The problem that in column A i may have data repeated twice like this value P20845 which in column F it is repeated one with the name of Ghaith and the other with the name of sirine but as you can see in the column A it is just with the name also of Ghaith and there is no name of sirine
Anyidea or better solution in solving this and getting all the needed DATA? .
Best Regards
POLOS
Or use a dictionary
Option Explicit
Public Sub AddValues()
Application.ScreenUpdating = False
Dim wb As Workbook, wsSource As Worksheet, wsTarget As Worksheet, masterDict As Object, arr() As Variant, i As Long, rng As Range
Set wb = ThisWorkbook
Set wsSource = wb.Worksheets("Feuil1")
Set wsTarget = wb.Worksheets("Feuil2")
Set masterDict = CreateObject("Scripting.Dictionary")
With wsSource
arr = Intersect(.Columns("A:B"), .UsedRange)
For i = 1 To UBound(arr, 1)
If Not masterDict.exists(arr(i, 1)) Then masterDict.Add arr(i, 1), GetAllMatches(arr(i, 1), arr(i, 2), wsSource)
Next i
End With
With wsTarget
For Each rng In Intersect(.Columns("A"), .UsedRange)
On Error Resume Next
rng.Offset(, 1) = masterDict(rng.Value)
On Error GoTo 0
Next rng
End With
Application.ScreenUpdating = True
End Sub
Public Function GetAllMatches(ByVal findString As String, ByVal dupString As String, ByVal searchRng As Worksheet) As String
Dim foundCell As Range
Dim concatenatedString As String
concatenatedString = vbNullString
With Intersect(searchRng.Columns(1), searchRng.UsedRange)
Set foundCell = .Find(findString)
If foundCell Is Nothing Then Exit Function
If Not foundCell Is Nothing Then concatenatedString = foundCell.Offset(, 1)
Dim currMatch As Long
currMatch = 0
For currMatch = 1 To WorksheetFunction.CountIf(.Cells, findString)
Set foundCell = .Find(What:=findString, After:=foundCell, _
LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False)
If Not foundCell Is Nothing And InStr(1, dupString, concatenatedString) = 0 Then
concatenatedString = concatenatedString & "/" & foundCell.Offset(, 1)
Else
concatenatedString = foundCell.Offset(, 1)
End If
Next currMatch
End With
GetAllMatches = concatenatedString
End Function
Output in Feuil2
Maybe something like this instead?
Sub Test()
Dim i As Long, myrow As Long, lastrow As Long
Dim sht1 As Worksheet, sht2 As Worksheet
Set sht1 = ThisWorkbook.Worksheets("Sheet1")
Set sht2 = ThisWorkbook.Worksheets("Sheet2")
lastrow = 1
For i = 1 To 7
If Application.WorksheetFunction.CountIf(sht1.Range("A:A"), sht2.Range("F" & i).Value) = 0 Then
If i = 1 Then
lastrow = 1
Else
lastrow = sht1.Cells(sht1.Rows.Count, "A").End(xlUp).Row + 1
End If
sht1.Range("A" & lastrow).Value = sht2.Range("F" & i).Value
sht1.Range("B" & lastrow).Value = sht2.Range("G" & i).Value
Else
sht1.Range("B" & sht1.Columns("A:A").Find(What:=sht2.Range("F" & i).Value).Row).Value = sht1.Range("B" & sht1.Columns("A:A").Find(What:=sht2.Range("F" & i).Value).Row).Value & "/" & sht2.Range("G" & i).Value
End If
Next i
End Sub

Finding array data in worksheet values

I have a table sort of like this:
Pendergrass (606)-663-4567
Rich (606)-667-4567
Scott (606)-987-4567
Dennis (606)-233-4567
David (606)-888-4567
Red (606)-567-4567
Wendy (606)-765-4567
Todd (606)-677-4567
Andrea (606)-780-3451
Caroline (606)-992-7865
and the code I'm using looks like this:
Private Sub CommandButton2_Click()
Dim ws As Worksheet, bFound As Boolean, rFound As Range
Dim a As Long, aNames As Variant
aNames = Array("David", "Andrea", "Caroline")
For Each ws In ThisWorkbook.Worksheets
'If ws.Name <> Worksheets("Report").Name Then
If ws.Name = "Sheet1" Then
With ws.Range("A1:E30").Cells
For a = LBound(aNames) To UBound(aNames)
Set rFound = .Find(What:=aNames(a), MatchCase:=False, LookAt:=xlWhole, SearchFormat:=False)
If Not rFound Is Nothing Then
bFound = True
With Worksheets("Report")
.Cells(.Rows.Count, 1).End(xlUp).Offset(1, 0) = rFound.Value
End With
End If
Next a
End With
End If
Next ws
If Not bFound Then
MsgBox "None of the sheets contains the names " & Chr(10) & _
"'" & Join(aNames, "', '") & "' in cells A1:E30.", vbInformation, "Not Found"
End If
End Sub
I would like if to take the numbers of David, Andrea and Caroline and put them any where in the Report page. This only grabs one.
Can anyone suggest where I am going wrong with this code?
Try the code below.
However, not sure why you are looping through all the sheets with For Each ws In ThisWorkbook.Worksheets , if at the following line you are checking If ws.Name = "Sheet1" Then.
You can replace the lines below (remove a For, a With and If) :
For Each ws In ThisWorkbook.Worksheets
With ws
'If ws.Name <> Worksheets("Report").Name Then
If .Name = "Sheet1" Then
With .Range("A1:E30").Cells
with a simple:
With Worksheets("Sheet1").Range("A1:E30").Cells
Code
Private Sub CommandButton2_Click()
Dim ws As Worksheet, bFound As Boolean, rFound As Range
Dim a As Long, aNames As Variant
aNames = Array("David", "Andrea", "Caroline")
For Each ws In ThisWorkbook.Worksheets
With ws
'If ws.Name <> Worksheets("Report").Name Then
If .Name = "Sheet1" Then
With .Range("A1:E30").Cells
For a = LBound(aNames) To UBound(aNames)
Set rFound = .Find(What:=aNames(a), MatchCase:=False, LookAt:=xlWhole, SearchFormat:=False)
If Not rFound Is Nothing Then
bFound = True
Worksheets("Report").Cells(Worksheets("Report").Rows.Count, 1).End(xlUp).Offset(1) = rFound.Value
Worksheets("Report").Cells(Worksheets("Report").Rows.Count, 1).End(xlUp).Offset(, 1) = rFound.Offset(, 1).Value
End If
Next a
End With
End If
End With
Next ws
If Not bFound Then
MsgBox "None of the sheets contains the names " & Chr(10) & _
"'" & Join(aNames, "', '") & "' in cells A1:E30.", vbInformation, "Not Found"
End If
End Sub

copy a filtered range to 2nd row where col headings match

i need to copy data from one sheet to another and paste into the next available row where the column headings match.
I am having difficulty creating the range to copy into.
this seems to be the issue -
rng1.SpecialCells(xlCellTypeVisible).Copy Destination:=Sheets("Combined Totals").Range(tCell.Offset(1) & lRow)
i ahve tried creating the destination to paste to using Cells and Range, but i can't seem to add variables into the syntax correctly.
What am i doing wrong?
Set this to the relevant worksheet
Set ws = ThisWorkbook.Sheets("OPT 1 Total")
With ws
'~~> Find the cell which has the name
Set sCell = .Range("A1:Z1").Find("MN")
Set tCell = Sheets("Combined Totals").Range("A1:Z1").Find("MN")
'~~> If the cell is found
If Not sCell Is Nothing Then
'~~> Get the last row in that column and check if the last row is > 1
lRow = .Range(Split(.Cells(, sCell.Column).Address, "$")(1) & .Rows.Count).End(xlUp).Row
If lRow > 1 Then
'~~> Set your Range
Set rng1 = .Range(sCell.Offset(1), .Cells(lRow, sCell.Column))
'bCell.Offset(1).Activate
Debug.Print tCell.Address
rng1.SpecialCells(xlCellTypeVisible).Copy Destination:=Sheets("Combined Totals").Range(tCell.Offset(1) & lRow)
'Cells(2, 1).Resize(rng1.Rows.Count) '
'~~> This will give you the address
Debug.Print rng1.Address
End If
End If
End With
EDIT2: parameterized....
Sub CopyAll()
TransferToTotals "OPT 1 Total", Array("MN", "TX", "CA")
TransferToTotals "OPT 2 Total", Array("MN", "TX", "CA")
End Sub
Sub TransferToTotals(srcSheet As String, arrHeaders)
Dim ws As Worksheet, sCell As Range, tCell As Range, lstCell As Range
Dim wsd As Worksheet, i As Long, arrHeadings
Set wsd = ThisWorkbook.Sheets("Combined Totals")
On Error Resume Next
Set ws = ThisWorkbook.Sheets(srcSheet)
On Error GoTo 0
If ws Is Nothing Then
Debug.Print "Source sheet '" & srcSheet & "' not found!"
Exit Sub
End If
For i = LBound(arrHeaders) To UBound(arrHeaders)
With ws
Set sCell = .Range("A1:Z1").Find(arrHeaders(i))
Set tCell = wsd.Range("A1:Z1").Find(arrHeaders(i))
If Not sCell Is Nothing And Not tCell Is Nothing Then
Set lstCell = .Cells(.Rows.Count, sCell.Column).End(xlUp)
If lstCell.Row > 1 Then
'EDIT - paste values only...
.Range(sCell.Offset(1), lstCell).SpecialCells( _
xlCellTypeVisible).Copy
wsd.Cells(Rows.Count, tCell.Column).End(xlUp) _
.Offset(1, 0).PasteSpecial xlPasteValues
End If
Else
Debug.Print "Couldn't find both '" & _
arrHeaders(i) & "' headers"
End If
End With
Next i
End Sub

Excel VBA - Delete empty rows

I would like to delete the empty rows my ERP Quotation generates. I'm trying to go through the document (A1:Z50) and for each row where there is no data in the cells (A1-B1...Z1 = empty, A5-B5...Z5 = empty) I want to delete them.
I found this, but can't seem to configure it for me.
On Error Resume Next
Worksheet.Columns("A:A").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
On Error GoTo 0
How about
sub foo()
dim r As Range, rows As Long, i As Long
Set r = ActiveSheet.Range("A1:Z50")
rows = r.rows.Count
For i = rows To 1 Step (-1)
If WorksheetFunction.CountA(r.rows(i)) = 0 Then r.rows(i).Delete
Next
End Sub
Try this
Option Explicit
Sub Sample()
Dim i As Long
Dim DelRange As Range
On Error GoTo Whoa
Application.ScreenUpdating = False
For i = 1 To 50
If Application.WorksheetFunction.CountA(Range("A" & i & ":" & "Z" & i)) = 0 Then
If DelRange Is Nothing Then
Set DelRange = Range("A" & i & ":" & "Z" & i)
Else
Set DelRange = Union(DelRange, Range("A" & i & ":" & "Z" & i))
End If
End If
Next i
If Not DelRange Is Nothing Then DelRange.Delete shift:=xlUp
LetsContinue:
Application.ScreenUpdating = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
IF you want to delete the entire row then use this code
Option Explicit
Sub Sample()
Dim i As Long
Dim DelRange As Range
On Error GoTo Whoa
Application.ScreenUpdating = False
For i = 1 To 50
If Application.WorksheetFunction.CountA(Range("A" & i & ":" & "Z" & i)) = 0 Then
If DelRange Is Nothing Then
Set DelRange = Rows(i)
Else
Set DelRange = Union(DelRange, Rows(i))
End If
End If
Next i
If Not DelRange Is Nothing Then DelRange.Delete shift:=xlUp
LetsContinue:
Application.ScreenUpdating = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
I know I am late to the party, but here is some code I wrote/use to do the job.
Sub DeleteERows()
Sheets("Sheet1").Select
Range("a2:A15000").Select
Selection.SpecialCells(xlCellTypeBlanks).EntireRow.Delete
End Sub
for those who are intersted to remove "empty" and "blank" rows ( Ctrl + Shift + End going deep down of your worksheet ) .. here is my code.
It will find the last "real"row in each sheet and delete the remaining blank rows.
Function XLBlank()
For Each sh In ActiveWorkbook.Worksheets
sh.Activate
Cells(1, 1).Select
lRow = Cells.Find(What:="*", _
After:=Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
Range("A" & lRow + 1, Range("A1").SpecialCells(xlCellTypeLastCell).Address).Select
On Error Resume Next
Selection.EntireRow.SpecialCells(xlBlanks).EntireRow.Delete
Cells(1, 1).Select
Next
ActiveWorkbook.Save
ActiveWorkbook.Worksheets(1).Activate
End Function
Open VBA ( ALT + F11 ), Insert -> Module,
Copy past my code and launch it with F5.
Et voila :D
I have another one for the case when you want to delete only rows which are complete empty, but not single empty cells. It also works outside of Excel e.g. on accessing Excel by Access-VBA or VB6.
Public Sub DeleteEmptyRows(Sheet As Excel.Worksheet)
Dim Row As Range
Dim Index As Long
Dim Count As Long
If Sheet Is Nothing Then Exit Sub
' We are iterating across a collection where we delete elements on the way.
' So its safe to iterate from the end to the beginning to avoid index confusion.
For Index = Sheet.UsedRange.Rows.Count To 1 Step -1
Set Row = Sheet.UsedRange.Rows(Index)
' This construct is necessary because SpecialCells(xlCellTypeBlanks)
' always throws runtime errors if it doesn't find any empty cell.
Count = 0
On Error Resume Next
Count = Row.SpecialCells(xlCellTypeBlanks).Count
On Error GoTo 0
If Count = Row.Cells.Count Then Row.Delete xlUp
Next
End Sub
To make Alex K's answer slightly more dynamic you could use the code below:
Sub DeleteBlankRows()
Dim wks As Worksheet
Dim lngLastRow As Long, lngLastCol As Long, lngIdx As Long, _
lngColCounter As Long
Dim blnAllBlank As Boolean
Dim UserInputSheet As String
UserInputSheet = Application.InputBox("Enter the name of the sheet which you wish to remove empty rows from")
Set wks = Worksheets(UserInputSheet)
With wks
'Now that our sheet is defined, we'll find the last row and last column
lngLastRow = .Cells.Find(What:="*", LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious).Row
lngLastCol = .Cells.Find(What:="*", LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious).Column
'Since we need to delete rows, we start from the bottom and move up
For lngIdx = lngLastRow To 1 Step -1
'Start by setting a flag to immediately stop checking
'if a cell is NOT blank and initializing the column counter
blnAllBlank = True
lngColCounter = 2
'Check cells from left to right while the flag is True
'and the we are within the farthest-right column
While blnAllBlank And lngColCounter <= lngLastCol
'If the cell is NOT blank, trip the flag and exit the loop
If .Cells(lngIdx, lngColCounter) <> "" Then
blnAllBlank = False
Else
lngColCounter = lngColCounter + 1
End If
Wend
'Delete the row if the blnBlank variable is True
If blnAllBlank Then
.rows(lngIdx).delete
End If
Next lngIdx
End With
MsgBox "Blank rows have been deleted."
End Sub
This was sourced from this website and then slightly adapted to allow the user to choose which worksheet they want to empty rows removed from.
In order to have the On Error Resume function work you must declare the workbook and worksheet values as such
On Error Resume Next
ActiveWorkbook.Worksheets("Sheet Name").Columns("A:A").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
On Error GoTo 0
I had the same issue and this eliminated all the empty rows without the need to implement a For loop.
This worked great for me (you can adjust lastrow and lastcol as needed):
Sub delete_rows_blank2()
t = 1
lastrow = ActiveSheet.UsedRange.Rows.Count
lastcol = ActiveSheet.UsedRange.Columns.Count
Do Until t = lastrow
For j = 1 To lastcol
'This only checks the first column because the "Else" statement below will skip to the next row if the first column has content.
If Cells(t, j) = "" Then
j = j + 1
If j = lastcol Then
Rows(t).Delete
t = t + 1
End If
Else
'Note that doing this row skip, may prevent user from checking other columns for blanks.
t = t + 1
End If
Next
Loop
End Sub
Here is the quickest way to Delete all blank Rows ( based on one Columns )
Dim lstRow as integet, ws as worksheet
Set ws = ThisWorkbook.Sheets("NameOfSheet")
With ws
lstRow = .Cells(Rows.Count, "B").End(xlUp).Row ' Or Rows.Count "B", "C" or "A" depends
.Range("A1:E" & lstRow).SpecialCells(xlCellTypeBlanks).EntireRow.Delete
End with