Convert numbers stored as text to numbers? - excel

How can I convert numbers stored as text to numbers?
I have tried setting:
ActiveSheet.Range("H154").NumberFormat = "General"
But it doesn't work!
The only things I've found that work are using "Text to columns" or clicking the cell to edit it and then clicking Enter.
But I would really like to find a way to turn number cells in a sheet stored as text into numbers using VBA.

A general technique is to Copy PasteSpecial, Multiply by 1
In code, something like this:
Sub ConvertToNumber()
Dim rng As Range
Dim cl As Range
Dim rConst As Range
' pick an unused cell
Set rConst = Cells(1, 4)
rConst = 1
Set rng = Cells.SpecialCells(xlCellTypeConstants)
rng.NumberFormat = "General"
rConst.Copy
rng.PasteSpecial xlPasteValues, xlPasteSpecialOperationMultiply
rConst.Clear
End Sub

Just use CDbl():
ActiveSheet.Range("H154") = CDbl(ActiveSheet.Range("H154"))

I'm not a coding expert and the "Number Stored as Text" error plagued me for a long time.
I finally found this:
Delimited Text-to-Columns in a Macro
Which got me to this:
Sub ConvertTextToNumber()
Sheets("Worksheet_Name").Select
Range("A1").Select
Selection.TextToColumns _
Destination:=Range("A:A"), _
DataType:=xlDelimited
End Sub
I use this in a macro to copy & reorder columns in a new sheet:
Sub ColumnReorder()
'**********************************************************
'Paste this macro into the Workbook of each new "Employee_List_Weekly_Update"
'Functionality:
'1. Column order in the "Employee_List_Weekly_Update" worksheet changes fairly often.
' The macro will find each column by header name,
' select that column and copy it to the new sheet.
'2. The macro also converts "Employee ID#" to a number,
' removing the "Number saved as Text" error.
'**********************************************************
'Create new sheet
Sheets.Add.Name = "Roster_Columns_Reordered"
'Repeat for each column or range
'Find Column in "Employee_List_Weekly_Update" - Copy it - Paste it in "Roster_Columns_Reordered" - Employee ID#
Dim a As Integer
Sheets("Employee_List_Weekly_Update").Select
Set rngData = Range("A1").CurrentRegion
a = Application.WorksheetFunction.Match("Employee ID#", Range("A1:BB1"), 0)
Columns(a).Select
Selection.Copy
Sheets("Roster_Columns_Reordered").Select
Range("A1").Select
ActiveSheet.Paste
'Use TextToColumns to convert "Number Stored as Text "
Selection.TextToColumns _
Destination:=Range("A:A"), _
DataType:=xlDelimited
'Find Column in "Employee_List_Weekly_Update" - Copy it - Paste it in "Roster_Columns_Reordered" - Name
Dim b As Integer
Sheets("Employee_List_Weekly_Update").Select
Set rngData = Range("A1").CurrentRegion
b = Application.WorksheetFunction.Match("Name", Range("A1:BB1"), 0)
Columns(b).Select
Selection.Copy
Sheets("Roster_Columns_Reordered").Select
Range("B1").Select
ActiveSheet.Paste
'Go to "Roster_Columns_Reordered" - Add AutoFilter - Freeze Top Row
Rows("1:1").Select
Selection.AutoFilter
With ActiveWindow
.SplitColumn = 2
.SplitRow = 1
End With
Rows("2:2").Select
ActiveWindow.FreezePanes = True
Range("A1").Select
End Sub

