I'm new to Excel VBA and was looking for some help in fixing my code. So basically to provide colour on what I have, I have an excel database, and a word document. In the word document I have bookmarked section headers (reffered to as "cat", "dog", and "bird") and in a row on the excel database I have "dog" and "bird".
What I am trying to do is write a code that compares the elements of the array (which are strings) to the cell values within a range declared in an excel database. For the values that exist in the array but not in the declared excel range, I want to delete those values (i.e. the bookmark) from the word document.
If anyone could provide me with feedback, ideas, or example codes it would be greatly appreciated.
Thanks.
Sub ArrayToDatabase()
Dim myRange As Variant
Set myRange = Range("C7:AP7")
Dim myArray As Variant
myArray = Array("cat", "dog", "bird")
Dim i As Integer
Dim reqName As Object
For i = LBound(myArray) To UBound(myArray)
Set reqName = myArray(i).Value
If myRange.Validation(reqName) = False Then
wdApp.ActiveDocument.Bookmarks(reqName).Range._
Paragraphs(1).Range.Delete
End If
Next i
End Sub
Logic
Use .Find to check if the keywords are present in the range or not.
Store the relevant keywords in a comma delimited string which will later be converted into an array
Open word doc
Loop through the array and delete the bookmarks
Is this what you are trying?
Option Explicit
Sub Sample()
Dim myArray As Variant, BookMarksToDelete As Variant
Dim oWordApp As Object, oWordDoc As Object
Dim sTemp As String, FlName As String
Dim aCell As Range, myRange As Range
Dim i As Long
'~~> Change this to the relevant sheet
Set myRange = ThisWorkbook.Sheets("Sheet1").Range("C7:AP7")
myArray = Array("cat", "dog", "bird")
'~~> Change this to the relevant word document
FlName = "C:\Users\Siddharth\Desktop\DeleteMeLater.docx"
For i = LBound(myArray) To UBound(myArray)
'~~> Check if the word exists in the range or not
Set aCell = myRange.Find(What:=myArray(i), LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
'~~> If it doesn't then store it in a comma delimited string
If aCell Is Nothing Then
sTemp = sTemp & "," & myArray(i)
Else
Set aCell = Nothing
End If
Next i
sTemp = Mid(sTemp, 2)
If Not Len(Trim(sTemp)) = 0 Then
'~~> Convert comma delimited string to array
BookMarksToDelete = Split(sTemp, ",")
'~~> Open word document
Set oWordApp = CreateObject("Word.Application")
oWordApp.Visible = True
Set oWordDoc = oWordApp.Documents.Open(FlName)
'~~> Delete the bookmarks
For i = LBound(BookMarksToDelete) To UBound(BookMarksToDelete)
oWordDoc.Bookmarks(BookMarksToDelete(i)).Delete
Next i
End If
MsgBox "Done"
End Sub
Does your code work? It's a little unclear what you're asking, unless that's just for feedback. All I personally have to say is the way you declare variables.
So if you know what the variable will hold, it's best to declare it as such. For example,
Dim myRange as Range
Dim myArray(2) as String
myArray = {"cat", "dog", "bird"}
Dim reqName as String
I'm no expert either, just trying to help! Feel free to ask any questions, but I can't guarantee I have an answer.
Related
I want to find a date in a range, or rather part of a date. For example, I have the month and the year from a user input, stored in two variables userInputMonth and userInputYear, and would now like to find out in which row they appear.
Option Explicit
Sub CheckDate()
Dim wb As Workbook
Dim ws As Worksheet
Dim userInputYear As String
Dim userInputMonth As String
Dim rngDate As Range
Dim foundCell As Range
Set wb = ThisWorkbook
Set ws = wb.Sheets(2)
userInputYear = Right(wb.Sheets(1).Range("A1").Value, 4) 'e.g. "2019"
userInputMonth = Mid(wb.Sheets(1).Range("A1").Value, 2, 2) 'e.g. "09"
Set rngDate = ws.Range("A3:A11")
Set foundCell = rngDate.Find("??." & userInputMonth & "." & userInputYear)
Debug.Print foundCell.Row '-> error
'=====Trying out stuff=====
Set foundCell = rngDate.Find(userInputMonth)
Debug.Print foundCell.Row 'works
Set foundCell = rngDate.Find(userInputMonth & ".")
Debug.Print foundCell.Row '-> error
Set foundCell = rngDate.Find("12.2019")
Debug.Print foundCell.Row '-> error
End Sub
I guess the format is the problem, but how do I deal with this, but I don't know how to apply something like CStr to this issue
edit: The data in rngDate looks like this: 31.12.2019 (formatted as date). A1 is text (e.g. A12 2019).
In my opinion you have to decide which type of data you want to manipulate. Do you prefer working with dates or strings ? After that choice, it will be easier to determine which operations will be necessary and which method or function will be applicable (you cannot do the same thing with dates or strings). Cheers
I am new in VBA, so I am not familiar with all its capabilities. I have a worksheet with many "tables" in it. By tables, I do not mean actual Excel Table Object but chunks of data that are separated into "tables" via color/border formatting.
I can find which cell a specific table starts by finding the cell which contains "RefNum:". However, to avoid false detection of table, I would like to double check the next cells after it.
Essentially, what I want is not just to find "RefNum:" but to find the position of 3x1 array which contains the ff in correct order:
- RefNum:
- Database:
- ToolID:
Only then can I be sure that what I found was a real table.
I am thinking of finding "RefNum:" and doing if-else for verification, but maybe there is a more sophisticated way of doing it?
Thanks for the help.
Try this code:
Sub FindTables()
Dim cell As Range
Dim firstAddress As String
With Range(Cells(1, 1), Cells(Rows.Count, Columns.Count))
Set cell = .Find("RefNum", LookIn:=xlValues)
firstAddress = cell.Address
Do
'check cell next to "RefNum" and one after that
If LCase(cell.Offset(0, 1).Value) = "database" And LCase(cell.Offset(0, 2).Value) = "toolid" Then
'here, cell is first cell (ref num) of the table
cell.Interior.ColorIndex = 4
End If
Set cell = .FindNext(cell)
Loop While Not cell Is Nothing And cell.Address <> firstAddress
End With
End Sub
Based from Michal's code, this is the answer I came up with. It works well except for one thing. It does not detect the 1st cell address, only the 2nd and succeeding. Can anyone see where I made an error?
Option Explicit
Public Sub LogSum()
'Declare variables
Dim shtMacro As Worksheet 'Sheet where macro button is located
Dim Fname As Variant 'List of user-selected files
Dim bookLOG As Workbook 'Active logsheet file
Dim shtLOG As Worksheet 'Active worksheet from current active workbook
Dim WS_Count As Integer 'Number of worksheets in active workbook
Dim CellDB As Range 'First cell output for find "RefNum"
Dim FirstAddress As String 'Address of the first CellDB
Dim i As Integer, j As Integer 'Loop iterators
'Prompt user to get logsheet filenames
Fname = Application.GetOpenFilename("ALL files (*.*), *.*,Excel Workbook (*.xlsx), *.xlsxm,Excel 97-2003 (*.xls), *.xls", , "Open Logsheet Files", , True)
If (VarType(Fname) = vbBoolean) Then Exit Sub
DoEvents
'Iterate per workbook
For i = LBound(Fname) To UBound(Fname)
Set bookLOG = Workbooks.Open(Filename:=Fname(i), UpdateLinks:=0, _
ReadOnly:=True, IgnoreReadOnlyRecommended:=True) 'Open workbook i
WS_Count = bookLOG.Worksheets.Count 'Store max number of sheets
Debug.Print bookLOG.Name 'Print the workbook filename in log
'Iterate per worksheet in workbook i
For j = 1 To WS_Count
Debug.Print bookLOG.Worksheets(j).Name 'Print the current sheet in log
Set CellDB = bookLOG.Worksheets(j).UsedRange.Find("RefNum:", LookIn:=xlValues) 'Search for "RefNum:"
If (Not (CellDB Is Nothing)) Then
bookLOG.Worksheets(j).UsedRange.Select
Debug.Print "Something's found here."
FirstAddress = CellDB.Address 'Assign the 1st search address
Debug.Print FirstAddress
Do 'Check cell next to "RefNum:" and one after that
If CellDB.Offset(1, 0).Value = "DATABASE: " And CellDB.Offset(2, 0).Value = "Tester:" Then
Debug.Print "Yay! Got You"
Debug.Print CellDB.Address
Else
Debug.Print "Oops. False Alarm"
End If
Set CellDB = bookLOG.Worksheets(j).UsedRange.FindNext(CellDB)
Loop While CellDB.Address <> FirstAddress
Else
Debug.Print "Nothing found here."
End If
Next j
Next i
End Sub
I'm trying to write some VBA with a Microsoft Word Document that will search for a text string within itself, and once it has found it, will return the preceding bookmark name.
I currently have the below code;
Public Sub FindDocument()
Dim wrdThis As Document
Dim strSearch As String
Dim myRange As Range
Dim lngBookMark As Long
Dim lngHeadingName As Long
Dim varBookmarks As Variant
Dim i As Integer
Set wrdThis = ThisDocument
Set myRange = wrdThis.Content
strSearch = "ID: VTER"
varBookmarks = wrdThis.GetCrossReferenceItems(wdRefTypeBookmark)
myRange.Find.Execute FindText:=strSearch, Forward:=True
If myRange.Find.Found = True Then
lngBookMark = myRange.BookmarkID
MsgBox "Search text found in bookmark " & varBookmarks(lngBookMark)
End If
End Sub
I can't seem to get the code to return a unique identifier for the preceding bookmark as the text I am searching for will be found between 2 bookmarks.
Any help would be greatly appreciated.
The only way, really, to pick up bookmarks is to query them from a Range. In your case, you need the Range from the Found range backwards. Simplest would simply be to set the Range back to the start of the Document, then pick up the last bookmark. The following code sample, based on your original, illustrates this.
Note that I've changed ThisDocument to ActiveDocument. ThisDocument is the document object in which your VBA code resides. I'm assuming you want the code to run on whichever document is currently being worked on? In that case, ActiveDocument is correct.
Sub FindThenPrevBookmark()
Dim wrdThis As Document
Dim strSearch As String
Dim myRange As Range, rngToStart As word.Range
Dim bkm As word.Bookmark
'Dim lngBookMark As Long
'Dim lngHeadingName As Long
'Dim varBookmarks As Variant
'Dim i As Integer
Set wrdThis = ActiveDocument
Set myRange = wrdThis.content
strSearch = "Home"
'Ensure that Execute and Found are performed on the same FIND
With myRange.Find
.Execute findText:=strSearch, Forward:=True
If .found = True Then
'Always use DUPLICATE to "copy" a Range object!
Set rngToStart = myRange.Duplicate
rngToStart.Start = wrdThis.content.Start
If rngToStart.Bookmarks.Count > 0 Then
Set bkm = rngToStart.Bookmarks(rngToStart.Bookmarks.Count)
MsgBox "Search text found in bookmark " & bkm.Name
End If
End If
End With
End Sub
I'm working on an Excel Spreadsheet that pulls a pick list from the SQL Database and populates the sheet. It then prompts the user to Scan a Part number. I am trying to locate the part number in Column A, and return the row for the part number.
The part number begins as a Variant type, but thinking that type was the problem, I converted it to string by setting its value to another variable.
Finally, I found this snippet of code (I've tried many and none have worked so far), and it works when you specify a number (123456789012) as in the code below. It does not work if you replace that number with the variable sPart nor scanPart.
I need it to work to find the row of the variable sPart (String) or scanPart (Variant). What am I doing wrong?
Function ReturnRowNumber()
Dim ws As Excel.Worksheet
Set ws = ActiveSheet
Dim scanPart As Variant
Dim sPart As String
Dim FoundRow As String
scanPart = InputBox("Scan the first part number", "Part Number") 'Get Part Number
sPart = scanPart
MsgBox sPart
Dim SearchRange As Range
Dim FindRow As Range
Set SearchRange = Range("A1", Range("A65536").End(xlUp))
Set FindRow = SearchRange.Find(123456789012#, LookIn:=xlValues, lookat:=xlWhole)
MsgBox FindRow.Row
End Function
Thanks in advance for any help!
Dana
The code as written in your post will NEVER work, as the syntax is not correct, especially in the .Find statement. Perhaps that issue was throwing you in the
wrong direction, thinking it was a data type issue.
Please see this code. Tested on both string and numerical values.
Option Explicit
Sub Test()
Dim sPart As String
sPart = InputBox("Scan the first part number", "Part Number") 'Get Part Number
MsgBox ReturnRowNumber(sPart)
End Sub
Function ReturnRowNumber(sPart As String) As Long
Dim ws As Worksheet
Set ws = Worksheets("Sheet1") 'be more explicit than 'ActiveSheet
Dim SearchRange As Range
Dim FindRow As Range
Set SearchRange = ws.Range("A1", ws.Range("A65536").End(xlUp))
Set FindRow = SearchRange.Find(sPart, LookIn:=xlValues, lookat:=xlWhole)
If Not FindRow Is Nothing Then ReturnRowNumber = FindRow.Row
End Function
From your code and the description of your problem it sounds like what is happening is you are defining a variable as Variant, but that Varian is really a String (thus, never use Variant unless you have a very specific reason to).
Something like:
Dim Foo as Variant
Dim Bar as Long
Foo = "123"
Bar = "123"
Is basically like saying:
Dim Foo as String
Dim Bar as Long
Foo = "123"
Bar = CLng("123")
The reason why this is important is because:
12345 <> "12345"
They are different values. One is a Long representation, the other is a String representation.
The solution to your problem? It depends on how your initial values are stored. If you are using String representations of your barcodes then you want to declare your barcode as a String, and use that String to search. It seems though that you are actually storing whole numbers, and if that is the case you will want to declare your barcode as a Long.
If, by some curse, you are storing Barcodes as Strings and as whole numbers, well you will either need to choose one or the other, or you will need to use a more robust find method (I recommend dictionaries).
Function ReturnRowNumber()
Dim ws As Excel.Worksheet
Set ws = ActiveSheet
Dim scanPart As Variant
Dim sPart As String
Dim FoundRow As String
Dim xlCell as Range
scanPart = InputBox("Scan the first part number", "Part Number") 'Get Part Number
sPart = scanPart
Dim SearchRange As Range
Dim FindRow As Range
Set SearchRange = Range(Range("A1"), Range("A1").End(xlDown))
Set xlCell = ActiveCell
Application.ScreenUpdating = False
SearchRange.Select
Set FindRow = SearchRange.Find(What:=sPart, After:=ActiveCell, SearchOrder:=xlByRows)
xlCell.Select
Application.ScreenUpdating = True
MsgBox FindRow.Row
End Function
It looks like your find function was not formatted properly. The code above works perfectly for me
I'm trying to get data from an excel sheet to a word document. I try using the 'Find' function however I keep getting the same error "Type mismatch" on this line:
Set FoundRange = .Cells.Find(260707)
Here is the subroutine I am running.
Sub GetID()
Dim oXL As Object
Dim oWB As Object
Dim oSheet As Object
Dim WorkbookToWorkOn As String
Dim FoundRange As Range
Dim dummyvar As String
'Start a new instance of Excel
Set oXL = CreateObject("Excel.Application")
'Line to make Excel Visible or not
oXL.Visible = False
'Open the workbook
'Set the file path to access the 'Certified Personnel' table
WorkbookToWorkOn = "\\DataSource\CertifiedPersonnel.xlsx"
Set oWB = oXL.Workbooks.Open(FileName:=WorkbookToWorkOn, ReadOnly:=True, IgnoreReadOnlyRecommended:=True)
Set oSheet = oXL.ActiveWorkbook.Sheets("tblCertifiedPersonnel")
'End of Excel Automation. Everything from this point on can reference Excel.
With oSheet
dummyvar = .Cells(1, 2).Text
.Cells(1, 2).Select
'Set the range of the cell containing the ID number
'If the ID was found
Set FoundRange = .Cells.Find(260707)
If Not FoundRange Is Nothing Then
'Set the NTlogin equal to the value of column 1, and row corresponding to the FoundRange row
NTlogin = .Cells(FoundRange.Rows, 1).Text
Role = .Cells(FoundRange.Rows, 4).Text
End If
End With
'End Excel reference
oXL.ActiveWorkbook.Close SaveChanges:=False
oXL.Application.Quit
Set oXL = Nothing
Set oWB = Nothing
Set oSheet = Nothing
End Sub
I know it is accessing the correct workbook, because the dummy variable (dummyvar) is returning the value I expect. I have tried several things related to the 'Find' function, however I have not been able to get it to work. Any ideas? Much appreciated.
You are using late binding and have FoundRange declared as a Range. Since this is in a Word document, you're implicitly declaring it as a Word.Range here:
Dim FoundRange As Range
.Find is returning an Excel.Range. Change it to:
Dim FoundRange As Object
With the assumption that the ID values are stored as text in the worksheet, either with a cell type of Text or with an apostrophe/single-quote in front of the number, you may need to format the ID as string. With the further assumption that eventually you may want to pass the ID via parameter to the procedure, give this a try:
Set FoundRange = .Cells.Find(CStr(260707))
That will also allow you to replace the constant number with a variable if desired.