VBA/excel-VBA - add two values with dot separator - vba

I'm new to VBA and need to add two values using VBA in Excel. I receive imported values with dot-separator and if I try to add them, the dot is ignored.
So:
1.12
1.34
should result in 2.46, but I'm getting 246
Code:
Do Until (Cells(iRow, 1) = 100)
addValue = Cells(iRow, 2).Value
dValue = dValue + addValue
iRow = iRow + 1
MsgBox (dValue)
Loop
Thanks for some 101-tips...
Here is the updated code:
Dim iRow As Integer
Dim addValue As Double
Dim dValue As Double
iRow = 2
Do Until (Cells(iRow, 1) = 100)
addValue = Cells(iRow, 8)
Debug.Print "Row"; iRow; " is "; addValue
modValue = Replace(addValue, ".", ",")
MsgBox (addValue)
newVal = Cells(iRow, 8).Value
dValue = dValue + newVal
iRow = iRow + 1
Loop
MsgBox (dValue)
Basically I have a lit of values like this:
100 header
200 1.12
200 1.34
200 1.54
100 header
...
I want to sum the 200 correspondig values 1.12, 1.34, 1.54. The values show up as 112, 134 and 154.
Thanks

Would you place this line after addValue =, please?
Debug.Print "Row"; iRow; " is "; addValue
Offhand, I am suspecting that the 1.12 is not really a double.
Also, did you declare your variables? Nothing fancy, but something like
Dim iRow As Integer
Dim addValue As Double
Dim dValue As Double
Finally, you may want to consider placing the MsgBox after the loop, instead of having it give a subtotal on every; iteration.

