defining LastRow in VBA - excel

I am trying to export data from excelsheet to excel Invoice template.
The VBA code which I have, It considers each row as a different Invoice and hence makes a different workbook for each row.
So in case I have 1 invoice which has 3 products this code considers each of the product (row) as separate Invoice which is not correct.
I want to modify it in a way that if the Invoice number (PiNo) is repeated in the next row then it means the next product (row) belongs to the above Invoice only.
I am new to VBA hence I have taken code from another site.
Here is the code:-
Private Sub CommandButton1_Click()
Dim customername As String
Dim customeraddress As String
Dim invoicenumber As Long
Dim r As Long
Dim mydate As String
Dim path As String
Dim myfilename As String
lastrow = Sheets(“CustomerDetails”).Range(“H” & Rows.Count).End(xlUp).Row
r = 2
For r = 2 To lastrow
ClientName = Sheets("CustomerDetails").Cells(r, 6).Value
Address = Sheets("CustomerDetails").Cells(r, 13).Value
PiNo = Sheets("CustomerDetails").Cells(r, 5).Value
Qty = Sheets("CustomerDetails").Cells(r, 9).Value
Description = Sheets("CustomerDetails").Cells(r, 12).Value
UnitPrice = Sheets("CustomerDetails").Cells(r, 10).Value
Salesperson = Sheets("CustomerDetails").Cells(r, 1).Value
PoNo = Sheets("CustomerDetails").Cells(r, 3).Value
PiDate = Sheets("CustomerDetails").Cells(r, 4).Value
Paymentterms = Sheets("CustomerDetails").Cells(r, 7).Value
PartNo = Sheets("CustomerDetails").Cells(r, 8).Value
Shipdate = Sheets("CustomerDetails").Cells(r, 14).Value
Dispatchthrough = Sheets("CustomerDetails").Cells(r, 15).Value
Modeofpayment = Sheets("CustomerDetails").Cells(r, 16).Value
VAT = Sheets("CustomerDetails").Cells(r, 17).Value
Workbooks.Open ("C:\Users\admin\Desktop\InvoiceTemplate.xlsx")
ActiveWorkbook.Sheets("InvoiceTemplate").Activate
ActiveWorkbook.Sheets("InvoiceTemplate").Range(“Z8”).Value = PiDate
ActiveWorkbook.Sheets("InvoiceTemplate").Range(“AG8”).Value = PiNo
ActiveWorkbook.Sheets("InvoiceTemplate").Range(“AN8”).Value = PoNo
ActiveWorkbook.Sheets("InvoiceTemplate").Range(“B16”).Value = ClientName
ActiveWorkbook.Sheets("InvoiceTemplate").Range(“B17”).Value = Address
ActiveWorkbook.Sheets("InvoiceTemplate").Range(“B21”).Value = Shipdate
ActiveWorkbook.Sheets("InvoiceTemplate").Range(“K21”).Value = Paymentterms
ActiveWorkbook.Sheets("InvoiceTemplate").Range(“T21”).Value = Salesperson
ActiveWorkbook.Sheets("InvoiceTemplate").Range(“AC21”).Value = Dispatchthrough
ActiveWorkbook.Sheets("InvoiceTemplate").Range(“AL21”).Value = Modeofpayment
ActiveWorkbook.Sheets("InvoiceTemplate").Range(“B25”).Value = PartNo
ActiveWorkbook.Sheets("InvoiceTemplate").Range(“J25”).Value = Description
ActiveWorkbook.Sheets("InvoiceTemplate").Range(“Y25”).Value = Qty
ActiveWorkbook.Sheets("InvoiceTemplate").Range(“AF25”).Value = UnitPrice
ActiveWorkbook.Sheets("InvoiceTemplate").Range(“AL39”).Value = VAT
path = "C:\Users\admin\Desktop\Invoices\"
ActiveWorkbook.SaveAs Filename:=path & PiNo & “.xlsx”
myfilename = ActiveWorkbook.FullName
ActiveWorkbook.Close SaveChanges:=True
Next r
End Sub
"H" is the Product column and the data starts from Row 2. Row 1 are headers.
enter image description here
enter image description here
enter image description here

