Search based on contents of cell - vba

I have a command button set up, and I assigned a macro to it. I need the button to take the contents of cell B2 and search for it in column A on the next sheet. Here is my code. As you can see, it's looking for the literal text that was there when I recorded the macro. How do I get that to search for whatever is entered into B2?
Sub Button3_Click()
Range("B2").Select
Selection.Copy
Sheets("Sheet3").Select
Cells.Find(What:="", After:=ActiveCell, LookIn:=xlFormulas, LookAt:= _
xlWhole, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False).Activate
End Sub

This might be overkill for what you need, but I've always believed in error checking as well as using complete and flexible code, so here's what you asked for, with comments:
Sub btnFindText()
'Declare variables
Dim wb As Workbook 'Used to store and reference the ActiveWorkbook
Dim wsActive As Worksheet 'Used to store and reference the ActiveSheet (the sheet containing the button)
Dim wsNext As Worksheet 'Used to store and reference the next sheet
Dim rngFound As Range 'Used to find a matching cell in the next sheet, if any
Dim rngText As Range 'Used to store and reference the cell that will contain the text
Dim sFind As String 'Used to store and reference the text in wsActive, cell B2
'Set variables
Set wb = ActiveWorkbook
Set wsActive = wb.ActiveSheet
Set rngText = wsActive.Range("B2")
sFind = wsActive.Range("B2").Value
'Perform error checking and return appropriate errors
'Check if text to search for was provided
If Len(sFind) = 0 Then
rngText.Select
MsgBox "No text provided in cell " & rngText.Address(0, 0), , "No Search Value"
Exit Sub
End If
'Check if there is a sheet after the activesheet
If wsActive.Index = wb.Sheets.Count Then
MsgBox "There is not a sheet after this one to search on", , "Next Sheet Unavailable"
Exit Sub
End If
'Next sheet found, set the wsNext variable and search for the text
Set wsNext = wb.Sheets(wsActive.Index + 1)
Set rngFound = wsNext.Columns("A").Find(sFind, , , xlWhole)
'Check if anything was found
If rngFound Is Nothing Then
'Nothing found, return error
MsgBox "No matches found for [" & sFind & "] within column A of " & wsNext.Name, , "No Matches"
Else
'Match found, prompt if user wants to go to its location
If MsgBox("Match found for [" & sFind & "] at '" & wsNext.Name & "'!" & rngFound.Address(0, 0) & Chr(10) & "Go to cell?", vbYesNo, "Match Found") = vbYes Then
wsNext.Activate
rngFound.Select
End If
End If
End Sub
Additionally, you can do this with an Inputbox instead of using cell B2 as the text entry. The code is mostly the same, I'm putting it here for you to compare/contrast, as well as hopefully learn how to do both methods. Note that this method doesn't require to check if there's a next sheet, because we're not using an input cell. It only needs to know what sheet to search on.
Sub btnFindText2()
'Declare variables
Dim wb As Workbook 'Used to store and reference the ActiveWorkbook
Dim wsSearch As Worksheet 'Used to store and reference the worksheet that will be searched
Dim rngFound As Range 'Used to find a matching cell in the next sheet, if any
Dim sFind As String 'Used to get the search text from an inputbox
'Set variables
Set wb = ActiveWorkbook
Set wsSearch = wb.Sheets("Sheet3") 'In your provided sample code, you searched on Sheet3. Update this to correct sheetname
sFind = InputBox("Enter Part Number:")
'Perform error checking and return appropriate errors
'Check if text to search for was provided
If Len(sFind) = 0 Then Exit Sub 'Pressed cancel
'Because we're using an inputbox, no need to use the Next Sheet stuff
'Just need to search for the text
Set rngFound = wsSearch.Columns("A").Find(sFind, , , xlWhole)
'Check if anything was found
If rngFound Is Nothing Then
'Nothing found, return error
MsgBox "No matches found for [" & sFind & "] within column A of " & wsSearch.Name, , "No Matches"
Else
'Match found, prompt if user wants to go to its location
If MsgBox("Match found for [" & sFind & "] at '" & wsSearch.Name & "'!" & rngFound.Address(0, 0) & Chr(10) & "Go to cell?", vbYesNo, "Match Found") = vbYes Then
wsSearch.Activate
rngFound.Select
End If
End If
End Sub
EDITS: Updated the Inputbox method code so that it doesn't use the wsNext portions, made minor adjustments in code for clarity, readability, and debugging.

