Could you please help me on below error in vba. Formula works but there are error. My scenario is need to extract in between number (between two "-")
Ite1-223466678-ghtrdhjuyr321
Ite-654354477-hjuyt-
Dftehh-767678765-4yutiuy
Extract only this 9 digit in between "-" and need to apply till last row of my excel through VBA
Formula:
= Value(mid(A1,search("-",A1)+1, search ("-",A1, search ("-", A1)+1-search("-", A1)-1))
VBA:
Sub Data2
Dim lastrow as long
Lastrow=Range("A"&rows.count).end(xlup).row
Range("F2:F" & lastrow).formula = " =
Value(mid(A1,search("-",A1)+1, search
("-",A1, search ("-", A1)+1-
search("-. ", A1)-1)"
End sub
ERROR
#VALUE ERROR need to fix am not sure how to do if search fails in formula
RUNTIME ERROR 13 data mismatch
Give this a try:
Sub BetweenDashs()
Dim lastrow As Long, i As Long
lastrow = Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lastrow
arr = Split(Range("A" & i).Value, "-")
If UBound(arr) > 0 Then
Range("F" & i).Value = CLng(arr(1))
End If
Next i
End Sub
EDIT#1:
If your data is in column C rather than column A, then use:
Sub BetweenDashs()
Dim lastrow As Long, i As Long
lastrow = Range("C" & Rows.Count).End(xlUp).Row
For i = 2 To lastrow
arr = Split(Range("C" & i).Value, "-")
If UBound(arr) > 0 Then
Range("F" & i).Value = CLng(arr(1))
End If
Next i
End Sub
I am using VBA to write a Macro and it is working exactly as I want, except that I would like my formulas to loop through the sheets instead of using data on 'SAFO-1', 'SAFO-1' refers to the fish Salvelinus fontinalis (SAFO). I have many fish species (e.g., Morone saxatilis (MOSA)) and it would be way more pratical if I could refer to the sheet number instead of their name. Unfortunately, I do not decide sheet names and they have to stay as they are because we're working on shared projects with unique name for every samples. Sheets name change between projects and I want to be able to use my code in all of them. Here is my current code:
Sub Mean()
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim Sheet As Integer
k = 4
i = Application.Sheets.Count
For Sheet = 2 To i
Worksheets(Sheet).Select
j = 3
Do While ActiveCell.Value <> "0"
Range("A" & j).Select
If ActiveCell.Value = "0" Then
Range("A1").Copy
Worksheets("Mean").Range("A" & Sheet + 1).PasteSpecial Paste:=xlPasteValues
Worksheets("Mean").Range("B" & Sheet + 1).Formula = "=(('SAFO-1'!B80)-('SAFO-1'!B75))"
Worksheets("Mean").Range("C" & Sheet + 1).Formula = "=(('SAFO-1'!C80)-('SAFO-1'!C75))"
For k = 4 To 41
Worksheets("Mean").Cells(Sheet + 1, k).FormulaR1C1 = "=AVERAGE('SAFO-1'!R" & j + 10 & "C" & k & ":R" & j - 9 & "C" & k & ")"
Next k
Else
j = j + 1
End If
Loop
Next Sheet
Range("B1:AP2").Copy Worksheets("Mean").Range("A1")
Worksheets("Mean").Select
End Sub
My idea is to replace 'SAFO-1' by 'Sheet1', to be enventually able to write something like :
Worksheets("Mean").Cells(Sheet + 1, k).FormulaR1C1 = "=AVERAGE('Sheet "& Sheet")'!R" & j + 10 & "C" & k & ":R" & j - 9 & "C" & k & ")"
Thanks in advance!
William Fortin
First, we are going to stop using .Select and instead use object handles. I'm not entirely sure where the name of your sheet comes from but I'm going to assume that it's related to the loop and use that as an example. We get an object handle on the sheet using it's number Set currentSheet = Worksheets(Sheet) and then we can grab it's name and use that where we need to in the formula currentSheet.Name.
I hope that even if this code isn't a complete solution that it shows you how to get where you are going.
Option Explicit
Public Sub Mean()
Dim j As Long
Dim k As Long
Dim Sheet As Long
k = 4
For Sheet = 2 To Application.Sheets.Count
Dim currentSheet As Worksheet
Set currentSheet = Worksheets(Sheet)
j = 3
Do
Dim currentCell As Range
Set currentCell = currentSheet.Range("A" & j)
If currentCell.Value = "0" Then
With Worksheets("Mean")
.Range("A" & Sheet + 1).Value = currentSheet.Range("A1").Value
.Range("B" & Sheet + 1).Formula = "=(('" & currentSheet.Name & "'!B80)-('" & currentSheet.Name & "'!B75))"
.Range("C" & Sheet + 1).Formula = "=(('" & currentSheet.Name & "'!C80)-('" & currentSheet.Name & "'!C75))"
For k = 4 To 41
.Cells(Sheet + 1, k).FormulaR1C1 = "=AVERAGE('" & currentSheet.Name & "'!R" & j + 10 & "C" & k & ":R" & j - 9 & "C" & k & ")"
Next k
End With
Else
j = j + 1
End If
Loop While currentCell.Value <> "0"
Next Sheet
currentSheet.Range("B1:AP2").Copy Worksheets("Mean").Range("A1")
Worksheets("Mean").Select
End Sub
We can create an array of worksheet names in VBA and use them to create the formulas we put in the sheets. For example:
Sub useNumber()
sh = Array("big worksheet name", "collosal worksheet name", "mammoth worksheet name", "tiny worksheet name")
Sheets("Sheet1").Range("A1").Formula = "=SUM('" & sh(1) & "'!A3:A6)"
End Sub
If you have many sheets, use a For loop to fill the array rather than the Array() function.
running this creates:
=SUM('collosal worksheet name'!A3:A6)
In Sheet1 cell A1
This approach makes looping over data sheets easier:
Sub useNumberloop()
sh = Array("big worksheet name", "collosal worksheet name", "mammoth worksheet name", "tiny worksheet name")
For i = 1 To 4
Sheets("Sheet1").Range("A" & i).Formula = "=SUM('" & sh(i - 1) & "'!A3:A6)"
Next i
End Sub
I have a workbook with 2 sheets.
Sheet1:
Column B Column C Column D Column E
Dairy Crest Ltd
Milk Farm
Tuna Family
Guiness
Sheet 2:
Column A Column B Column C Column d
Dairy Crest James james#email.com 07874565656
Milk Farm Limited Kelly kely#email.com 07874565656
Tuna's Families Dave dave#email.com 07874565656
Guiness Prep Limited Tom tom#email.com 07874565656
I want to match the similar named companies. This can't be a case of saying if value = value because the company name is usually spelt different.
Instead i want to use like or wildcard. Would this work?
If i use Value Like Value this doesn't seem to work.
Where found, i want to copy the contact name, email and contact number over to sheet 1 in the relevant columns.
For some reason this is not working. Please can someone show me where i am going wrong?
Relevant code:
'Start second loop sequence
With ThisWorkbook.Worksheets(3)
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
j2 = 2
For i2 = 1 To LastRow
' === For DEBUG ONLY ===
Debug.Print ThisWorkbook.Worksheets(2).Range("B" & j2).Value
If ThisWorkbook.Worksheets(2).Range("B" & j2).Value = .Range("A" & i2).Value Then ' check if Week No equals the value in "A1"
ThisWorkbook.Worksheets(2).Range("C" & j2).Value = .Range("B" & i2).Value
ThisWorkbook.Worksheets(2).Range("D" & j2).Value = .Range("D" & i2).Value
ThisWorkbook.Worksheets(2).Range("E" & j2).Value = .Range("C" & i2).Value
j2 = j2 + 1
End If
Next i2
End With
'End Second Loop
Full COde:
Option Explicit
Sub LoadWeekAnnouncementsFromPlanner()
Dim WB As Workbook
Dim WB2 As Workbook
Dim i As Long
Dim i2 As Long
Dim j As Long
Dim j2 As Long
Dim LastRow As Long
Dim ws As Worksheet
'Open Planner
'On Error Resume Next
Set WB = Workbooks("2017 Planner.xlsx")
On Error GoTo 0
If WB Is Nothing Then 'open workbook if not open
Set WB = Workbooks.Open("G:\BUYING\Food Specials\2. Planning\1. Planning\1. Planner\8. 2017\2017 Planner.xlsx", xlUpdateLinksNever, True, Password:="samples")
End If
'Open PhoneBook
'On Error Resume Next
'On Error GoTo 0
' ======= Edit #2 , also for DEBUG ======
With WB.Worksheets(1)
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
j = 2
For i = 1 To LastRow
' === For DEBUG ONLY ===
Debug.Print CInt(ThisWorkbook.Worksheets(1).Range("I8").Value)
If CInt(ThisWorkbook.Worksheets(1).Range("I8").Value) = .Range("A" & i).Value Then ' check if Week No equals the value in "A1"
ThisWorkbook.Worksheets(2).Range("A" & j).Value = .Range("A" & i).Value
ThisWorkbook.Worksheets(2).Range("B" & j).Value = .Range("N" & i).Value
ThisWorkbook.Worksheets(2).Range("H" & j).Value = .Range("K" & i).Value
ThisWorkbook.Worksheets(2).Range("I" & j).Value = .Range("L" & i).Value
ThisWorkbook.Worksheets(2).Range("J" & j).Value = .Range("M" & i).Value
ThisWorkbook.Worksheets(2).Range("K" & j).Value = .Range("G" & i).Value
ThisWorkbook.Worksheets(2).Range("L" & j).Value = .Range("O" & i).Value
ThisWorkbook.Worksheets(2).Range("M" & j).Value = .Range("P" & i).Value
ThisWorkbook.Worksheets(2).Range("N" & j).Value = .Range("W" & i).Value
ThisWorkbook.Worksheets(2).Range("O" & j).Value = .Range("Z" & i).Value
'Start second loop sequence
With ThisWorkbook.Worksheets(3)
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
j2 = 2
For i2 = 1 To LastRow
' === For DEBUG ONLY ===
Debug.Print ThisWorkbook.Worksheets(2).Range("B" & j2).Value
If ThisWorkbook.Worksheets(2).Range("B" & j2).Value = .Range("A" & i2).Value Then ' check if Week No equals the value in "A1"
ThisWorkbook.Worksheets(2).Range("C" & j2).Value = .Range("B" & i2).Value
ThisWorkbook.Worksheets(2).Range("D" & j2).Value = .Range("D" & i2).Value
ThisWorkbook.Worksheets(2).Range("E" & j2).Value = .Range("C" & i2).Value
j2 = j2 + 1
End If
Next i2
End With
'End Second Loop
j = j + 1
End If
Next i
End With
End Sub
Please can someone show me where i am going wrong?
This is a good example how to use Like in VBA. Try it in the console window, to get the answers.
?"Vito6" Like "V?to6"
True
?"Vito6" Like "Vito#"
True
?"Vito6" Like "V*6"
True
?"Vito6" Like "Vit[a-z]6"
True
?"Vito6" Like "Vit[A-Z]6"
False
?"Vito6" Like "Vit[!A-Z]6"
True
?"12 34" Like "## ##"
True
?"12 34" Like "1[0-9] [0-9]4"
True
If there's not a specific reason you need VBA, you could apply the solution that #Cyril gave in his comment to an Excel cell formula on Sheet1.
For example, in Sheet1, Cell F1, you can input:
=LEFT(B1, 4)
'This would return "Dair"
Then, in column A, you could use a nested IF statement:
=IF(F1 = "dair", "Dairy Crest", IF(F1 = "milk", "Milk Farm Limited, IF(F1 = "tuna", "Tuna's Families", IF(F1 = "Guiness", "Guiness Prep Limited", "No match))))
Will try to elaborate on my thought from the comment I left you:
Dim asdf as String
Dim i as Variant
Dim LR as Long
LR = Sheets("Sheet2").Cells(.Rows.Count, "A").End(xlUp).Row
For i = 2 to LR 'Sheet1 looks to start on row 3, while Sheet2 looks to start on row2
asdf = Sheets("Sheet1").Cells(i+1,2).Value
If Sheets("Sheet2").Cells(i,1).Value Like "*asdf*" Then 'you left out the asterisks
'true: copy data
Else:
'false: can just be nothing here
End If
Next i
Something similar to that is what I was suggesting. Utilized like operator, as suggested by #DougCoats.
While you can use wildcards to compare strings using the like operator , the explicit parts need to be exact. So
"*Dairy Crest*" like "Dairy Crest Ltd" will work nicely
but "*Tuna Family*" like "Tuna's Families" will not work.
You can try fuzzy lookup for matching for the 2nd scenario. It employs probability into the lookup.
Here is the link to the source code.
https://www.mrexcel.com/forum/excel-questions/195635-fuzzy-matching-new-version-plus-explanation.html
Just one note for fuzzy matching with probability, the matching may not be 100% correct if you set the accuracy % too low. If accuracy is important, then set the accuracy % higher.
I am working with this macro that will look at a block of transactions, insert 3 rows between months, and then add the month and subtotal. The issue is that the break and totals are getting inserted at the beginning of the month instead of the end.
I have tried to adjust the shift but it either ends up giving me an error or the total ends up overriding an existing cell instead of going into a new row. This is a more complex macro than I have worked with before and I'm a little lost now, still working on learning VBA.
Option Explicit
Sub AddAndSum()
On Error GoTo lblError
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim shData As Worksheet, wbData As Workbook
Dim fr As Long, lr As Long, i As Long, lr2 As Long
Dim intMonth As Long, intYear As Long
Set wbData = ThisWorkbook
Set shData = wbData.Sheets("Sheet1")
fr = 13
lr = shData.Rows.Count
For i = fr To lr
With shData
If (IsDate(.Cells(i, 3).Value) And IsDate(.Cells(i - 1, 3).Value) And Month(.Cells(i, 3).Value) <> Month(.Cells(i - 1, 3).Value)) Or i = fr Then
intMonth = Month(.Cells(i, 3).Value)
intYear = Year(.Cells(i, 3).Value)
.Rows(i & ":" & i + 2).Insert Shift:=xlDown
.Cells(i + 1, 1).Value = "Monthly Total (" & MonthName(intMonth) & ")"
.Cells(i + 1, 2).Formula = "=SUMPRODUCT((MONTH($C$" & fr & ":$C$" & lr & ")=" & intMonth & ")*(YEAR($C$" & fr & ":$C$" & lr & ")=" & intYear & ")*$E$" & fr & ":$E$" & lr & ")"
i = i + 3
End If
End With
Next i
lblError:
If Err.Number <> 0 Then
MsgBox "Error (" & Err.Number & "): " & Err.Description, vbOKOnly + vbCritical
End If
GoTo lblExit
lblExit:
Application.DisplayAlerts = True
Application.ScreenUpdating = True
Application.Calculate
Application.Calculation = xlCalculationAutomatic
Exit Sub
End Sub
This line begins the insertion at Row i.
.Rows(i & ":" & i + 2).Insert Shift:=xlDown
You want to begin the insertion at row i+3, and you can accomplish that with the Offset method:
.Rows(i & ":" & i + 2).Offset(3).Insert Shift:=xlDown
You may also want to see this answer regarding best way of getting the "last row" in a column:
Error in finding last used cell in VBA
As you're currently doing lr = shData.Rows.Count that is 65,336 rows in Excel 2003, or 1,048,576 rows in Excel 2007+ and you almost certainly do not have that many data (otherwise an Insert would fail!), so your loop is cycling needlessly over a bunch of empty rows.
You need to change this row:
intMonth = Month(.Cells(i, 3).Value)
to
intMonth = Month(.Cells(i-1, 3).Value)
At the moment it is setting intMonth to the value of the current cell (which is the first cell of the next month) instead of the value of the previous cell (which contains the month you want to subtotal).
Then add a condition into your loop to add the last subtotal.
Also:
If (IsDate(.Cells(i, 3).Value) And IsDate(.Cells(i - 1, 3).Value) And Month(.Cells(i, 3).Value) <> Month(.Cells(i - 1, 3).Value)) Or i = fr Then
Should this be i = lr ? as you are checking for the last line in the sheet? At the moment will always put a subtotal after the first line. You'll need to update this value when you add the three subtotal lines in as well.
I have a VBA code that calculates a formula (I know it's pretty long):
Cells(i, mcol) = "=IF(RC[-1]=""C"",(RC[-3]/SUMIFS(C[-3],C66,RC66))*(VLOOKUP('Sheet1'!RC66,GA_C!C1:C4,4,0)),SUM((RC[-3]/SUMIFS(C[-3],C66,RC66))*(VLOOKUP('Sheet1'!RC66,GA_C!C1:C4,4,0)),(RC[-3]/SUMIFS(C[-3],C66,RC66,C[-1],""GA + C""))*(VLOOKUP('Sheet1'!RC66,GA_C!C1:C3,3,0))))"
in the Vlookup it takes a 4th column in the range from C1:C4 and the 3rd column from the range C1:C3.
It was ok till the column number (4 and 3) was fixed.
Now it changes each time running For cycle.
Foe example, the second run column numbers will be 5 and 4, the third run 6 and 5 and so on till 12.
Is there any way to integrate the column number changed dynamically into the formula above?
Thanks a lot!
I put also a whole code as well.
Sub AutoCalcV2()
Dim ws As Worksheet
Dim LastRow As Long
Dim i As Integer, n As Integer, x As Integer, j As Integer, mcol As Integer
Set ws = ActiveWorkbook.Sheets("Sheet1")
ws.Select
LastRow = Sheets("Sheet1").Range("A" & Sheets("Sheet1").Rows.Count).End(xlUp).Row
mcol = 71
For j = 1 To 11
mcol = mcol + 1
For i = 3 To LastRow
On Error Resume Next
Cells(i, mcol) = "=IF(RC[-1]=""C"",(RC[-3]/SUMIFS(C[-3],C66,RC66))*(VLOOKUP('Sheet1'!RC66,GA_C!C1:C4,4,0)),SUM((RC[-3]/SUMIFS(C[-3],C66,RC66))*(VLOOKUP('Sheet1'!RC66,GA_C!C1:C4,4,0)),(RC[-3]/SUMIFS(C[-3],C66,RC66,C[-1],""GA + C""))*(VLOOKUP('Sheet1'!RC66,GA_C!C1:C3,3,0))))"
Range("BT4").Select
Next i
Next j
End Sub
Dim iColumn as Integer
mcol = 71
For j = 1 To 11
iColumn = 4
mcol = mcol + 1
For i = 3 To LastRow
On Error Resume Next
Cells(i, mcol) = "=IF(RC[-1]=""C"",(RC[-3]/SUMIFS(C[-3],C66,RC66))*(VLOOKUP('Sheet1'!RC66,GA_C!C1:C4," & str(iColumn) & ",0)),SUM((RC[-3]/SUMIFS(C[-3],C66,RC66))*(VLOOKUP('Sheet1'!RC66,GA_C!C1:C4," & str(iColumn) & ",0)),(RC[-3]/SUMIFS(C[-3],C66,RC66,C[-1],""GA + C""))*(VLOOKUP('Sheet1'!RC66,GA_C!C1:C3,3,0))))"
Range("BT4").Select
iColumn = iColumn + 1
Next i
Next j
So based on what I understood, you have 3 vlookups and you want to use 4 (4+1,5+1,6+1) for first Two vlookups and 3 (3+1,4+1,5+1) for third one.
If that so, here how you can increment your 4 and 3.
Sub AutoCalcV2()
Dim ws As Worksheet
Dim LastRow As Long
Dim i, n, x, j, mcol, iCol As Integer '<-- Changed here
Set ws = ActiveWorkbook.Sheets("Sheet1")
ws.Select
LastRow = Sheets("Sheet1").Range("A" & Sheets("Sheet1").Rows.Count).End(xlUp).Row
mcol = 71
iCol = 4 '<-- Newly added
For j = 1 To 11
mcol = mcol + 1
For i = 3 To LastRow
On Error Resume Next
'Changed the formula
Cells(i, mcol) = "=IF(RC[-1]=""C"",(RC[-3]/SUMIFS(C[-3],C66,RC66))" & _
"*(VLOOKUP('Sheet1'!RC66,GA_C!C1:C4," & iCol & ",0)),SUM((RC[-3]/SUMIFS(C[-3],C66,RC66))" & _
"*(VLOOKUP('Sheet1'!RC66,GA_C!C1:C4," & iCol & ",0)),(RC[-3]/SUMIFS(C[-3],C66,RC66,C[-1],""GA + C""))" & _
"*(VLOOKUP('Sheet1'!RC66,GA_C!C1:C3," & i & ",0))))"
Range("BT4").Select
iCol = iCol + 1
Next i
Next j
End Sub
OK, Take a look. I can give an suggestion for you. Not the whole formula, Just a part of VLOOKUP.
I know that this is your formula for cell in loop:
Cells(i, mcol) = "=IF(RC[-1]=""C"",(RC[-3]/SUMIFS(C[-3],C66,RC66))*(VLOOKUP('Sheet1'!RC66,GA_C!C1:C4,4,0)),SUM((RC[-3]/SUMIFS(C[-3],C66,RC66))*(VLOOKUP('Sheet1'!RC66,GA_C!C1:C4,4,0)),(RC[-3]/SUMIFS(C[-3],C66,RC66,C[-1],""GA + C""))*(VLOOKUP('Sheet1'!RC66,GA_C!C1:C3,3,0))))"
Now is you want to change the dynamically the column according to looping. I understand the column pair as follow:
C1:C4 & C1:C3
C1:C5 & C1:C4
C1:C6 & C1:C5
C1:C7 & C1:C6
C1:C8 & C1:C7
C1:C9 & C1:C8
C1:C10 & C1:C9
C1:C11 & C1:C10
C1:C12 & C1:C11
Actually, your looping are not clear, I can't use it. So, I used as follow:
For column = 3 To 11
mcol = mcol + 1
For row = 1 To lastRow
Cells(row , mcol) = "=IF(RC[-1]=""C"",(RC[-3]/SUMIFS(C[-3],C66,RC66))*" & _
"(VLOOKUP('Sheet1'!RC66,GA_C!C1:C" & column + 1 & "," & column + 1 & ",0))" & _
",SUM((RC[-3]/SUMIFS(C[-3],C66,RC66))*" & _
"(VLOOKUP('Sheet1'!RC66,GA_C!C1:C" & column + 1 & "," & column + 1 & ",0))" & _
",(RC[-3]/SUMIFS(C[-3],C66,RC66,C[-1],""GA + C""))*" & _
"(VLOOKUP('Sheet1'!RC66,GA_C!C1:C" & column & "," & column & ",0))))"
Next row
Next column
Try as above, it will be helpful for you.