Excel Summing over Rows with for loop - Type mismatch error - vba

so I am currently working on an Excel sheet where I have to calculate confidence intervals. Long story short, I think the only way I can do this automatically, is to write vba code. The first step would be to calculate the average of the cells in a column for several columns in the sheet. What I did:
Dim temp As Double
temp = 0
Dim it_row As Long
for it_row = 1 to 100
if IsBlank(Sheet.Cells(it_row,it_col)) then
temp = temp + 0
else
temp = temp + Sheet.Cells(it_row,it_col).Value
end if
next it_row
Dim Average As Double
Average = temp/100
'writing average in another cell
This code does not work, as the compiler returns Type missmatch, error code 13
in the line
temp = temp + Sheet.Cells(it_row,it_col).Value
I tried to do a CDouble(Sheet.Cells(it_row,it_col).Value) but that did not work.
Any help is appreciated, as I am quite desperate because googling did not really help me.
I should mention that I do have to use vba and this code because this is part of a bigger automated process and my supervisor said I must use vba for automation in the next step.

The Average and Sum Excel Functions ignore text, boolean, and empty values:
Average = Application.Average(Sheet.Cells(1, it_col).Resize(100))

Check
Sheet.Cells(it_row,it_col).Value
...with
if isnumeric(Sheet.Cells(it_row,it_col).Value)
...before adding it to a double type value. If that check fails, then you can chose to skip it or treat it as sth. else.
I would've added this as a comment, but I don't have enough rep. to add comments.

Related

Nested for loop with three variables - order of execution clarity - Appending all variable combinations

I am working with a file which includes an automated calculation for given inputs. Using [Sub:Other_Sub_Calc].
The aim of this code is to get all combinations of the 3 different variables (listed in 'sheet4' columns a:c) along with the corresponding result [Cell: b61]copied on to a separate sheet(rather than running each combination individually).
The code seems to work with just the two variables in places but I've messed up somewhere adding the third.
I'm sorry for my very bad vba knowledge, I'd imagine someone with better knowledge may be able to spot my mistake in this simple code relatively quickly.
Thank you in advance if anyone can help.
Sub Expected_results()
Dim age, town, studylength As Range
Dim lastrow As Integer
'Variables
Set age = Sheets("Sheet4").Range("a2:a5")
Set town = Sheets("Sheet4").Range("b2:b6")
Set studylength = Sheets("Sheet4").Range("c2:c6")
For Each Year In age
Sheets("Summary").Range("B28").Value = volume
For Each Location In town
Sheets("Summary").Range("B34").Value = Ratio
For Each duration In studylength
Sheets("Summary").Range("B29").Value = Ratio
Other_Sub_Calc 'Example Sub to be ran for each combination of variables
'copy and append each generated result
Worksheets("Summary").Range("b61").Copy
Worksheets("Sheet5").Range("d2" & lastrow + 1).PasteSpecial
Next age
Next Location
Next duration
End Sub

How can I add values from table 1 to values in the cells of table 2 and display the result in table 2 after?

I am looking at somewhat of a problem when trying to program a macro in Excel that is meant to add the number values from 2 tables and display the updated total in the second of the two.
I have just started learning how to program macros, so my knowledge is a little basic, but I am sure that there has to be a way to set this up in a more convenient way than what I am doing right now.
I have two tables, table 1 contains the data of the current week, which is entered manually, while table 2 is supposed to contain the total, which is calculated when clicking the macro button "Add".
I was able to fully set this up myself, using very basic code, which is why I am asking for help. At the moment the macro code is very messy and absolutely massive, I am looking at 242 declared variable values and a total of 925 lines of code.
The below is simplified and shortened, but basically how everything is working right now:
Each table contains up to 11 columns of data, with 11 rows each, so the macro is adding cells B2 to L12 to cells B29 to L39. The results are then being displayed as the total in cells B29 to L39.
The code right now:
Sub Add()
Dim Add As Integer
Dim var1 As Integer
Dim var2 As Integer
var1 = Range("B2").Value
var12 = Range("B29").Value
Add = var1 + var12
Range("B29").Select
ActiveCell.FormulaR1C1 = Add
Like I said, this does work and does exactly what I need, but this involves a lot of code and a huge potential for mistakes, as well as hours of writing it all out. Doesn't look very good either, and is even harder to follow/work through.
Can anybody help me streamline this, make it shorter? Is there any option to sum the whole thing up in fewer lines of code, fewer arguments?
Thanks in advance for any help.
UPDATE:
As mentioned before, the code I currently have does work as intended, but I would like to cut it down volume wise. There's just too much of it and I know it is possible to do the exact same with a lot less, I just don't know how.
I have structured the code to make it a little easier to read, the first section declaring the variables, the next chunk declaring the values (separated into blocks per row in the table) and lastly the calculating action of adding table A to table B and displaying the result in table B (again, separated into blocks per row in the table).
Thank again everyone for your help.
This is the complete code currently written
Try this out:
Dim cell as Range
For each cell in Range("B29:L39")
cell.Value = cell + cell.offset(-27).Value
Next
you could use PasteSpecial() method with xlPasteSpecialOperationAdd value for its Operation parameter
Range("B2:L12").Copy
Range("B29:L39").PasteSpecial Operation:=xlPasteSpecialOperationAdd
Application.CutCopyMode = False
or you could use arrays
Dim i As Long, j As Long
Dim var1 As Variant, var2 As Variant
var1 = Range("B2:L12").Value
var2 = Range("B29:L39").Value
For i = 1 To UBound(var1, 1)
For j = 1 To UBound(var1, 2)
var2(i, j) = var2(i, j) + var1(i, j)
Next
Next
Range("B29:L39").Value = var2

