Excel VBA - Value of a field to Number - vba

My quote generator creates an Excel document and I want to run a macro on it to just keep it's calculations. For some reason it says 'Number stored as text' when there are numbers. How can I change them to the number format using the macro? I have found out if I click once in the formula bar, the problem is solved too.
The code below is what I have now, but it won't solve the error.
Range("A1:A" & LastRow).Select
Selection.NumberFormat = "0"
Column A contains an amount (1, 2, 3, etc). I have another column with the same problem, but this contains a currency in € and has 2 decimal places.
Range("I1:I" & LastRow).Select
Selection.NumberFormat = "0.00"
Thanks for your help! :)
Extra shoutout to Siddharth who helped me complete this complete issue.

Tom,
There are 3 ways to solve this
1) Go Back to your quote generator and see how it is saving the data to Excel Sheet and amend the code there
2) Manually: Highlight the Range and click on the exclamation mark next to the Green Triangle and click on "Convert to Number" See snapshot
3) Use this code.
Sub Sample()
Dim LastRow As Long, i As Long
LastRow = Sheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
Sheets("Sheet1").Range("A1:A" & LastRow).NumberFormat = "0"
For i = 1 To LastRow
If Val(Sheets("Sheet1").Range("A" & i).Value) <> 0 Then _
Sheets("Sheet1").Range("A" & i).Formula = _
Val(Sheets("Sheet1").Range("A" & i).Value)
Next i
Dim temp As Double
LastRow = Sheets("Sheet1").Range("I" & Rows.Count).End(xlUp).Row
Sheets("Sheet1").Range("I1:I" & LastRow).NumberFormat = "\$#,##0.00"
For i = 1 To LastRow
If Val(Sheets("Sheet1").Range("I" & i).Value) <> 0 Then
temp = Sheets("Sheet1").Range("I" & i).Value
Sheets("Sheet1").Range("I" & i).ClearContents
Sheets("Sheet1").Range("I" & i).Value = temp
End If
Next i
End Sub
FOLLOW UP
Before and After snapshot attached
MORE FOLLOW UP (IMPORTANT)
If you have different regional settings then you will have to take care of them appropriately.
For Example Dutch Belgium you have to use "," for a decimal. Please see snapshot.

Try this different ways:-
Way 1
Selection.NumberFormat = "General"
Way 2
vStr = "1000.5"
intNum = CInt(vStr)
Way 3
Convert Text to Numbers With VBA
If you frequently convert text to numbers, you can use a macro.
Add a button to an existing toolbar, and attach the macro to that button. Then, select the cells, and click the toolbar button.
Sub ConvertToNumbers()
Cells.SpecialCells(xlCellTypeLastCell) _
.Offset(1, 1).Copy
Selection.PasteSpecial Paste:=xlPasteValues, _
Operation:=xlPasteSpecialOperationAdd
With Selection
.VerticalAlignment = xlTop
.WrapText = False
End With
Selection.EntireColumn.AutoFit
End Sub

Related

Dyanmic VBA code for changing the vba when a sheet name is changed