Just pass Range("B2") as the value for the What parameter. For example:
Dim r As Range
Set r = Sheets("Sheet3").Range("A:A").Find(What:=Range("B2"), _
LookIn:=xlFormulas, LookAt:=xlWhole, MatchCase:=False)
If Not r Is Nothing Then
Debug.Print "Found at " & r.Address
' If you want to activate it...
r.Activate
End If
If you want to search for values instead of formulas (which is what your original macro was doing), replace xlFormulas with xlValues.

Related

Copy data from one excel workbook to another while retaining formatting

I am new to excel VBA. I have already written VBA code to select any Excel file and copy path of that file to cell A1. Using the path I am trying to copy contents of source file, Sheet7, while retaining cell formatting i.e. bold, borders, colors, etc.
My first error is appearing for file path. Currently cell A1 value = C:\Users\Personal\Documents\Excel files\Dummy-Data - Copy.xlsx.
When I try to read value of A1 cell, VBA throws me an error "Sorry, we couldn't find. Is it possible it was moved, renamed or deleted?" and automatically clears the value of cell A1. But when I give the same path directly in VBA script, it works! Can someone tell me how to get this fixed?
My second doubt is around copying cell formats. When I use wksht.paste to paste copied content to Sheet2, it just pastes all cell values without formatting. But when I try to use PasteSpecial following error occurs- "Application-defined or object-defined error" . Can someone help me correct this please?
Sub Button1_Click()
' define variables
Dim lastRow As Long
Dim myApp As Excel.Application
Dim wbk As Workbook
Dim wkSht As Object
Dim filePath As Variant
'on error statement
On Error GoTo errHandler:
' Select file path
Set myApp = CreateObject("Excel.application")
Sheet2.Range("A1").Value = filePath
Set wbk = myApp.Workbooks.Open(filePath)
'Set wbk = myApp.Workbooks.Open("C:\Users\Personal\Documents\Excel files\Dummy-Data - Copy.xlsx")
' Copy contents
Application.ScreenUpdating = False
lastRow = wbk.Sheets(7).Range("A" & Rows.Count).End(xlUp).Row
wbk.Sheets(7).Range("A2:Q" & lastRow).Copy
myApp.DisplayAlerts = False
wbk.Close
myApp.Quit
' Paste contents
Set wbk = Nothing
Set myApp = Nothing
Set wbk = ActiveWorkbook
Set wkSht = wbk.Sheets("Sheet2")
wkSht.Activate
Range("A2").Select
wkSht.Paste
'wkSht.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=False
Application.ScreenUpdating = True
Exit Sub
'error block
errHandler:
MsgBox "An Error has Occurred " & vbCrLf & "The error number is: " _
& Err.Number & vbCrLf & Err.Description & vbCrLf & _
"Please follow instruction sheet"
End Sub
My first error is appearing for file path. Currently cell A1 value = C:\Users\Personal\Documents\Excel files\Dummy-Data - Copy.xlsx. When I try to read value of A1 cell, VBA throws me an error "Sorry, we couldn't find. Is it possible it was moved, renamed or deleted?" and automatically clears the value of cell A1.
You're not setting a var's value to the value of a cell, you're setting the cell's value to a blank var thereby erasing the cell's value. It should be filePath = Sheet2.Range("A1").Value, (the reverse of what you have above).
When I use wksht.paste to paste copied content to Sheet2, it just pastes all cell values without formatting.
You're not just pasting between workbooks; you're pasting between workbooks open in separate application instances. You lose detail like formatting when pasting across instances. In any event, the separate Excel.Application seems wholly unnecessary.
Option Explicit
Sub Button1_Click()
' define variables
Dim lastRow As Long
Dim wbk As Workbook
Dim filePath As Variant
'on error statement
On Error GoTo errHandler:
' Select file path
filePath = Sheet2.Range("A1").Value
Set wbk = Workbooks.Open(filePath)
'Set wbk = Workbooks.Open("C:\Users\Personal\Documents\Excel files\Dummy-Data - Copy.xlsx")
' Copy contents & Paste contents
Application.ScreenUpdating = False
lastRow = wbk.Sheets(7).Range("A" & Rows.Count).End(xlUp).Row
wbk.Sheets(7).Range("A2:Q" & lastRow).Copy _
Destination:=Sheet2.Range("A2")
'shouldn't have to disable alerts
'Application.DisplayAlerts = False
wbk.Close savechanges:=False
'Application.DisplayAlerts = True
'
Application.ScreenUpdating = True
Exit Sub
'error block
errHandler:
MsgBox "An Error has Occurred " & vbCrLf & "The error number is: " _
& Err.Number & vbCrLf & Err.Description & vbCrLf & _
"Please follow instruction sheet"
End Sub
The naked worksheet codename references should be valid within ThisWorkbook.