vba - Macro producing incorrect results when run, but when stepping into results are correct

I have a macro that inserts a VLOOKUP into a column. The macro has to take a number stored as text and convert it to a number, before looking up that number in another sheet.
The macro always produces the same results, such as reaching row 43 before starting to produce erroneous results however when using F8 to step through the code, these incorrect results are not produced.
The erroneous results are that the value placed into col 13 is not equal to the number stored as text. Mostly it seems as though values from rows above and below, sometimes 2 rows below are being inserted to col 13. Almost seems to me as if 2 different threads are running at 2 different speeds or something?
If anyone could have a look at the loop causing the errors I would be grateful, thanks.
For counter = 2 To NumRowsList
checker = CInt(Sheets("Sheet2").Cells(counter, 3)
Sheets("Sheet2").Cells(counter, 13).Value = checker
'Call WaitFor(0.5)
If checker < 4000 Then
Sheets("Sheet2").Cells(counter, 14) = "=VLOOKUP(M" & counter & ",Sheet4!E2:F126,2,FALSE)"
Else
Sheets("Sheet2").Cells(counter, 14) = "=VLOOKUP(M" & counter & ",Sheet5!B2:C200,2,FALSE)"
End If
Next counter
I have tried a few similar variations of this code, such as using the value stored in col 13 directly rather than using the cell reference in the VLOOKUP, always producing the same results.
I even used the waitfor function to try and create a delay hoping it may synchronise the operations, but it did not help and using a delay of more than 0.5 would cause the run time of the macro to be too big.
UPDATE:
I did not find a perfect solution, only a long hand work around. I simply combined the Vlookups onto a single sheet, and converted the numbers stored as text to numbers outside of the vba routine. This took the error away from the number calculation (just col C * 1), and then the vlookups were looking up the correct values. Thank you for the help, regardless.
you can avoid looping, checker and all those If-Then-Else, like follows
edited to account for VlookUp range depending on VlookUp value
With Worksheets("Sheet2")
.Range("N2", .Cells(NumRowsList, 14)).FormulaR1C1 = "=VLOOKUP(Value(RC3),IF(Value(RC3)<4000,Sheet4!R2C5:R126C6,Sheet4!R2C2:R200C3),2,FALSE)"
End With
The following works for me with my test data, but you'll need to see if it works for you... (also are you turning off calculation or events? I don't know if this might have an issue?)
I find it preferable to set a reference to the sheet you want to use rather than access it directly, and this may help?
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet2")
Dim VLURange As String, checker As Long
For counter = 2 To 200 ' NumRowsList
checker = CLng(ws.Cells(counter, 3).Value)
ws.Cells(counter, 13) = checker
VLURange = IIf(checker < 4000, "Sheet4!E2:F126", "Sheet5!B2:C200")
ws.Cells(counter, 14) = "=VLOOKUP(M" & counter & ", " & VLURange & ", 2, FALSE)"
Next counter

VBA Macro: Trying to code "if two cells are the same, then nothing, else shift rows down"