I have a vba code which specifies particular sheet names to look at for example sheet 2,
But what if, someone forgot to change the sheet name to sheet2, can I add a piece of dynamic code to automatically change the vba code for which ever the sheet name is called? for example the second sheet in from the left.
Code Module 1:
Sub Calculation()
Range("P2:P800").Select
Application.CutCopyMode = False
Selection.ClearContents
Dim dict1 As Object
Dim c1 As Variant, k As Variant
Dim currWS As Worksheet
Dim i As Double, lastRow As Double, tot As Double
Dim number1 As Double, number2 As Double, firstRow As Double
Set dict1 = CreateObject("Scripting.Dictionary")
Set currWS = ThisWorkbook.Sheets("Trade data")
'get last row withh data in Column A
lastRow = currWS.Cells(Rows.Count, "M").End(xlUp).Row
'put unique numbers in Column A in dict1
c1 = Range("M2:V" & lastRow)
For i = 1 To UBound(c1, 1)
If c1(i, 1) <> "" Then
'make combination with first 4 characters
dict1(Left(c1(i, 1), 4) & "," & Left(c1(i, 8), 4) & "," & Left(c1(i,
6), 10) & "," & Left(c1(i, 10), 7)) = 1
End If
Next i
'loop through all the numbers in column A
For Each k In dict1.keys
number1 = Split(k, ",")(0)
number2 = Split(k, ",")(1)
tot = 0
firstRow = 0
For i = 2 To lastRow
If k = Left(currWS.Range("M" & i).Value, 4) & "," &
Left(currWS.Range("T" & i).Value, 4) & "," & currWS.Range("R" &
i).Value & "," & (currWS.Range("O" & i).Value) Then
If firstRow = 0 Then
firstRow = i
End If
tot = tot + currWS.Range("W" & i).Value
End If
Next i
currWS.Range("P" & firstRow) = tot
Next k
Call Consolidate
Call SingleTradeMove
End Sub
Module 2 code:
Sub SingleTradeMove()
Dim wsTD As Worksheet
Set wsTD = Worksheets("Trade data")
Sheets("UnMatching").Range("A2:AK600").ClearContents
With wsTD
lastRow = .Range("A" & .Rows.Count).End(xlUp).Row
For i = 2 To lastRow
If Left(.Cells(i, "M"), 4) <> Left(.Cells(i, "T"), 4) _
Or .Cells(i, "O") <> .Cells(i, "V") _
Or .Cells(i, "R") <> .Cells(i, "Y") Then
.Cells(i, "J").EntireRow.Copy _
Destination:=Sheets("UnMatching").Range("A" & Rows.Count).End(xlUp).Offset(1)
End If
Next i
End With
End Sub
Building off ian0411's answer since I can not comment yet. You can also change this name to short hand. I always change mine to CN and then an abbreviation or something short enough its not a hassle to type out. In the example the sheet name in excel is BlueMoon. So I used CNBM in VBA. This gives a reference to the sheet, and the sheet name on excel's side can be changed without effecting your code. To change the name, click the sheet you want to name in the properties box. Then below that alter the (Name) option.
Say you have a sheet named "Work data" and you programmed as Sheets("Work data"). To make this dynamic, you can use the name before the parenthese that when you launch your Visual Basic editor.
For example, you have this code:
Sheets("Work data").Select
Now you can change to this:
Sheet1.Select
And this way, no matter how users changed the sheet name, it will always work. BUT please remember, the Sheet1 can be also changed but that can only be done inside Visual Basic editor properties. You can password protected the VBA so no one can accidentally alter it.

Autofill formulas not dynamic

I'm trying to autofill down some formulas, but instead of updating the cell reference when copying down, it keeps the same reference. This is happening for copying down both the VLookup and If(and) statements. The relevant part of the code is below, the part in question below the comments 'Now let's get the 2014 Data and below.
Sub sidebyside()
'
' test Macro
'
'
Dim lastRow2014 As Long
ActiveSheet.Range("$A$10:$V$4388").AutoFilter Field:=11, Criteria1:="1"
lastRow2014 = Range("A" & Rows.Count).End(xlUp).Row
' Get side-by-side data for comparison
Range("E10").Value = "Full Name"
Range("Y10").Value = "Full name"
Range("Z10").Value = "2014 Data"
Range("AA10").Value = "2016 Data"
Range("Y11").Select
Range("Y11").Formula = "=E11"
'Copy this down to the lastrow of the lefthand side (lastRow2014)
Range("Y11").AutoFill Destination:=Range("Y11", "Y" & lastRow2014)
'Now let's get the 2014 data
'Range("I11: I" & lastRow2014).Copy Destination:=Range("Z11")
Range("Z11").FormulaR1C1 = "=VLOOKUP(Y11,E: I, 5, FALSE)"
Range("Z11").AutoFill Destination:=Range("Z11", "Z" & lastRow2014)
'Let's get the corresponding 2016 data.
'VLOOKUP!
Range("AA11").FormulaR1C1 = "=VLOOKUP(Y11,P:T,5,FALSE)"
Range("AA11").Select
'Selection.AutoFill Destination:=Range("AA3:AA" & Range(
Selection.AutoFill Destination:=Range("AA11:AA" & Range("T" & Rows.Count).End(xlUp).Row)
'Now, let's calculate the percentage. The trick will be the reference.
Range("AA4").FormulaR1C1 = "='Summary 2'!M3" 'This is the index from the summary tab
Range("AA10").Value = "Within?"
Range("AA11").Formula = "=IF(AND(Y11 <=(Z11 + ($AA$4 * Z11)), Y11 >= (Z11 - (Z11 * $AA$4))), ""WITHIN"", ""NOT"")"
Range("AA11").Select
Selection.FillDown
Instead of populating the first formula and filling it down, populate all formulas at once:
For example:
Range("Y11:Y" & lastRow2014).Formula = "=E11"
instead of:
Range("Y11").Select
Range("Y11").Formula = "=E11"
'Copy this down to the lastrow of the lefthand side (lastRow2014)
Range("Y11").AutoFill Destination:=Range("Y11", "Y" & lastRow2014)
Sticking to this, you can modify your Z equation with:
Range("Z11:Z" & lastRow2014).Formula = "=VLOOKUP(Y11,E:I, 5, FALSE)"
The issue you are running into is the extra space in your VLOOKUP. "E: I" should be "E:I".