Find cell containing greater 255 characters

My code below works perfectly to find a cell on a different worksheet when the string is small, however large text strings pull up an error. I have tried using error handling even just to give a MsgBox rather than open a VBA window when it errors.
Can anyone help, preferably find the cell with many characters or if not possible, put an error handler in to say something like, too large to search.
What the code does, is a have a range of cells with text in each cell. I can click on that cell, or a cell 2 columns to the right, then click the FIND button, to go in the next worksheet to find the exact same cell value. All cells are unique.
Sub Find_Cell()
Dim NA As Worksheet
Set NA = Worksheets("Notes Analysis")
LastRow = NA.Cells(Rows.Count, 2).End(xlUp).Row
On Error Resume Next
If Not Intersect(ActiveCell, Range("G19:G" & LastRow)) Is Nothing Then
Dim value As String 'Declare a string
value = ActiveCell.Offset(, -2) 'Get the value of the selected Cell
Dim ws As Worksheet
'ws is the worksheet from we are searching the value
'You have to change myWorkSheetName for you worksheet name
Set ws = ThisWorkbook.Worksheets("DEBT_SALE_ACTIVITY")
ws.Activate
Dim c As Range 'Declare a cell
Set c = ws.Cells.Find(value, LookIn:=xlValues) 'Search the value
If Not c Is Nothing Then 'If value found
c.Activate 'Activate the cell, select it
Else
MsgBox "Not found" 'shows a message "Not Found"
End If
Else
If Not Intersect(ActiveCell, Range("E19:E" & LastRow)) Is Nothing Then
Dim value2 As String 'Declare a string
value2 = ActiveCell 'Get the value of the selected Cell
Dim ws2 As Worksheet
'ws is the worksheet from we are searching the value
'You have to change myWorkSheetName for you worksheet name
Set ws2 = ThisWorkbook.Worksheets("DEBT_SALE_ACTIVITY")
ws2.Activate
Dim c2 As Range 'Declare a cell
Set c2 = ws2.Cells.Find(value2, LookIn:=xlValues) 'Search the value
If Not c2 Is Nothing Then 'If value found
c2.Activate 'Activate the cell, select it
Else
MsgBox "Not found" 'shows a message "Not Found"
End If
Else
MsgBox "Select an Account Note"
End If 'end the If for if active cell is in our notes
End If 'end the If for if active cell is in Account note
End Sub
To provide an error message indicating the text is too long you could do the following:
Add this after each statement where you assign value its value:
value = ActiveCell.Offset(, -2) 'Get the value of the selected Cell
If Len(value) > 255 Then
MsgBox "Text in cell " & CStr(ActiveCell.Address) & " is too long", vbOKOnly, "Search Text Too Long"
Exit Sub
End If
Also, you might want to change your if...then...else code structure.
Currently your code is operating like this:
If Not Intersect(ActiveCell, Range("G19:G" & LastRow)) Is Nothing Then
do things
exit sub
Else
If Not Intersect(ActiveCell, Range("E19:E" & LastRow)) Is Nothing Then
do things
exit sub
Else
MsgBox "Select an Account Note"
exit sub
Which, based on your comments for your End If's isn't exactly what your message box says. If your first if statement is Account Notes and your second if statement is notes, then a better structure would be the following.
Change this code
Else
If Not Intersect(ActiveCell, Range("E19:E" & LastRow)) Is Nothing Then
To look like this
ElseIf Not Intersect(ActiveCell, Range("E19:E" & LastRow)) Is Nothing Then
Then the statement `MsgBox "Select an Account Note" will be accurate. You also be able to delete one of your End If statements.
Your code will operate like this:
If Not Intersect(ActiveCell, Range("G19:G" & LastRow)) Is Nothing Then
do things
exit sub
ElseIf Not Intersect(ActiveCell, Range("E19:E" & LastRow)) Is Nothing Then
do things
exit sub
Else
MsgBox "Select an Account Note"
exit sub

Ungroup Sheets from an array in VBA

I've been trying to get an easy printout (in PDF using a single button) of one sheet with only active range and one chart located in another sheet. I've got everything working, except after I print, both sheets are grouped together and I can't edit my chart.
I'm trying to make this foolproof and easy for coworkers during real time operations. Right now I can right-click and select 'Ungroup sheets' to fix it, but I hate to have to do that each time (or explain that it needs to be done).
I tried to select a sheet, a different sheet, only one sheet etc. I can't figure out how to get VBA to ungroup the sheets at the end. Any ideas?
Sub CustomPrint()
'if statement to ask for file path
If Dir(Environ("commonprogramfiles") & "\Microsoft Shared\OFFICE" _
& Format(Val(Application.Version), "00") & "\EXP_PDF.DLL") <> "" Then
If FixedFilePathName = "" Then
'Open the GetSaveAsFilename dialog to enter a file name for the PDF file.
FileFormatstr = "PDF Files (*.pdf), *.pdf"
fname = Application.GetSaveAsFilename("", filefilter:=FileFormatstr, _
Title:="Create PDF")
'If you cancel this dialog, exit the function.
If fname = False Then Exit Sub
Else
fname = FixedFilePathName
End If
'Dynamic reference to RT drilling data
Dim LastRow As Long
Dim LastColumn As Long
Dim StartCell As Range
Dim sht As Worksheet
Set sht = Worksheets("rt drilling data")
Set StartCell = Range("A1")
'Refresh UsedRange
Worksheets("rt drilling data").UsedRange
'Find Last Row
LastRow = sht.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
'Select Range
sht.Range("A1:K" & LastRow).Select
Sheets("Chart Update").Activate
ActiveSheet.ChartObjects(1).Select
ThisWorkbook.Sheets(Array("chart update", "RT drilling data")).Select
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, _
Filename:=fname, IgnorePrintAreas:=False
'If the export is successful, return the file name.
If Dir(fname) <> "" Then RDB_Create_PDF = fname
End If
If OverwriteIfFileExist = False Then
If Dir(fname) <> "" Then Exit Sub
End If
On Error GoTo 0
Worksheets("ws model updates").Select
End Sub
If Dir(fname) <> "" Then Exit Sub will bypass Worksheets("ws model updates").Select
If OverwriteIfFileExist = False Then
If Dir(fname) <> "" Then
Worksheets("ws model updates").Select
Exit Sub
End If
End If

Implement Paste Link for this code

I have this code which allows to a copy a customized range from any sheet and paste it to a fixed range on sheet 2. This code works but I need to implement paste link function in this code, so that if i want to make any changes to the data in DB it will auto update in sheet 2 as well. Here is the code I have done so far. Thank you in advance
Sub CustomizedInputFixedoutput()
Dim rng As Range, _
inp As Range, _
ws As Worksheet
Set inp = Selection
On Error Resume Next
Set rng = Application.InputBox("Copy to", Type:=8)
On Error GoTo 0
If TypeName(rng) <> "Range" Then
MsgBox "Cancelled", vbInformation
Exit Sub
Else
rng.Parent.Activate
rng.Copy
Sheets("Sheet 2").Range("B2:N5").Value = rng.Value
End If
Application.CutCopyMode = False
End Sub
I felt sure this had to be a duplicate but searching [excel-vba] Paste Link found a few questions without any accepted answers and none that matched to OP desire to paste into a specific range.
Option Explicit
Sub CustomizedInputFixedoutput()
Dim CopyRng As Range
Dim PasteRng As Range
Dim Msg As String
Dim Response As VbMsgBoxResult
Set CopyRng = Selection
On Error Resume Next
Set PasteRng = Application.InputBox("Select a cell to copy to", Type:=8)
On Error GoTo 0
If Not PasteRng Is Nothing Then 'user clicked Cancel
If PasteRng.Count > 1 Then
'Get confirmation to paste to multi-cell range
Msg = "Are you sure you want to paste to " & PasteRng.Address & "?" _
& vbCrLf & vbCrLf _
& "Results may be unexpected if you proceed."
Response = MsgBox(Msg, vbQuestion + vbYesNo, "Confirm multi-cell paste range")
End If
If Response = vbYes Or PasteRng.Count = 1 Then
CopyRng.Copy
PasteRng.Parent.Activate
PasteRng.Activate
ActiveSheet.Paste Link:=True
Else
MsgBox "Cancelled", vbInformation
End If
Else
MsgBox "Cancelled", vbInformation
End If
Application.CutCopyMode = False
End Sub
Here you copy the range:
rng.Copy
And here you are assigning the value of B2:N5 the same value as rng.
Sheets("Sheet 2").Range("B2:N5").Value = rng.Value
The problem is that that code isn't pasting anything from the clipboard! You don't need to .Copy anything to assign cell values like this.
Use the Worksheet.Paste method instead of assigning the values (then the .Copy will serve its purpose), and set the optional parameter Links to True, like this:
Worksheets("Sheet 2").Range("B2:N5").Select
Worksheets("Sheet 2").Paste Links:=True

VBA Excel - find a value in a column, paste to another sheet

I've got a folder of excel worksheets, and also another worksheet with a column whose entries correspond to the file names of the worksheets in the folder.
The column to the right of the worksheet names has a number, which I want to paste into each corresponding worksheet... but it's not working... here's my code so far :
Sub FraisRank()
Dim folderPath As String
Dim filename As String
Dim filenameshort As String
Dim wb As Workbook
Dim fraislist As Workbook
Dim find As Range
Dim sel As Range
folderPath = "C:\Users\richard\Desktop\temp"
If Right(folderPath, 1) <> "\" Then folderPath = folderPath + "\"
Set fraislist = Workbooks.Open("C:\Users\richard\desktop\frais list.xlsx")
filename = Dir(folderPath & "*.*")
Do While filename <> ""
Application.ScreenUpdating = False
Set wb = Workbooks.Open(folderPath & filename)
filenameshort = Left(filename, Len(filename) - 4)
Set sel = fraislist.Sheets(1).Range("A1:A164")
Set find = sel.find(What:=filenameshort, After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If find Is Nothing Then
MsgBox ("Cell " & filenameshort & " not found")
Else
find.Offset(, 1).Resize(1, 1).Copy
ActiveSheet.Range("$H$5").PasteSpecial Paste:=xlPasteValues
End If
ActiveWorkbook.Save
ActiveWorkbook.Close
filename = Dir
Loop
End Sub
For the moment I'm getting a Runtime error '13', type mismatch on the 'Set find = ...' part. And in general I don't really understand how to run the '.find' on the selected cells in the 'fraislist' workbook...
The problem with ActiveCell is that it will always refer to the Activesheet and hence statements like Activecell/Select/Activate/ActiveSheet/Activeworkbook should be avoided. Always create relevant objects and work with them
INTERESTING READ
In your case it is not necessary that the ActiveSheet is fraislist.Sheets(1) so ActiveCell might not be referring to the correct sheet and hence, it's better to qualify it completely.
If you change After:=ActiveCell to After:=fraislist.Sheets(1).Range("A1") then your code will refer to the correct sheet and it will work.