My Goal: To get all data about the same subject from multiple reports (already in the same spreadsheet) in the same row.
Rambling Backstory: Every month I get a new datadump Excel spreadsheet with several reports of variable lengths side-by-side (across columns). Most of these reports have overlapping subjects, but not entirely. Fortunately, when they are talking about the same subject, it is noted by a number. This number tag is always the first column at the beginning of each report. However, because of the variable lengths of reports, the same subjects are not in the same rows. The columns with the numbers never shift (report1's numbers are always column A, report2's are always column G, etc) and numbers are always in ascending order.
My Goal Solution: Since the columns with the ascending numbers do not change, I've been trying to write VBA code for a Macro that compares (for example) the number of the active datarow with from column A with Column G. If the number is the same, do nothing, else move all the data in that row (and under it) from columns G:J down a line. Then move on to the next datarow.
I've tried: I've written several "For Each"s and a few loops with DataRow + 1 to and calling what I thought would make the comparisons, but they've all failed miserably. I can't tell if I'm just getting the syntax wrong or its a faulty concept. Also, none of my searches have turned up this problem or even parts of it I can maraud and cobble together. Although that may be more of a reflection of my googling skill :)
Any and all help would be appreciated!
Note: In case it's important, the columns have headers. I've just been using DataRow = Found.Row + 1 to circumvent. Additionally, I'm very new at this and self-taught, so please feel free to explain in great detail
I think I understand your objective and this should work. It doesn't use any of the methodology you were using as reading your explanation I had a good idea how to proceed. If it isn't what you are looking for my apologies.
It starts at a predefined column (see FIRST_ROW constant) and goes row by row comparing the two cells (MAIN_COLUMN & CHILD_COLUMN). If MAIN_COLUMN < CHILD_COLUMN it pushes everything between SHIFT_START & SHIFT_END down one row. It continues until it hits an empty row.
Sub AlignData()
Const FIRST_ROW As Long = 2 ' So you can skip a header row, or multiple rows
Const MAIN_COLUMN As Long = 1 ' this is your primary ID field
Const CHILD_COLUMN As Long = 7 ' this is your alternate ID field (the one we want to push down)
Const SHIFT_START As String = "G" ' the first column to push
Const SHIFT_END As String = "O" ' the last column to push
Dim row As Long
row = FIRST_ROW
Dim xs As Worksheet
Set xs = ActiveSheet
Dim im_done As Boolean
im_done = False
Do Until im_done
If WorksheetFunction.CountA(xs.Rows(row)) = 0 Then
im_done = True
Else
If xs.Cells(row, MAIN_COLUMN).Value < xs.Cells(row, CHILD_COLUMN).Value Then
xs.Range(Cells(row, SHIFT_START), Cells(row, SHIFT_END)).Insert Shift:=xlDown
Debug.Print "Pushed row: " & row & " down!"
End If
row = row + 1
End If
Loop
End Sub
I modified the code to work as a macro. You should be able to create it right from the macro dialog and run it from there also. Just paste the code right in and make sure the Sub and End Sub lines don't get duplicated. It no longer accepts a worksheet name but instead runs against the currently active worksheet.

Macro to run through 3 conditions and provide value

This is my first time using VBA for Excel (I usually code Java and C++), and I was hoping to get some tips to start out.
I want to write a macro for a large data set that will proceed through the following list of conditions to provide a dollar result:
Collect unit size from column A (Possible values 0-8)
Determine whether single or family unit from Column B (Single- 1, Family- 0)
Collect utility code from Column C (code for type of product being assessed)
From this information, a new value will be placed in the row which determines utility costs by taking into account unit size, type of unit, and the product in question. I have thought about using nested Select Case or nested conditionals in a loop, but overall I am pretty lost.
It seems like a worksheet formula might do the trick, but it's hard to tell without knowing what the calculation is. Below is a user-defined function (UDF) that you would put in a standard module. You would call it from a cell like:
=computecosts(A2,B2,C2)
Obviously the code would change depending on how your data is laid out and what your calculation is.
Public Function ComputeCosts(rSize As Range, rFamily As Range, rCode As Range) As Double
Dim lSizeFactor As Long
Dim lFamilyFactor As Long
Dim dCodeFactor As Double
Dim rFound As Range
Const lFAMILY As Long = 0
'Size factor is a function of 0-8, namely adding 1
lSizeFactor = rSize.Value + 1
'Family factor is computed in code
If rFamily.Value = lFAMILY Then
lFamilyFactor = 3
Else
lFamilyFactor = 2
End If
'Code factor is looked up in a different sheet
Set rFound = Worksheets("Sheet2").Columns(1).Cells.Find(rCode.Value, , xlValues, xlWhole)
If Not rFound Is Nothing Then
dCodeFactor = rFound.Offset(0, 1).Value
End If
'do the math
ComputeCosts = lSizeFactor * lFamilyFactor * dCodeFactor
End Function
Thanks for the responses, they were helpful in understanding VBA for Excel. I just ended up putting possible values in a table and then using Match functions within an Index function to pick out the right value.