if you want to convert a selection (even with text in it!), you can use the code by firefiend (http://www.ozgrid.com/forum/showthread.php?t=64027&p=331498#post331498)
I think the magic is in .Value = .Value
vba
Sub macro()
Range("F:F").Select 'specify the range which suits your purpose
With Selection
.NumberFormat = "General"
.Value = .Value
End With
End Sub

Related

Excel Macro to Insert Row, with formatting, below header of named range

I would like the user to be able to click the green button on the right of each named range to insert a new data entry row below the named range header. The code I have hard codes the insert row number for the first named range. I need a way to have the code to be smart enough to know that the first row below the header of the second, third, & forth named range will changed.
Another big part is that the inserted row needs to have the same formatting (dropdowns, formulas, color, etc.) as the rows below.
First named range button code:
Sub BidSheetAddRow_Materials()
' BidSheetAddRow_Materials Macro
Rows("19:19").Select
Selection.Copy
Rows("19:19").Select
Selection.Insert Shift:=xlDown
Range("A19").Select
Application.CutCopyMode = False
Selection.ClearContents
Range("C19").Select
Selection.ClearContents
Range("K19").Select
Selection.ClearContents
End Sub
Based on the screenshot all table headers are in colA, the first input row is 3 cells below the header, and the first input cell on each table row is a merged cell.
So this works for me:
Sub AddMaterial()
AddRow "MATERIALS"
End Sub
Sub AddRate()
AddRow "RATE"
End Sub
Sub AddRow(TableHeader As String)
Dim f As Range, ws As Worksheet, c As Range
Set ws = ThisWorkbook.Worksheets("Input") 'or whatever
Set f = ws.Columns("A").Find(what:=TableHeader, lookat:=xlWhole) 'find the header
If Not f Is Nothing Then
Set c = f.Offset(3) 'step down to first input row below header
Do While c.Offset(1).MergeArea.Cells.Count > 1 'keep looping while `c` is merged
Set c = c.Offset(1)
Loop
c.Offset(1).EntireRow.Insert shift:=xlDown 'insert
c.EntireRow.Copy c.Offset(1) 'copy
c.Offset(1).EntireRow.ClearContents 'clear new row
Else
MsgBox "Table header '" & TableHeader & "' not found!"
End If
End Sub
Before/after:

Vlookup from Another Workbook with fill to Last Row

I'm looking to import data from another file (combinedWorkbook) to my master file (the file which is running the code) using a vlookup. I then need it to drag the vlookup down to the bottom row of data (using column M in the masterfile as a reference to when the data ends) with cell I15 being the starting point for the vlookup in the masterfile.
The problem I'm having is that when running the macro the vlookup is happening in cell M10 in my masterfile, not dragging down the vlookup to the end of the data and not referencing the combinedWorkbook.
Any help would be appreciated.
This is what I got so far
Dim combinedBook As Workbook
Dim filter As String
Dim caption As String
Dim combinedFilename As String
Dim combinedWorkbook As Workbook
Dim targetWorkbook As Workbook
MsgBox ("Select Unpaid Capital Extract")
Set targetWorkbook = ThisWorkbook
filter = "Text files (*.xlsx),*.xlsx"
caption = "Please Select an input file"
combinedFilename = Application.GetOpenFilename(filter, , caption)
Set combinedWorkbook = Application.Workbooks.Open(combinedFilename)
ThisWorkbook.Activate
ActiveCell.FormulaR1C1 = _
"=VLOOKUP(RC[-8],combinedWorbookSheet1!R1C1:R700000C2,2,0)"
Range("M16").Select
Selection.End(xlDown).Select
Range(Selection, Selection.End(xlUp)).Select
Range("I15:I60297").Select
Range("I60297").Activate
Selection.FillDown
Range("I15").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Application.CutCopyMode = False
Selection.End(xlUp).Select
Range("I15").Select
combinedWorkbook.Close False
There are simply too many unknowns in your code to give a specific answer.
Some observations:
1) Always use Option Explicit at the top of your code, it will pick up mistakes and inconsistencies for you.
2) Watch out for unused variables declared in your code
3) Always specify which workbook and worksheet you are working with; don't just put Range ... or Cells.... this leads to all sorts of bugs.
4) Your VLOOKUP syntax for working with another workbook needs to be of the order
'[" & combinedWorkbook.Name & "]Sheet1'
5) xlsx are not text files btw re: your filter
6) For the rest i.e. where you want formulas to go, how you are determining last row etc I am just having to guess. Be specific when coding and try bullet pointing pseudo code first so you are clear what is going on at each stage.
Option Explicit
Sub test()
Dim filter As String
Dim caption As String
Dim combinedFilename As String
Dim combinedWorkbook As Workbook
Dim targetWorkbook As Workbook
MsgBox "Select Unpaid Capital Extract"
Set targetWorkbook = ThisWorkbook
filter = "Text files (*.xlsx),*.xlsx"
caption = "Please Select an input file"
combinedFilename = Application.GetOpenFilename(filter, , caption)
Set combinedWorkbook = Application.Workbooks.Open(combinedFilename)
'Assuming M is used to find last row in targetWorkbook
Dim lastRow As Long
With targetWorkbook.Worksheets("Sheet1") 'this wasn't specified (specify appropriate sheet name)
lastRow = .Cells(.Rows.Count, "M").End(xlUp).Row
'Assuming I is where formula is being put
.Range("I15:I" & lastRow).FormulaR1C1 = _
"=VLOOKUP(RC[-8],'[" & combinedWorkbook.Name & "]Sheet1'!R1C1:R700000C2,2,0)"
combinedWorkbook.Close False
End With
End Sub
As I understood you need to apply a vlookup formula in your master file gathering data from another workbook.
The proper strucutre is as followed:
ActiveCell.FormulaR1C1 = "=VLOOKUP(RC[8],[Book1]Sheet1!R1C5:R23C6,2,FALSE)"
The first bold text is the place of the value you are looking for, relative to the active cell.
The second bold text is the position of your reference table in your other workbook ( here it is book 1).
You can apply this formula to your masterfile by using a loop.
Dim lastRow as Integer
lastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, "M").End(xlUp).Row
endCount = 15 + lastRow
For i = 15 to endCount
ActiveSheet.Cells(i,13).FormulaR1C1 = "=VLOOKUP(RC[-8],[combinedWorkbook]Sheet1!R1C1:R700000C2,2,FALSE)"
next i
This will apply the vlookup formula in the column I starting row 15 searching for the value in the same row but 8 column before (column "A") and will apply for as many row as there are value in the column M.