Copying to cells without having to select them first

I'm currently trying to use VBA to copy some cells from one location to another and because I'm new to VBA I was wondering if anyone could help me make my code a bit more efficient I know there must be a way to copy to a cell without having to select the cell and then copy to it
For i = 1 To dataSheet.Range("A" & dataSheet.Rows.Count).End(xlUp).Row
dataSheet.Range("A" & i & ":" & "CT" & i).Copy
Set rCell = dataSheet.Range("C" & i)
pasteSheet.Activate
If rCell = condition1 Then
With ActiveSheet
.Range("CU" & rowLoop2).Select
ActiveSheet.paste
End With
You have 2 options. Either use the .PasteSpecial method, or you can just reference the original range and set the new range to it's value.
.Range("CU" & rowLoop2).PasteSpecial Paste:=xlPasteAll
With the setting values option, you have to define the whole range which the values should fill.
Range("A3:E3").Value = Range("A1:E1").Value
If you just used Range("A3").Value = Range("A1:E1").Value only cell A3 would be populated, and it would take th value from cell A1. Hope this helps.
Edit: it's worth noting that you do not have to change sheets to paste either. Your code could be amended to the below:
With dataSheet
For i = 1 To .Range("A" & .Rows.Count).End(xlUp).Row
.Range("A" & i & ":" & "CT" & i).Copy
Set rCell = .Range("C" & i)
If rCell = condition1 Then
pasteSheet.Range("CU" & rowLoop2).PasteSpecial Paste:=xlPasteAll
End If
Next i
End With

Find first empty row in Excel and select

I tried adapting this post: Error in finding last used cell in VBA to my needs but couldn't quite get it to work.
I'm pasting data into a new worksheet and then want to select the first empty row after data. Currently what's happening is the data is pasted and then the very first row in the sheet is selected. See code below. Any thoughts?
'runs when user enters data
If Target.Cells.Count = 1 And _
Not Application.Intersect(Target, [I3:I10000]) Is Nothing Then
Application.EnableEvents = False
'User inputs type of event
Archive = InputBox("Was this event a Win, Loss, or Close? (Please input Win/Loss/Close)")
With Target
If Archive = "Win" Then
'all data to transfer is selected and cut
.EntireRow.Select
Selection.Cut
'the receiving sheet is selected and data is pasted to the selected cell
Sheets("Win").Select
ActiveSheet.Paste
'the selection on the sheet the data was cut from is deleted
Sheets("Begin").Select
Selection.Delete
'this is the issue I'm having - I want to select the row below the row I just copied into.
Sheets("Win").Select
lastRow = Range("C" & .Rows.Count).End(xlUp).Row
ActiveSheet.Range("C" & lastRow & ":C" & lastRow).EntireRow.Select
Sheets("Begin").Select
Try replacing this:
'this is the issue I'm having - I want to select the row below the row I just copied into.
Sheets("Win").Select
lastRow = Range("C" & .Rows.Count).End(xlUp).Row
ActiveSheet.Range("C" & lastRow & ":C" & lastRow).EntireRow.Select
with this:
With Sheets("Win")
lastRow = .Range("C" & .Rows.Count).End(xlUp).Row
.Cells(lastRow + 1, 1).EntireRow.Select
End With
Just to add to the existing answer. You can avoid doing so much selection by using a construction more like this:
On Error GoTo problem
Dim Archive As String
If (Target.Cells.Count = 1) And _
Not (Excel.Application.Intersect(Target, [I3:I10000]) Is Nothing) Then
Excel.Application.EnableEvents = False
'User inputs type of event
Archive = InputBox("Was this event a Win, Loss, or Close? (Please input Win/Loss/Close)")
With Target
'>>>> good idea to defend against users entering "win" instead of "Win"
If (LCase(Archive) = "win") Then
'>>>> find the last row in Win sheet at the beginning
With Sheets("Win")
lr = .Range("C" & .Rows.Count).End(Excel.xlUp).Row
End With
'>>>> as you are cutting there should be no need to do any subsequent deletion or clearcontents
.EntireRow.Cut Sheets("Win").Rows(lr + 1)
End If
End With
End If
problem:
Excel.Application.EnableEvents = True