I think you have some funny number formatting applied to the values in Excel. Highlight the range and hit Ctrl-Shift-` (or format the cells as "General" from the format menu). I bet those numbers are actually 112 and 134.

Right... The problem is formatting, and Excel's insistence on describing (say) '4/7' as 'Fourth of July' rather than four-sevenths*. Or indeed, as a textual 'Four-slash-seven'.
I do not know what strange format has been picked up in those 'decimal' cells, but you have two jobs to do:
Change the number format of those cells to 'general' so you can see
what's actually in them, rather than whatever Excel wants to
present;
Change your code to use the 'Value2' property of a range, which
gives you the raw data instead of a formatted interpretation of the
'value' - newVal = Cells(iRow, 8).Value2
I would also recommend that you declare NewVal as Double. This will coerce a type conversion to floating-point number, a far better idea than letting a 'variant' decide what type it would like to be, based on formatting information in a range.
I'd better warn you that task (1) works about half the time on data imported from Oracle databases, and numbers copied from spreadsheets originating France (where the comma is used as a decimal point) are better-suited to the semiotic analyses developed by French Deconstructivist philosophers, rather than statistical analysis and arithmetic calculation.
*You'll be able (or unable) to reproduce this error some of the time, depending on your machine locale. And that's today's big lesson: a problem is worsened when it is intermittent, unpredictable, or inconsistently-reproducible.

Related

the curious case of disappearing decimals

I have an issue with disappearing decimal places when I put them into arrays and then pasting them out again. not sure why this is happening at all. any soluntions?
an example below:
excel:
A B
1 Input $213,213,132,135,654.00 <--format: Accounting
2 =B1/1000000 $213,213,132.14 <--format: Accounting
3 output $213,213,132,135,700.00 <--format: Accounting
Code:
Sub test()
Dim ar() As Variant
ReDim ar(1)
ar(1) = Cells(2, 2).Value
ar(1) = ar(1) * 1000000
Cells(3, 2) = ar(1)
End Sub
213213132135654.00 / 1000000 = 213213132.135654
You provided the answer when you mentioned that it only does it when formatted as accountancy. Accountancy works to four decimal places only making the result 213213132.1357, when when multiplied gets to the non-matching 213213132135700.00.
As to a fix, I would suggest either using rounding to 4 decimal places in all formula or do the math in another worksheet as numbers and then present the results on your main worksheet as accountancy.

Excel VBA code for MID/Splitting text in cell based on fixed width

I apologize if there is already the same question asked elsewhere with an answer however I have been unable to find it so here I go.
I will also mention that I am a VBA beginner, mostly playing around with codes obtained from other people to get what I want.
I currently have data in Columns A-D, with the information in column C being the important column. Everything else should be ignored.
I have a line of text in cell C1 of sheet1. It is 25 characters long and resembles the following:
4760-000004598700000000000
I have over ~970,000 rows of data and need to pull out the information found within each of these cells into two different cells in another sheet.
I cannot simply use a formula due to the number of records (excel crashes when I try).
If using the mid function for C1, I would enter something like (C1,2,3) and (C1,5,11). (except it would be for each cell in column C)
The leading zeroes between the + or - and the beginning of the first non-zero value are of no consequence but I can fix that part on my own if need be.
Ideally the information would be pulled into an existing sheet that I have prepared, in the A and B columns. (IE:sheet2)
For example, using the text provided above, the sheet would look like:
A|B
760|-0000045987 or -45987
I have looked into array, split and mid codes but I had troubles adapting them to my situation with my limited knowledge of VBA. I am sure there is a way to do this and I would appreciate any help to come up with a solution.
Thank you in advance for your help and please let me know if you need any additional information.
It sounds like what you're after could be achieved by the Text to Columns tool. I'm not sure whether you're trying to include this as a step in an existing macro, or if this is all you want the macro to do, so I'll give you both answers.
If you're just looking to split the text at a specified point, you can use the Text to Columns tool. Highlight the cells you want to modify, then go to the Data tab and select "Text to Columns" from the "Data Tools" group.
In the Text to Columns wizard, select the "Fixed Width" radio button and click Next. On step 2, click in the data preview to add breaks where you want the data to be split - so, in the example you gave above, click between "760" and "-". Click Next again.
On step 3, you can choose the format of each column that will result from the operation. This is useful with the leading zeroes you mentioned - you can set each column to "Text". When you're ready, click Finish, and the data will be split.
You can do the same thing with VBA using a fairly simple bit of code, which can be standalone or integrated into a larger macro.
Sub RunTextToColumns()
Dim rngAll As Range
Set rngAll = Range("A1", "A970000")
rngAll.TextToColumns _
DataType:=xlFixedWidth, _
FieldInfo:=Array(Array(0, 2), Array(3, 2))
With Sheets("Sheet4").Range("A1", "A970000")
.Value = Range("A1", "A970000").Value
.Offset(0, 1).Value = Range("B1", "B970000").Value
End With
End Sub
This takes around a second to run, including the split and copying the data. Of course, the hard-coded references to ranges and worksheets are bad practice, and should be replaced with either variables or constants, but I left it this way for the sake of clarity.
How about this:
Sub GetNumbers()
Dim Cel As Range, Rng As Range, sCode As String
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set Rng = Sheets("Sheet1").Range("C1:C" & Sheets("Sheet1").Range("C1048576").End(xlUp).Row)
For Each Cel In Rng
Sheets("Sheet2").Cells(Cel.Row, 1).Value = Mid(Cel.Value, 2, 3)
sCode = Mid(Cel.Value, 5, 11)
'Internale loop to get rid of the Zeros, reducing one-by-one
Do Until Mid(sCode, 2, 1) <> "0" And Mid(sCode, 2, 1) <> 0
sCode = Left(sCode, 1) & Right(sCode, Len(sCode) - 2)
Loop
Sheets("Sheet2").Cells(Cel.Row, 2).Value = sCode
Next
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
I think there's an array formula thing that would do this, but I prefer the brute force approach. There are two ways to fill in the fields, with a procedure or with a function. I've done both, to illustrate them for you. As well, I've purposely used a number of ways of referencing the cells and of separating the text, to illustrate the various ways of achieving your goal.
Sub SetFields()
Dim rowcounter As Long, lastrow As Long
lastrow = ActiveSheet.Cells(Rows.Count, 3).End(xlUp).Row 'get the last row in column "C"
For rowcounter = 1 To lastrow 'for each row in the range of values
'put the left part in column "D"
ActiveSheet.Range("D" & rowcounter) = FieldSplitter(ActiveSheet.Cells(rowcounter, 3).Text, True)
'and the right part in the column two over from colum "C"
ActiveSheet.Cells(rowcounter, 3).Offset(0, 2) = FieldSplitter(ActiveSheet.Cells(rowcounter, 3).Text, False)
Next rowcounter
End Sub
Function FieldSplitter(FieldText As String, boolLeft As Boolean) As String
If boolLeft Then
FieldSplitter = Mid(FieldText, 2, 3) 'one way of getting text from a string
Else
FieldSplitter = Left(Right(FieldText, 16), 5) ' another way
End If
'Another useful function is Split, as in myString = Split (fieldtext, "-")(0) This would return "4760"
End Function

Subtract two columns, with each other as a condition, and append values

I need to subtract two columns from a large array and see which ones are positive and of those positive values I need to find the positive values row and append a few things onto that value.
Here is the general concept I'm thinking so far
While < 8000
if (cell(i,1).Value - cell(i,2) > 0)
print in another sheet cell(i,3).value (cell(i,2).Value-cell(i,4)) cell.value(i,4)
for example...
suppose I have something like this
[2 2 hi yo]
[3 2 go mo]
this macro would return "go 1 mo" in another sheet.
Sub Leaves()
Dim i As Integer
Dim g As Integer
Dim Quantity As Integer
Dim Executed As Integer
Dim Leaves As Integer
i = 1
g = 1
Do While i < 8000
Quantity = Worksheets("Sheet1").Cells(i, 3).value
Executed = Worksheets("Sheet1").Cells(i, 5).value
Leaves = Quantity - Executed
If Leaves > 0 Then
Worksheets("Sheet2").Cells(g, 1).value = _
Worksheets("Sheet1").Cells(i, 9).value & _
Worksheets("Sheet2").Cells(i, 2).value & _
Leaves & Worksheets("Sheet2").Cells(i, 3).value
g = g + 1
End If
i = i + 1
Loop
End Sub
The above code gives me a Type mismatch error.
It is helpful if you say what line is throwing an error. Also, one should strive to create a Minimal, complete, and verifiable example. The effort to do so often resolves the question before you need to post it.
The code itself seems fine and it runs for me (on an empty workbook) with no type mismatch. Thus, the problem must be with your assumptions about the spreadsheet.
Either of the lines
Quantity = Worksheets("Sheet1").Cells(i, 3).value
Executed = Worksheets("Sheet1").Cells(i, 5).value
will trigger a type mismatch if the corresponding value can't be converted to an integer. This could happen, for example, if one of the cells contains a string (other than something like "1") or an error value such as #N/A or #Value!.
The line which begins
Worksheets("Sheet2").Cells(g, 1).value = _
will throw a type mismatch if one of the values being concatenated can't be converted to a string. An error value in one of the cells is the most likely culprit. If this is the case and for some reason you actually want to create a string that includes substrings which look like e.g. "#N/A" then you could use the Text property of those cells rather than Value.

Excel VB - Multiple If Column Contains Strings Then

I have looked at a bunch of questions like this, but I have only found formulas, and VB examples that don't appear to check the values of cells in a column.
I was able to derive the following formula in Excel:
=IF(AND(ISNUMBER(SEARCH("Cat",R2)),OR(ISNUMBER(SEARCH("5E",R2)),ISNUMBER(SEARCH("6",R2))), ISNUMBER(SEARCH("Patch",R2)), ISNUMBER(SEARCH("Cables",R2))), "CAT 5E Ethernet Cables")
The problem is that this formula only checks for 1 out of 500 possible values. This is not productive. Plus, I have to make it one big formula when I check the entire row, because if I don't, the formula overwrites the result of the previous formula...
So, Visual Basic... I think I may have better luck scripting some kind of IF ELSE or CASE statement. I just do not understand how to do this in excel. I need to achieve the same thing as the formula above, but instead of checking for one set of conditions,
I need to check for multiple, and populate the S & T columns based on the result of each set of conditions.
I found this webpage that just mentions Excel and shows a VB IF - ELSE statement. How can I make this statement check Excel columns?
I tried the selected answer in this post with no luck:
Private Sub UpdateCategories()
Dim x As Long
For x = 1 To 5000
If InStr(1, Sheet1.Range("$B$" & x), "cat") > 0 And InStr(1, Sheet1.Range("$B$" & x), "5e") > 0 Then
Sheet1.Range("$T$" & x) = Sheet1.Range("$T$" & x) & "CAT 5E Ethernet Cables (Test)"
End If
Next
End Sub
Any help is appreciated. Thanks in advance!
Assuming you choose the route of using a data table sheet to compare to your string.
You would need to have a sheet looking like this (Maybe this is not what you want because I didn't thoroughly understand how your data looks like but the idea remains). You could have sub-category if you want, as well as category, in a third column.
column A | column B
keyword |category
CAT |ATX Cases
5e |Mini-ITX Cases
important words |MicroATX Cases
...
This would need to be filled manually. I'm not sure about the amount of data you're looking at. It can be pretty rapid if you can copy/paste stuff efficiently, depending on the form of your data.
When you have that, loop using this code. I assume the data table is in Sheet1, columns A and B and the values are in Sheet2, column A.
dim listLength as integer 'number of values to look at
dim i as integer
dim dataLength as integer 'number of keywords
dim j as integer
dim keyword as string
dim value as string
listlength = Sheet2.Cells(Rows.Count, "A").End(xlUp).Row - 1 'assuming you start on row 2
datalength = Sheet1.Cells(Rows.Count, "A").End(xlUp).Row - 1 'assuming you start on row 2
for i = 2 to listLength + 1
value = Sheet2.Range("A")(i)
for j = 2 to dataLength + 1
keyword = Sheet1.Range("A")(j)
if instr(value, keyword) <> 0 then
' what happens when the keyword is present goes here
end if
next j
next i

Data/Time Formula Excel in VBA Program

I really have no idea if this is possible or not, but I'm trying to write an Excel program that uses the built-in date/time function to do a calculation and output it to a cell. It will use the downloaded date (located in column A), the last time of data entry (bottom row of B), and each independent data entry time (column B).
I want the formula in each cell to look like this::
A2 - Time(0,0,(B_Last - B_Current)/1000)
I'm assuming I will need it in some sort of loop.
My current code looks like this ::
Sub Bottom()
Dim Count As Integer
Dim i As Integer
Dim Last As Double
Set myRange = Columns("B:B")
Last = Cells(Rows.Count, "B").End(xlUp)
Set r1 = ThisWorkbook.Sheets("Sheet1").Range("A2")
Count = Application.WorksheetFunction.CountA(myRange)
For i = 1 To Count
Set r2 = ThisWorkbook.Sheets("Sheet1").Range("B" & i)
r2 = r1 - Time(0, 0, (Last - r2) / 1000)
Next
End Sub
Any help with this would be greatly appreciated!
Thanks!!
VBA has much more "in-built power" than Excel and thus you don't really need to rely on Excel formulae when using VBA. But if you want to do it anyway, you have to do something like this:
Range("B" & i).Value = "=Time(0, 0, (" & Last - r2 & ") / 1000)"
To get the value from the cell:
Dim cellVal As Date
cellVal = Range("B" & i).Value
You just have to make sure that the VBA variables and the strings written to the cells are treated separatedly (with " and &, as shown above) and that you store the value of the given cell in a variable of the right type (if you rely on string type it would work with any content).
Some correction in your code:
Sub Bottom()
Dim Count As Integer
Dim i As Integer
Dim Last As Double
Set myRange = Columns("B:B")
Last = 10 'What you want here??
Set r1 = ThisWorkbook.Sheets("Sheet1").Range("A2")
Dim r1Val As Long
r1Val = r1.Value
Count = Application.WorksheetFunction.CountA(myRange)
For i = 1 To Count
Set r2 = ThisWorkbook.Sheets("Sheet1").Range("B" & i)
r2.Value = "=" & r1Val & " - Time(0, 0," & CStr(Last) & "/ 1000)" 'r2 = r1 - Time(0, 0, (Last - r2) / 1000) -> r2 = ... Last - r2 does not make any sense; r2 is a whole date and Last - r2 refers to a part of a date
Next
End Sub
This is just a simple version of your code showing you some of things you shouldn't be doing: you are mixing up ranges with values, not considering different types, accounting for variables which I cannot even understand, etc.
Just take this code, analyse it carefully, understand what you have done wrong and keep adding functionalities step by step, by doing some research every time. The ideas are very simple:
You can set as many cells as you wish as a range.
A range can have different contents (got through range.Value); these contents are associated to a variable in VBA which has to have
the same type (string works for any content).
When you write to a cell, you write the whole text (if you put "=" ahead, Excel understand it as a formula).
When you read from a cell, you get the final value (the one from the formula, if applicable).
Etc.
I recommend you to do some research and get much more used to VBA than what you are right now.