paste from clipboard transpose to last non empty cell

i want a macro to paste values from clipboard ( values that i have copied from another source)
in transpose to last non empty cell in row E in worksheet "sheet1"
any help?
Try something like this:
Sub WriteFromClipboard()
Dim refRow As Integer
Dim Data As DataObject
Dim DataText As String
On Error Resume Next
'Get row to write data:
refRow = 1 + ThisWorkbook.Sheets("Sheet1").Columns(5).Find("*", SearchOrder:=xlByRows, LookIn:=xlValues, SearchDirection:=xlPrevious).Row
If Err.Number > 0 Then
refRow = 1
End If
Err.Clear
'Get data from clipboard:
Set Data = New DataObject
Data.GetFromClipboard
DataText = Data.GetText
'Write data from clipboard on the spreadsheet:
If Err.Number > 0 Then
MsgBox "Clipboard doesn't contain valid data."
Else
ThisWorkbook.Sheets("Sheet1").Cells(refRow, 5).Select
ThisWorkbook.Sheets("Sheet1").Paste
End If
End Sub
function findLastRowInCol(wks as excel.worksheet, col as long)
dim rng as range
with wks
set rng = .cells(.rows.count, col).end(xlup)
findLastRowInCol = rng.row
end with
end function
To test from the Immediate pane:
debug.print findLastRowInCol(thisworkbook.sheets("sheet1"), 5)
This will give you the row of the last non-empty cell in the specified column. Note that this may not be the last used row of the worksheet; selecting a different column may give you a different result depending which is that column's last non-empty cell.
Edit: replaced activesheet with "sheet1"
Edit: sample code to use in another macro to paste in from some other source,
thisworkbook.sheets("sheet1").cells(findLastRowInCol(thisworkbook.sheets("sheet1"), 5), 5).pastespecial paste:=xlAll
If pasting from another Excel sheet or to strip formatting, you can use e.g. "xlPasteSpecialValues"
Edited to add: to paste a row from another worksheet and transpose, use the above as far as ".pastespecial" then use some variation on:
.pastespecial paste:=xlpastevalues, transpose:=True
The simplest implementation is,
sub PasteToE()
thisworkbook.sheets("sheet1").cells(findLastRowInCol(thisworkbook.sheets("sheet1"), 5),5).pastespecial paste:=xlpastevalues, transpose:=True
end sub
Add a commandbutton to the other worksheet and assign this macro to it. Select your range and copy it, then click the button.