Splitting cell with multiple data into multiple rows in more than 1 column

I have a sheet with multiple data in 1 cell this happen in a couple of columns. What I need to do is split the cell into individual rows while still keep the details from the other columns
Screen 1 shows the data i got
http://imageshack.com/a/img845/1783/wxc8.png (Screen 1)
Screen 2 is what i wish the macro to output.
http://imageshack.com/a/img842/7356/7yra.png (screen 2)
The macro i found and edited in only allows me to split 1 column and i can't get the editing of the range right. the columns that needs to be split is "J" "K" "N" and "O". The columns "A"- "I" and "L""M" just needs to copy their content to the new row.
Thank you in advance for the help.
Here the Macro im using
Sub Splt1()
Dim LR As Long, i As Long
Dim X As Variant
Application.ScreenUpdating = False
LR = Range("J" & Rows.Count).End(xlUp).Row
Columns("J").Insert
For i = LR To 1 Step -1
With Range("K" & i)
If InStr(.Value, Chr(10)) = 0 Then
.Offset(, -1).Value = .Value
Else
X = Split(.Value, Chr(10))
.Offset(1).Resize(UBound(X)).EntireRow.Insert
.Offset(, -1).Resize(UBound(X) - LBound(X) + 1).Value = Application.Transpose(X)
End If
End With
Next i
Columns("K").Delete
LR = Range("J" & Rows.Count).End(xlUp).Row
With Range("L1:M" & LR)
On Error Resume Next
.SpecialCells(xlCellTypeBlanks).FormulaR1C1 = "=R[-1]C"
On Error GoTo 0
.Value = .Value
End With
Application.ScreenUpdating = True
End Sub
The problem appears to be the with operator. It constrains your selection. Try reformulating your macro without the with and refer to the the ranges direct. For example, replace your first for loop with something like this:
For i = LR To 1 Step -1
If InStr(Range("K" & i).Value, Chr(10)) = 0 Then
Range("K" & i).Offset(, -1).Value = Range("K" & i).Value
'Range("J" ...
'Range("N" ...
'Range("O" ...
Else
K_collection = Split(Range("K" & i).Value, Chr(10))
Range("K" & i).Offset(1).Resize(UBound(K_collection)).EntireRow.Insert
Range("K" & i).Offset(, -1).Resize(UBound(K_collection) - LBound(K_collection) + 1).Value = Application.Transpose(K_collection)
'J_collection = Split(Range("J"...
'N_collection = Split(Range("N"...
'O_collection = Split(Range("O"...
End If
Next i
In general I avoid with because it tends to obscure the visual pattern of code.
You might also consider eliminating the .INSERT and .DELETE columns, and overwrite directly to the cells. When working with more than one at a time, it becomes hard to keep track which column is temporary and which one is the source. But that all depends on your preference.
Copying values for the other columns should be easy compared to this.