There are a few areas to address when it comes to what you want to achieve vs. your current code. I'll outline this below in no particular order and provide some sample code to help you achieve what you want.
Your code to create, save and close the new workbook is contained within your for loop. This means that if we assume you have 3 products to add to your invoice, your code is going to open the InvoiceTemplate.xlsx from the desktop a total of 3 times and also save it and close it with the PiNo name 3 times. To fix this you should move the code to open the workbook before your For loop starts and move the SaveAs code to after the loop so it's only saving and closing the workbook once.
Your code uses .activate and makes reference almost entirely to the ActiveWorkbook (if you don't declare the workbook it will assume ActiveWorkbook). This should be avoided and you should be explicitly defining the object you are using instead (why you should do this has already been discussed at great length - you can read more about it here: How To Avoid Using Select in Excel.
You have declared a few variables that you don't actually use. Either use them or remove them to declutter the code.
You haven't declared the variables storing the values from your sheet (at the start of your for loop) which means they are automatically created as the data type Variant which is not very efficient.
The for loop writes the variables to set cell references which means even if we fix all other issues, the code will just overwrite the same cells with each loop iteration. This can be resolved by setting the row value into a variable and increment it with each loop iteration (assuming this is how the template should be completed).
As a side point; using longer but more descriptive variable names can make life a lot easier when debugging errors, especially when you're new to VBA so you may want to consider this with all of your variables. E.g. LoopRow OR RowCounterForLoop instead of r and InvoiceTemplatePath OR SavedInvoicesPath instead of path.
Here is an example code to give you an idea how to implement some changes taking the above points into account, in it we will use the PiNo variable only (but just copy the changes to each of the other relevant variables):
Private Sub CommandButton1_Click()
Dim LastRow As Long
Dim RowCounterForLoop As Long
Dim InvoiceTemplateRowCounter as Long
Dim DesktopFilePath As String
Dim SavedInvoiceFilePath As String
Dim PiNo As String
LastRow = ThisWorkbook.Sheets("CustomerDetails").Range("H" & Rows.Count).End(xlUp).Row
InvoiceTemplateRowCounter = 8
DesktopFilePath = "C:\Users\admin\Desktop\"
SavedInvoiceFilePath = "C:\Users\admin\Desktop\Invoices\"
Workbooks.Open (DesktopFilePath & "InvoiceTemplate.xlsx")
For RowCounterForLoop = 2 To lastrow 'I've removed the previous assignment of 2 to RowCounterForLoop as it is assigned on this line.
PiNo = ThisWorkbook.Sheets("CustomerDetails").Cells(r, 5).Value 'I've added ThisWorkbook before the Sheet which explicitly defines the code to affect the workbook the code is running on. It also uses a variable instead of number to allow dynamic referencing to the range.
Workbooks("InvoiceTemplate.xlsx").Sheets("InvoiceTemplate").Range("AG" & InvoiceTemplateRowCounter).Value = PiNo 'I've added Workbooks("InvoiceTemplate.xlsx") to explicitly run this code on that workbook which avoids using ActiveWorkbook.
InvoiceTemplateRowCounter = InvoiceTemplateRowCounter + 1
Next RowCounterForLoop
Workbooks("InvoiceTemplate.xlsx").SaveAs Filename:=SavedInvoiceFilePath & PiNo & ".xlsx"
Workbooks("InvoiceTemplate.xlsx").Close SaveChanges:=False 'The file is saved on the previous line so this will avoid saving again and pop up prompts etc.
End Sub
The above won't fix everything and there are better and more efficient ways to achieve what you want but it does provide an answer to your question.
You may want to consider the following to further improve your code:
Using Arrays to store data and then write it to the new workbook. (This may be rather tricky depending on your skills using Arrays with VBA)
To enter the PiNo into each row (when there are more than 1 product) you can use the Range.FillDown method (depending on how exactly your sheet works) which you can read about Here.

Related

Paste rows from one sheet to another when condition is met in VBA

I have a macro with all tasks I have to do to generate a report, currently I need merge new data from the new sheet to the original. Some sort of JOIN if we could call it like that.
In the srcWorkbook we have things like address, who was in charge in that time and a date/id timestamp. In the outWorkbook there's vendor personal data and such.
Output table / New data table / Output table (after running macro)
To merge the both sheets I want to match id_date and id_hr in both files so if srcWorkbook and outWorkbook id's match, grab srcWorkbook row and paste it on the side of the outWorkbook.
I've tried to do a for / if statement which reads apparently but it doesn't paste the new rows. I also tried a VLOOKUP but I'd rather stick with basic statements for future modifications.
Sub popularSubG()
'File calling here and index variables
'Cells
' cell Src
Dim cellSrcPerPro As Long
Dim cellSrcIDHR As Long
' cell Out
Dim cellOutPerPro As Long
Dim cellOutIDHR As Long
For indexRowSrc = 2 To indexLastRowSrc
cellSrcPerPro = srcWorkbook.Cells(indexRowSrc, "A").Value
cellSrcIDHR = srcWorkbook.Cells(indexRowSrc, "B").Value
cellOutPerPro = outWorkbook.Cells(indexRowSrc, "A").Value
cellOutIDHR = outWorkbook.Cells(indexRowSrc, "B").Value
If cellSrcPerPro = cellOutPerPro & cellSrcIDHR = cellDestinoIDHR Then
indexRowOut = indexRowOut + 1
srcWorkbook.Sheets(1).Cells(2, "C").EntireRow.Copy Destination:=outWorkbook.Sheets(1).Range("O" & Rows.Count).End(xlUp).Offset(0)
End If
Next indexRowSrc
MsgBox "Sub ended"
End Sub

VLookup error when searching with numbers and text

I am new to VBA and am trying to recode a program that already exists, with the intention of optimizing it and adding new features. The program takes a scanner input (though I am just manually entering in the numbers at the moment), which then records and categorizes the type of item that is taken out. It is then put in a log for reference later. Here is the first Userform that takes the scanned input:
Private Sub TextBox1_Change()
Dim barcode As Long, emptyRow As Long, testHold As Long
Set TempHold = Worksheets("TempHold")
If Application.WorksheetFunction.CountIf(TempHold.Range("D2:D25"), TextBox1.Value) = 1 Then
If Application.WorksheetFunction.CountIf(Range("B:B"), TextBox1.Value) = 0 Then
CartTypeMenu.Show
barcode = TextBox1.Value
emptyRow = WorksheetFunction.CountA(Range("A:A")) + 1
Cells(emptyRow, 1).Value = Application.WorksheetFunction.VLookup(barcode, TempHold.Range("D2:E25"), 2, True)
Cells(emptyRow, 2).Value = barcode
Cells(emptyRow, 3).Value = Format(Now(), "mm/dd/yyyy hh:nn")
Cells(emptyRow, 4).Value = CartTypeMenu.ComboBox1.Value
TextBox1.Value = ""
Else
testHold = TextBox1.Value
Call boxTest(testHold)
End If
End If
End Sub
I have two tables in a separate sheet (TempHold) that have the scanned input corresponding to a number, and a number corresponding to a name. The row in the final log would basically be the number of the scanned input (as they are labeled by number), the scanned input, the time (which works properly), the type and then the name.
The problem I run into is when I search VLookup for the name to put into the next cell in the log row; getting the name from a number. It only looks for the name if it is actively in the log (it is cleared once tasks are completed). I have tried changing the numbers to strings, and vice versa, but I can't get it to work. Here is the problematic module:
Sub boxTest(testHold As Long)
Dim offsetValue As Long, myValue As Variant
Set ws = Worksheets("Log")
Set sheetLookup = Worksheets("TempHold")
offsetValue = Application.Match(testHold, ws.Range("B2:B8"), 0)
myValue = InputBox("Enter your number")
ws.Range("E" & offsetValue).Value = Application.WorksheetFunction.VLookup(myValue, sheetLookup.Range("A2:B9"), 1, True)
End Sub
VLookup keeps giving the error that it can't find the WorksheetFunction in this module.

Using a variable to declare a worksheet by its number in Excel VBA

Good evening. I am desperate for some help with a short piece of VBA Code I am writing.
Public TFOCUS As Integer ' Creates TFOCUS, which is the worksheet in focus
Public RFOCUS As Integer ' Creates RFOCUS, which is the row in focus
Public CFOCUS As String ' Creates CFOCUS, which is the column in focus
Public RECORD As Integer ' Creates RECORD, wich is the row that is having the record written to
FILEPATH.Worksheets(TFOCUS).Range(Cells(RFOCUS, B)).Value = Worksheets(3).Range(Cells(RECORD, A)).Value 'copies focus EmpID to destination
FILEPATH.Worksheets(TFOCUS).Range(Cells(4, CFOCUS)).Value = Worksheets(3).Range(Cells(RECORD, B)).Value 'copies focus Course to destination
FILEPATH.Worksheets(TFOCUS).Range(Cells(RFOCUS, CFOCUS)).Value = Worksheets(3).Range(Cells(RECORD, C)).Value 'copies focus Date to destination
CFOCUS = CFOCUS + 1 'moves focus to next column
RECORD = RECORD + 1 'creates next record
FILEPATH is set to the path of an external Excel workbook. In this instance, TFOCUS is set to 1, RFOCUS is set to 5, CFOCUS is set to "Q", and RECORD is set to 1.
The purpose is to copy records from an external excel document into the active spreadsheet, and reformat them by moving the cell contents about. This will be used to move multiple sources, and will have to deal with every tab in every source document (which could all be named something different).
The issue I am having is that I am recieving a Runtime Error 13: Type Mismatch error when compiling, on the following line:
FILEPATH.Worksheets(TFOCUS).Range(Cells(RFOCUS, B)).Value = Worksheets(3).Range(Cells(RECORD, A)).Value 'copies focus EmpID to destination
I am assuming that this is either to do with the use of TFOCUS as an integer or FILEPATH as a file path. Can anyone suggest:
What exactly the mismatch is
If it is because of using Worksheets(TFOCUS), any way I can reference the worksheet by its number in the tab order using a variable?
Any other suggestions?
Thanks in advance for your help.
You're not showing us where/whether the variables are assigned, but...
Public RFOCUS As Integer ' Creates RFOCUS, which is the row in focus
Public CFOCUS As String ' Creates CFOCUS, which is the column in focus
Try declaring CFOCUS as an Integer. Or better, as a Long, so that your code works beyond row 32767 (the Integer type is 16-bit and signed, so 32768 is an overflowing value).
Also, if FILEPATH is a String, then your code can't work:
FILEPATH is set to the path of an external Excel workbook.
FILEPATH.Worksheets(TFOCUS)
It should be a Workbook object.. but then the identifier you're using is very confusing.
Dim wb As Workbook
Set wb = Workbooks.Open(FILEPATH)
wb.Worksheets(TFOCUS).Range(Cells(RFOCUS, B)).Value = Worksheets(3).Range(Cells(RECORD, A)).Value 'copies focus EmpID to destination
wb.Worksheets(TFOCUS).Range(Cells(4, CFOCUS)).Value = Worksheets(3).Range(Cells(RECORD, B)).Value 'copies focus Course to destination
wb.Worksheets(TFOCUS).Range(Cells(RFOCUS, CFOCUS)).Value = Worksheets(3).Range(Cells(RECORD, C)).Value 'copies focus Date to destination
CFOCUS = CFOCUS + 1 'moves focus to next column
RECORD = RECORD + 1 'creates next record
'save [wb] workbook? Close it?
Set wb = Nothing
May I also suggest to keep YELLCASE for constants, and to use camelCase for locals and PascalCase for everything else?
If RFOCUS is set to "Q" and B and A are integers, then this:
FILEPATH.Worksheets(TFOCUS).Range(Cells(RFOCUS, B)).Value = Worksheets(3).Range(Cells(RECORD, A)).Value
should be:
FILEPATH.Worksheets(TFOCUS).Range(RFOCUS & B).Value = Worksheets(3).Cells(Record, A).Value
Here are all 3 lines:
FILEPATH.Worksheets(TFOCUS).Range(RFOCUS & B).Value = Worksheets(3).Cells(Record, A).Value
FILEPATH.Worksheets(TFOCUS).Cells(4, CFOCUS).Value = Worksheets(3).Cells(Record, B).Value
FILEPATH.Worksheets(TFOCUS).Range(RFOCUS & CFOCUS).Value = Worksheets(3).Cells(Record, C).Value

Find within an existing find loop in Excel Macro

I have a excel spreadsheet where I have values in a form format, I need to convert them into tabular format. example -
Project ID/Name: 3001 Miscellaneous Improvements
Location: This is Project Location.
Description: This is the project description. This is the project description. This is the project description. This is the project description. This is the project description. This is the project description. This is the project description. This is the project description.
Justification: This is the project Justification. This is the project Justification. This is the project Justification. This is the project Justification. This is the project Justification. This is the project Justification. This is the project Justification.
Duration: Q1 2013 to Ongoing
Status: This is some status
Each block starts with Project ID/Name, however, Description and Justification can vary according to the size of text they have. All the headings are in Column A. If I use Find for ProjectID - and use offset at a fixed length it works but if Justification and description are bigger or smaller they don't fall in correct place. Please help.
You can use TextToColumns. Example:
'Split this cells when find ':" or <TABS>
[A1:A6].TextToColumns Destination:=[A1], DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, Tab:=True, OtherChar:=":", _
FieldInfo:=Array(Array(1, 1), Array(2, 1)), TrailingMinusNumbers:=True
From what I understand, you want to convert a vertical "form" into a table of data. I suggest adding that data to an existing table.
Here's the code.
You'll need to edit some variables (sheet/range names)
Public Sub test()
'insert your code to get each Worksheet and it's column range here
transferFormDataToTable Range("Sheet1!B1:B100"), Worksheets(2).ListObjects(1)
End Sub
Public Sub transferFormDataToTable(yourRangeB As Range, dbTable As ListObject)
' make a reference to the form data range
Dim formRange As Range
Set formRange = yourRangeB
'create a new ListRow in your target table
Dim listR As ListRow
Set listR = dbTable.ListRows.Add
'transfer the data from form to the new ListRow
Dim lastHeader As String
lastHeader = ""
Dim targetColumnOffset As Integer
targetColumnOffset = 0
Dim currentColumn As Integer
currentColumn = 0
Dim i As Integer
For i = 1 To formRange.Count
'if the row's header is not empty and different than previous row
'then we'll know we have a new column of different type of data
If lastHeader <> formRange(i).Offset(0, -1).Value And formRange(i).Offset(0, -1).Value <> "" Then
lastHeader = formRange(i).Offset(0, -1).Value
targetColumnOffset = 0
currentColumn = currentColumn + 1
End If
'this loop captures data that might have been placed in columns to the right of the input cell
Dim rowString As String
rowString = ""
Dim j As Integer
j = 0
Do While True
If formRange(i).Offset(0, j).Value <> "" Then
If rowString = "" And targetColumnOffset = 0 Then
rowString = formRange(i).Offset(0, j).Value
Else
rowString = rowString & "; " & formRange(i).Offset(0, j).Value
End If
j = j + 1
Else
Exit Do
End If
Loop
If targetColumnOffset = 0 Then
listR.Range(currentColumn).Value = rowString
Else
listR.Range(currentColumn).Value = listR.Range(currentColumn).Value & rowString
End If
targetColumnOffset = targetColumnOffset + 1
'Exit the loop if it seems to get the end
If formRange(i).Value = "" And formRange(i).Offset(0, -1).Value = "" Then _
Exit For
Next i
End Sub
Notes:
Excel has weird bugs occasionally when creating editing with VBA empty tables that have only 1 or 2 rows. I suggest using this macro only when your table has 3+ rows.
Send me a note if you want a much more complete version of this. Namely, a problem you might eventually have with this short version is that the code will screw up if a user switches columns around.
EDIT
I just adapted the code to your requirements. This is bound to get buggy eventually though. I'd really look into convincing the team about just how much they need to find a more appropriate tool. Good luck.

excel vba split text

Please be aware that I am working with a series of ~1000 line medical information databases. Due to the size of the databases, manual manipulation of the data is too time consuming. As such, I have attempted to learn VBA and code an Excel 2010 macro using VBA to help me accomplish parsing certain data. The desired output is to split certain characters from a provided string on each line of the database as follows:
99204 - OFFICE/OUTPATIENT VISIT, NEW
will need to be split into
Active Row Active Column = 99204 ActiveRow Active Column+3 = OFFICE/OUTPATIENT VISIT, NEW
I have researched this topic using Walkenbach's "Excel 2013: Power Programming with VBA" and a fair amount of web resources, including this awesome site, but have been unable to develop a fully-workable solution using VBA in Excel. The code for my current macro is:
Sub EasySplit()
Dim text As String
Dim a As Integer
Dim name As Variant
text = ActiveCell.Value
name = Split(text, "-", 2)
For a = 0 To 1
Cells(1, a + 3).Value = Trim(name(a))
Next a
End Sub
The code uses the "-" character as a delimiter to split the input string into two substrings (I have limited the output strings to 2, as there exists in some input strings multiple "-" characters). I have trimmed the second string output to remove leading spaces.
The trouble that I am having is that the output is being presented at the top of the activesheet, instead of on the activerow.
Thank you in advance for any help. I have been working on this for 2 days and although I have made some progress, I feel that I have reached an impasse. I think that the issue is somewhere in the
Cells(1, a + 3).Value = Trim(name(a))
code, specifically with "Cells()".
Thank you Conrad Frix!
Yah.. funny enough. Just after I post I have a brainstorm.. and modify the code to read:
Sub EasySplit()
Dim text As String
Dim a As Integer
Dim name As Variant
text = ActiveCell.Value
name = Split(text, "-", 2)
For a = 0 To 1
ActiveCell.Offset(0, 3 + a).Value = Trim(name(a))
Next a
End Sub
Not quite the colkumn1,column4 output that I want (it outputs to column3,column4), but it will work for my purpose.
Now I need to incorporate a loop so that the code runs on each successive cell in the column (downwards, step 1) skipping all bolded cells, until it hits an empty cell.
Modified answer to modified request.
This will start on row 1 and continue until a blank cell is found in column A. If you would like to start on a different row, perhaps row 2 if you have headers, change the
i = 1
line to
i = 2
I added a check on the upper bound of our variant before doing the output writes, in case the macro is run again on already formatted cells. (Does nothing instead of erroring out)
Sub EasySplit()
Dim initialText As String
Dim i As Double
Dim name As Variant
i = 1
Do While Trim(Cells(i, 1)) <> ""
If Not Cells(i, 1).Font.Bold Then
initialText = Cells(i, 1).text
name = Split(initialText, "-", 2)
If Not UBound(name) < 1 Then
Cells(i, 1) = Trim(name(0))
Cells(i, 4) = Trim(name(1))
End If
End If
i = i + 1
Loop
End Sub
just add a variable to keep track of the active row and then use that in place of the constant 1.
e.g.
Dim iRow as Integer = ActiveCell.Row
For a = 0 To 1
Cells(iRow , a + 3).Value = Trim(name(a))
Next a
Alternate method utilizing TextToColumns. This code also avoids using a loop, making it more efficient and much faster. Comments have been added to assist with understanding the code.
EDIT: I have expanded the code to make it more versatile by using a temp worksheet. You can then output the two columns to wherever you'd like. As stated in your original question, the output is now to columns 1 and 4.
Sub tgr()
Const DataCol As String = "A" 'Change to the correct column letter
Const HeaderRow As Long = 1 'Change to be the correct header row
Dim rngOriginal As Range 'Use this variable to capture your original data
'Capture the original data, starting in Data column and the header row + 1
Set rngOriginal = Range(DataCol & HeaderRow + 1, Cells(Rows.Count, DataCol).End(xlUp))
If rngOriginal.Row < HeaderRow + 1 Then Exit Sub 'No data
'We will be using a temp worksheet, and to avoid a prompt when we delete the temp worksheet we turn off alerts
'We also turn off screenupdating to prevent "screen flickering"
Application.DisplayAlerts = False
Application.ScreenUpdating = False
'Move the original data to a temp worksheet to perform the split
'To avoid having leading/trailing spaces, replace all instances of " - " with simply "-"
'Lastly, move the split data to desired locations and remove the temp worksheet
With Sheets.Add.Range("A1").Resize(rngOriginal.Rows.Count)
.Value = rngOriginal.Value
.Replace " - ", "-"
.TextToColumns .Cells, xlDelimited, Other:=True, OtherChar:="-"
rngOriginal.Value = .Value
rngOriginal.Offset(, 3).Value = .Offset(, 1).Value
.Worksheet.Delete
End With
'Now that all operations have completed, turn alerts and screenupdating back on
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
You can do this in a single shot without looping using the VBA equivalent of entering this formula, then taking values only
as a formula
=IF(NOT(ISERROR(FIND("-",A1))),RIGHT(A1,LEN(A1)-FIND("-",A1)-1 ),A1)
code
Sub Quicker()
Dim rng1 As Range
Set rng1 = Range([a1], Cells(Rows.Count, "A").End(xlUp))
With rng1.Offset(0, 3)
.FormulaR1C1 = "=IF(NOT(ISERROR(FIND(""-"",RC[-3]))),RIGHT(RC[-3],LEN(RC[-3])-FIND(""-"",RC[-3])-1 ),RC[-3])"
.Value = .Value
End With
End Sub

Resources