Force "F2"+"Enter" on range of cells

I have an Excel 2010 worksheet which has macros to copy data from other sheets into a specific format on another sheet.
The data copies but I have an issue with the formatting of cell ranges which hold date or time values.
The data originates from a database extract and everything is in text format. In my worksheet when I copy the date (via VBA) I apply the format "yyyy-mm-dd" for dates and "hh:mm.ss.ss" for times.
There is never a fixed amount of rows so I've set the VBA code to apply the formatting to the range of cells for example:
AssDateLastRow = shAss.Range("C" & Rows.Count).End(xlUp).Row
shAss.Range("C4:C" & AssDateLastRow).NumberFormat = "yyyy-mm-dd"
Not all cells in the range have the correct format, they will appear as 15/04/2014 not 2014-04-15. If I manually select the cell and press the F2 then ENTER keys the format appears as I need. This happens randomly through the range and there could be thousands of rows so it is not practical to trawl though the worksheet manually hitting F2+ENTER on each one.
I've looked on the internet and found what should automatically do the F2+ENTER with VBA.
The code below is extracted from a larger set of lines of code, so the Dim statements etc. are further up in the actual copy, but this should show the way I've tackled this so far.
Dim shAss As Worksheet
Dim AssDateLastRow As Long
Dim c As Range
'enter method to format 'Date Craftperson Assigned' and 'Time Craftperson Assigned' in Assignments sheet
'column "C" and "D", to formats required by Archibus: date "yyyy-mm-dd", time "hh:mm.ss.ss"
AssDateLastRow = shAss.Range("C" & Rows.Count).End(xlUp).Row
shAss.Range("C4:C" & AssDateLastRow).NumberFormat = "yyyy-mm-dd"
'ensure format is applied by forcing F2 edit of cell
For Each c In shAss.Range("C4:C" & AssDateLastRow).Cells
c.Select
SendKeys "{F2}", True
SendKeys "{ENTER}", True
'Selection.NumberFormat = "yyyy-mm-dd"
Next
When I run the code, the data copies into my worksheets but the dates and times are still in a mixed format.
The attempt at forcing the F2+ENTER via the VBA doesn't seemed to have done anything. If done manually it works okay.
Below is an example of data copied from the results in the worksheet
Work Request Code Date Assigned Time Assigned
92926 19/05/2014 14:30.00.00
92927 19/05/2014 15:00.00.00
92928 2014-05-19 15:15.00.00
92934 2014-05-19 14:00.00.00
92527 12/05/2014 07:30
92528 12/05/2014 08:00
92804 2014-05-12 16:15
92805 2014-05-12 16:20.00.00
I use this simple macro to apply F2 + Enter on the currently selected range:
Sub ApplyF2()
Selection.Value = Selection.FormulaR1C1
End Sub
I can think of two options to get Excel to apply the formatting to the cells in one step.
The first is to use the Text to columns functionality even though there is nothing in the column to split.
The second option is to copy a value of 1 and paste it into the cells using the Paste Special - Multiply option.
Although either method should force an update of the cell formating, I would lean towards the first option.
This is incase some of your dates are is stored as text.
Sub Format_Text_to_Columns()
Dim AssDateLastRow As Long
AssDateLastRow = ActiveSheet.Range("C" & Rows.Count).End(xlUp).Row
ActiveSheet.Range("C4:C" & AssDateLastRow).NumberFormat = "yyyy-mm-dd;#"
'Set the format
Range("C4:C" & AssDateLastRow).Select
Selection.TextToColumns DataType:=xlDelimited, ConsecutiveDelimiter:=True, _
Space:=True, FieldInfo:=Array(1, 5)
'Use text to columns to force a format update
End Sub
Sub Format_Paste_Special_Multiply()
Dim AssDateLastRow As Long
AssDateLastRow = ActiveSheet.Range("C" & Rows.Count).End(xlUp).Row
ActiveSheet.Range("C4:C" & AssDateLastRow).NumberFormat = "yyyy-mm-dd;#"
'Set the format
Range("C1").FormulaR1C1 = "1"
Range("C1").Copy
Range("C4:C" & AssDateLastRow).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlMultiply
Application.CutCopyMode = False
Range("C1").ClearContents
'Multiply the dates by 1 to force a format update
End Sub
I struggled to get this to work too. My problem has been not just dates but also data with a single quote in front of it. What I hacked together works great for me. It cleans up over 70,000 cells very fast. Hope it works for you:
(you will change the range and such to suit your needs)
Dim MyRange As Range
Set MyRange = Range(Cells(2, 7), [G1].End(xlDown))
For Each MyRange In MyRange.Cells
'Mimic F2 without SendKeys
MyRange.Value = MyRange.Value
Next
This worked for me.
Dim r As Range
Dim n As Integer
Dim AssDateLastRow As Long
AssDateLastRow = ActiveSheet.Range("E" & Rows.Count).End(xlUp).Row
Set r = Range("E2:E" & AssDateLastRow)
r.Select
r.NumberFormat = "ddmmyyyy;#"
r.Select
For n = 1 To r.Rows.Count
SendKeys "{F2}", True
SendKeys "{ENTER}", True
Next n
It is possible to use Text to Columns to solve this problem
1) Highlight the column of data
2) Go to Data -> Text To Columns -> Delimited -> (deselect everything) -> Next
3) On page 3 of the wizard, set the Column Data Format YMD
4) OK
Sub RefreshCells()
Dim r As Range, rr As Range
Set rr = Selection
For Each r In rr
r.Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Application.CutCopyMode = False
Application.SendKeys "{F2}"
Application.SendKeys "{ENTER}"
Application.SendKeys "+{ENTER}"
DoEvents
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Application.CutCopyMode = False
Application.SendKeys "{ENTER}"
DoEvents
Next
End Sub
It seems odd that you would need to send keys F2 + Enter. What is the formatting before you run the macro? Try formatting the whole column that way (it won't affect the text).
Columns("C:C").NumberFormat = "yyyy-mm-dd"
My variation
n = Selection.Rows.count
Dim r1 As range, rv As range
Set r1 = Selection.Cells(1, 1)
For I = 1 To n
Set rv = r1.offset(I - 1, 0)
vali = rv.value
IsNumeric(vali) Then
vali = CDbl(vali)
rv.value = 0
rv.value = vali
End If
Try to press F9 or File-Option-formulas-workbook calculation- automatic
I just set the cell to the right of the top entry equal to a formula that multiplied the problem cell times 1. That new cell was a proper number, so then double clicking the handle extended it down the whole column fixed them all!
Sendkeys are not stable. The better way is to store the text in the clipboard and paste it.
See here on how to store values in the clipboard
Sub CopyText(Text As String)
Dim MSForms_DataObject As Object
Set MSForms_DataObject = CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
MSForms_DataObject.SetText Text
MSForms_DataObject.PutInClipboard
Set MSForms_DataObject = Nothing
End Sub
Sub Test()
CopyText (ActiveCell.Value)
ActiveCell.PasteSpecial
End Sub
'In place of active cell, you may pass a range
This works for me
Sub f2Cells(sel as Range)
Dim rng as Range
On Error GoTo exitHere
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
For Each rng In sel.Cells
If Not Intersect(sel, Application.Range(rng.Address)) Is Nothing And _
Application.Range(rng.Address).EntireColumn.Hidden = False And _
Application.Range(rng.Address).EntireRow.Hidden = False Then
Application.Range(rng.Address).Application.SendKeys "({F2}{ENTER})", True
End If
Next rng
exitHere:
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End With
Application.SendKeys "{NUMLOCK}", True
End Sub
Then from your function you can just call
f2Cells shAss.Range("C4:C" & AssDateLastRow)
I just got it, Simple
Select all the cells you want to hit F2 and Enter and run this short macro:
Sub AutoF2Enter()
Selection.Value = Selection.Value
End Sub
Works on date and numbers!
50.000 cells in a second!

excel database function in combination with vba, what if there are no records?

I'm using the database function of excel. see example image
I use vba to select records that have 'yes' for lets say A
Selection.AutoFilter Field:=2, Criteria1:="yes"
Range("B3").Select
Range(Selection, Selection.End(xlDown)).Select
I then copy it to paste it somewhere else. for example:
Selection.Copy
Range("B12").Select
ActiveSheet.Paste
The problem is that when there are no records with yes, i get error 1004. Probably because there is nothing to paste. How do I write a script so that if there is nothing to paste, it exits the sub?
I tried things like counta but to no succes.
Your help is much appreciated! :)
I like doing it this way because you don't need to error check it. If there are no results, it will simply paste a blank cell:
Sub tgr()
With Range("B2").CurrentRegion
.AutoFilter 2, "yes"
Intersect(.Offset(1), Columns("B")).Copy Range("B12")
.AutoFilter
End With
End Sub
Alternately, if you only have one criteria, you could use Countif to test if the criteria exists before performing the filter:
Sub tgr()
Dim strCriteria As String
strCriteria = "yes"
With Range("B2").CurrentRegion
If WorksheetFunction.CountIf(Intersect(.Cells, Columns("C")), strCriteria) > 0 Then
.AutoFilter 2, strCriteria
Intersect(.Offset(1), Columns("B")).Copy Range("B12")
.AutoFilter
Else
MsgBox "No cells found to contain """ & strCriteria & """", , "No Matches"
End If
End With
End Sub
This will check the number of visible cells after the AutoFilter is applied:
Selection.AutoFilter Field:=2, Criteria1:="yes"
If ActiveSheet.AutoFilter.Range.Rows.Offset(1, 0).SpecialCells(xlCellTypeVisible).Count - ActiveSheet.AutoFilter.Range.Columns.Count > 0 Then
Range("B3").Select
Range(Range("b3"), Range("b2").End(xlDown)).Select
Selection.Copy
Range("B12").Select
ActiveSheet.Paste
End If
The - ActiveSheet.AutoFilter.Range.Columns.Count part is to subtract the header cells from the count.
FWIW, when I walked through your original code, I got the 1004 because the Copy area was from B7 to the bottom of the sheet (the effect of xlDown in an empty selection).
You can use the SUBTOTAL worksheet function to count the visible rows and only do the copy and paste if there are visible rows. Here's an example.
Sub CopyFiltered()
Dim rToFilter As Range
Dim rToCopy As Range
Dim rToPaste As Range
Set rToFilter = Selection
Set rToPaste = rToFilter.Cells(1).Offset(10, 0) 'paste it 10 rows down
rToFilter.AutoFilter 2, "yes"
'Use subototal to count the visible rows in column 1
If Application.WorksheetFunction.Subtotal(2, rToFilter.Columns(1)) > 0 Then
'Copy excluding the header row
Set rToCopy = rToFilter.Columns(1).Offset(1, 0).Resize(rToFilter.Rows.Count - 1)
rToCopy.Copy Destination:=rToPaste
End If
End Sub

Resources