VBA partial string CountIf inside of cell formulas (not Values) - excel

So I have a worksheet with a bunch of linked cells set to a UNC path. For example, lets say that Cell A1 is equal to:
='\\corp\StackOverflow\[Example01.xlsx]TestSheet'!$A$1
and Cell A2 is equal to:
='\\corp\StackOverflow\[Example02.xlsx]TestSheet'!$A$1
Is there a way to have a CountIf for a partial string of "StackOverflow" for the entire worksheet? It would return a 2.
Sub Search()
Dim r As Range, s As String, i As Long
Dim ws As Worksheet
s = "StackOverflow"
For Each ws In ActiveWorkbook.Worksheets
Set r = ws.Cells
i = Application.WorksheetFunction.CountIf(r, "*" & s & "*")
MsgBox ("i: " & i)
Next ws
End Sub
This is what I am using, but it always returns a 0 because I think it only looks at the Values. I want it to look inside of the formula (even if that cell normally returns a #REF! error). And yes, if it could look at the entire worksheet's cells, because I want to use it on a For Each ws basis.

One can search the text of formula cells for a specific string and increase the counter.
Sub Search()
Dim r As Range, s As String, i As Long
Dim ws As Worksheet
s = lcase("StackOverflow")
For Each ws In ActiveWorkbook.Worksheets
For Each rng In ws.Cells.SpecialCells(xlCellTypeFormulas)
If LCase(rng.Formula) Like "*" & s & "*" Then i = i + 1
Next
Next ws
MsgBox ("i: " & i)
End Sub

Related

How to find a Excel cell has hyperlink

I have data in Column A in excel..I am iterating through column and i need to find if a cell value has hyperlink init.
LR=Activeworkbook.Worksheets("Emp").Range("A65000").End(xlup).Row
for j=1 to LR
if Thisworkbooks.Worksheets("Emp").cells(j,1)="" then 'Logic to find hyperlink
'Function
end if
next
Identify Cells Containing Hyperlinks
As Red Hare already mentioned in the comments, it is best tested with something like the following:
Dim cell As Range: Set cell = Sheet1.Range("A1")
If cell.Hyperlinks.Count > 0 Then ' has a hyperlink
Else ' has no hyperlink
End If
that is, using the Hyperlinks.Count property of the Hyperlinks object returned by the cell's Hyperlinks property which is a collection of hyperlinks in a range (in this case, a single cell). For a single cell, the Count property will return only 0 or 1 so you could actually use
If cell.Hyperlinks.Count = 1 Then ' has a hyperlink
instead.
Example Code
Option Explicit
Sub IdentifyCellsWithHyperlink()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' If it's not, modify accordingly.
Dim ws As Worksheet: Set ws = wb.Worksheets("Emp")
Dim rg As Range
Set rg = ws.Range("A2", ws.Cells(ws.Rows.Count, "A").End(xlUp))
Dim cell As Range
For Each cell In rg.Cells
If cell.Hyperlinks.Count > 0 Then ' has a hyperlink
Else ' has no hyperlink
End If
Next cell
End Sub
Here is something that can be used to run through each row to determine if it can be set as a hyperlink. Kinda hard to figure out what the range of possible solutions are that will work for you without fully understanding the context...
Private Sub cmdFollowLink_Click()
CreateHyperlink Me!cmdFollowLink, Me!txtSubAddress, _
Me!txtAddress
End Sub
Sub CreateHyperlink(ctlSelected As Control, _
strSubAddress As String, Optional strAddress As String)
Dim hlk As Hyperlink
Select Case ctlSelected.ControlType
Case acLabel, acImage, acCommandButton
Set hlk = ctlSelected.Hyperlink
With hlk
If Not IsMissing(strAddress) Then
.Address = strAddress
Else
.Address = ""
End If
.SubAddress = strSubAddress
.Follow
.Address = ""
.SubAddress = ""
End With
Case Else
MsgBox "The control '" & ctlSelected.Name _
& "' does not support hyperlinks."
End Select
End Sub

Retrieving the value of the cell in the same row in the specific column using VBA

I'm currently working on the statement that implies, that if any of the cell value in the range of "G3:ED3" in the worksheet named "Matrix", matches the cell value in the range of "H3:H204" in the worksheet named "Staff" and any cell value in the range "G5:ED57" in the "Matrix" worksheet is numeric, then the value of the cell in a column B, that intersects the numeric value, is retrieving to the required cell address in the target template.
Here's what I have tried so far:
Dim rng1 As Range
Set rng1 = Worksheets("Matrix").Range("G3:ED3")
Dim rng2 As Range
Set rng2 = Worksheets("Staff").Range("H3:H204")
Dim rng3 As Range
Set rng3 = Worksheets("Matrix").Range("G5:ED57")
For Each cell In Range(rng1, rng2, rng3)
While IsNumeric(rng3) And rng1.Value = rng2.Value
Worksheets("Matrix").Columns("B").Find(0).Row =
Worksheets("TEMPLATE_TARGET").Value(12, 4)
Wend
I'm unsure how to define the statement, so the code would automatically retrieve the value of the cell in a column B, that intersects any cell that contains numeric value in the rng3. Any recommendations would be highly appreciated.
it's probably best you take a proper look into documentation / whatever learning resource you are using as you seem to have missunderstood how While works (alongside few other things)
While is a loop within itself, it does not act as an Exit Condition for the For loop.
With all that said, it's also unclear from your question what you're trying to achieve.
My presumption is, that you want to check for all the conditions and
then if they do match, you're looking to paste the result into the
"TEMPLATE" sheet
First we create a function th ceck for values in the two data ranges:
Private Function IsInColumn(ByVal value As Variant, ByVal inSheet As String) As Boolean
Dim searchrange As Range
On Error Resume Next ' disables error checking (Subscript out of range if sheet not found)
' the range we search in
If Trim(LCase(inSheet)) = "matrix" Then
Set searchrange = Sheets("Matrix").Range("G5:ED7")
ElseIf Trim(LCase(inSheet)) = "staff" Then
Set searchrange = Sheets("Staff").Range("H3:H204")
Else
MsgBox ("Sheet: " & inSheet & " was not found")
Exit Function
End If
On Error GoTo 0 ' re-enable error checking
Dim result As Range
Set result = searchrange.Find(What:=value, LookIn:=xlValues, LookAt:=xlWhole)
' Find returns the find to a Range called result
If result Is Nothing Then
IsInColumn = False ' if not found is search range, return false
Else
If IsNumeric(result) Then ' check for number
IsInColumn = True ' ding ding ding, match was found
Else
IsInColumn = False ' if it's not a number
End If
End If
End Function
And then we run the procedure for our search.
Private Sub check_in_column()
Dim looprange As Range: Set looprange = Sheets("Matrix").Range("G3:ED3")
Dim last_row As Long
For Each cell In looprange ' loops through all the cells in looprange
'utlizes our created IsInColumn function
If IsInColumn(cell.Value2, "Matrix") = True And _
IsInColumn(cell.Value2, "Staff") = True Then
' finds last actively used row in TEMPLATE_TARGET
last_row = Sheets("TEMPLATE_TARGET").Cells(Rows.Count, "A").End(xlUp).Row
' pastes the found value
Sheets("TEMPLATE_TARGET").Cells(last_row, "A") = cell.Value2
End If
' otherwise go to next cell
Next cell
End Sub
I redefined your ranges a little in my example for utility reasons but it works as expected
In my Matrix sheet: (staff sheet only contains copy of this table)
In my TEMPLATE_TARGET sheet after running the procedure.
Result as expected
If I understand well, I would have done something like this:
Option Explicit
Public Sub Main()
Dim wsMatrix As Worksheet: Set wsMatrix = ThisWorkbook.Worksheets("Matrix")
Dim rgMatrix As Range: Set rgMatrix = wsMatrix.Range("G3:ED3")
Dim cell As Range
Dim cellStaff As Range
Dim cellMatrix As Range
For Each cell In rgMatrix
If CheckRangeStaff(cell.Range) And CheckRangeMatrix() Then
'Process in a column B? Which sheet? Which cell? Which Process?
End If
Next cell
Debug.Print ("End program.")
End Sub
Public Function CheckRangeStaff(ByVal value As String) As Boolean
Dim wsStaff As Worksheet: Set wsStaff = ThisWorkbook.Worksheets("Staff")
Dim rgStaff As Range: Set rgStaff = wsStaff.Range("H3:H204")
Dim res As Boolean
Dim cell As Range
res = False
For Each cell In rgStaff
If cell.value = value Then
res = True
Exit For
End If
Next cell
CheckRangeStaff = res
End Function
Public Function CheckRangeMatrix() As Boolean
Dim wsMatrix As Worksheet: Set wsMatrix = ThisWorkbook.Worksheets("Matrix")
Dim rgMatrix As Range: Set rgMatrix = wsMatrix.Range("G5:ED57")
Dim res As Boolean
Dim cell As Range
res = False
For Each cell In rgMatrix
If IsNumeric(cell.value) Then
res = True
Exit For
End If
Next cell
CheckRangeMatrix = res
End Function

Excel autofill between worksheets

I have an excel document with ~300 similar worksheets and 1 worksheet with a list of names. Each of these 300 worksheets has a specific cell where I need to fill a name from the list. The list and the sheets are in the same order (for example sheet1 needs a name from List!C1, sheet2 from List!C2 etc). I looked into VLOOKUP, but there isn't any reference data I can use.
I think for similar task you need use VBA Macros like this:
Sub DataFromList()
Dim nameSht As String: nameSht = "List"
Dim shtList As Worksheet
Set shtList = ThisWorkbook.Worksheets(nameSht)
Dim columnWithData As String: columnWithData = "C"
Dim n%: n = 0 ' start from 1 row (0 + 1)
' specific cell where you need to fill a name from the list
Dim addressForData As String: addressForData = "B2"
For Each sht In ThisWorkbook.Worksheets
If sht.Name <> nameSht Then
n = n + 1
sht.Range(addressForData).Formula = "=" & nameSht & "!" & columnWithData & n
End If
Next sht
End Sub
of course, it possible only if address of "specific cell" same in all sheet

Data validation macro

I'm creating an Excel sheet which different people are going to add to, so am wondering if there's any simple way to check for the row where user starts writing being filled?
For example, if user starts typing in cell A1, macro checks if the cells are filled on the same row.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim rsave As Range
Dim cell As Range
Set rsave = Sheet1.Range("a1:i1")
For Each cell In rsave
If cell = "" Then
Dim missdata
missdata = MsgBox("missing data", vbOKOnly, "Missing Data")
Cancel = True
cell.Select
Exit For
End If
Next cell
End Sub
to expand on the suggested solution, you can do the following. Instead of looping through each cell, your problem can be solved efficiently with two lines of code:
'get the used range
Set rsave = Sheet1.Range("a1:i1")
'Select all blank(not yet filled) cells
rsave.SpecialCells(xlCellTypeBlanks).Select
This will select all cells which've not been filled in the range a1:i1 of the sheet. Alternatively, you can use some colour to make it more explicit. If it works, don't forget to accept the answer.
If by saying "data validation", you mean check for blanks, you can use this:
Sub Test()
Dim wrng As Range
Set wrng = ActiveSheet.UsedRange
MsgBox "The data in a range: '" & wrng.Address & "' are" & IIf(IsValidData(wrng), "", "n't") & " valid"
Set wrng = Nothing
End Sub
Function IsValidData(rng As Range) As Boolean
IsValidData = rng.SpecialCells(xlCellTypeBlanks).Count = 0
End Function
Note, that the UsedRange method returns a range starting from A1 cell. So, you need to add extra code to select a range occupied by the data (skip blanks rows and columns).
Sub Test()
Dim wrng As Range
Set wrng = GetDataRange()
MsgBox "The data in a range: '" & wrng.Address & "' are" & IIf(IsValidData(wrng), "", "n't") & " valid"
End Sub
Function GetDataRange() As Range
Dim wrng As Range, c As Range, saddr As String
Dim pos As Integer
'get used range
Set wrng = ActiveSheet.UsedRange
'find first non-empty cell in a used range
saddr = ActiveSheet.Range(wrng.End(xlToLeft).Address, wrng.End(xlUp).Address).Address
pos = InStr(1, saddr, ":")
'skip blanks rows and set new range
Set GetDataRange = ActiveSheet.Range(Mid(saddr, pos + 1, Len(saddr) - pos) & ":" & wrng.SpecialCells(xlCellTypeLastCell).Address)
Set wrng = Nothing
End Function
Good luck!

VLookup range in another worksheet dynamically

I am trying to use a function that will allow me to import a range from a previous worksheet. I am not sure that my current macro allows this. I can call the previous worksheet manually, but not with the function that I have.
Here is the function that works fine when I manually input the worksheet name:
=IFERROR(VLOOKUP(D3,Aug9Daily!$D$3:$F$50,3, FALSE),"")
Here is the function that I am attempting to use:
=IFERROR(VLOOKUP(D3,NextSheetName()$D$3:$F$50,3, FALSE),"")
This is the VBA that I am using for the NextSheetName macro:
Function NextSheetName(Optional WS As Worksheet = Nothing) As String
Application.Volatile True
Dim S As String
Dim Q As String
If IsObject(Application.Caller) = True Then
Set WS = Application.Caller.Worksheet
If WS.Index = WS.Parent.Sheets.Count Then
With Application.Caller.Worksheet.Parent.Worksheets
Set WS = .Item(1)
End With
Else
Set WS = WS.Next
End If
If InStr(1, WS.Name, " ", vbBinaryCompare) > 0 Then
Q = "'"
Else
Q = vbNullString
End If
Else
If WS Is Nothing Then
Set WS = ActiveSheet
End If
If WS.Index = WS.Parent.Worksheets.Count Then
With WS.Parent.Worksheets
Set WS = .Item(1)
End With
Else
Set WS = WS.Next
End If
Q = vbNullString
End If
NextSheetName = Q & WS.Name & Q
End Function
What am I doing wrong? Is there a better way to select a range from another worksheet dynamically?
Try this to see if it works for you to fix your function's output:
NextSheetName = Q & WS.Name & Q & "!"
And then you will need to concatinate the output inside of an indirect function like this:
=IFERROR(VLOOKUP(D3,INDIRECT(NextSheetName() & "$D$3:$F$50"),3, FALSE),"")
I've found this little UDF to be handy:
Function sheet_offset(rng As Range, i As Integer) As Range
Application.Volatile 'necessary since value can change even when values of parameters do not
Set sheet_offset = rng.Worksheet.Parent.Worksheets.Item(rng.Worksheet.Index + i).Range(rng.Address)
End Function
which offsets rng by i sheets - eg, i=0 means the same sheet, i=-1 means the previous sheet, and i=1 means the next sheet.
In your example, you'd use:
IFERROR(VLOOKUP(D3,sheet_offset($D$3:$F$50,1),3, FALSE),"")
which would offset the range to reference the next worksheet.
Note that to make references relative to the current sheet (like yours) you would not specify the worksheet. To make absolute references, just specify a worksheet in the reference (eg 'Sheet1'!$D$3:$F$50) and that becomes your origin (the sheet referenced when i=0)

Resources