VBA macro to subtract one variable number (dynamic) from a fixed number - excel

I am after a dynamic macro that subtracts numbers in C2 onwards from B2 onwards and puts them in D2 onwards.
Numbers in C2 onwards are fixed, although the user will put numbers in B2 onwards. The length of Column C (Hours Charged) changes dependent on the sheet that has been imported. The code is as follows:
Dim O As Long
O = Cells(Rows.Count, "C").End(xlUp).Row
Cells(O + 1, "C").Formula = "=SUM(C2:C" & O & ")"
Cells(O + 1, "C").Interior.Color = RGB(208, 247, 197)
Cells(O + 1, "C").Font.Bold = True
The sheet looks something like this (the first column is B, the last is D):
Hours Budgeted | Hours Charged | Variance
0 | 85 | 0
0 | 31 | 0
0 | 20 | 0
0 | 100 | 0
0 | 75 | 0
To summarise, when a user inputs a value in the Hours Budgeted (B) column, i want it to automatically subtract from the Hours Charged (C) column and display in the Variance (D) column.
The reason why this can't just be a '=C2-B2' is because I have a macro inputting all this data, as well as a separate macro that 'Resets' the sheet (removing all data and formulas).
Thanks all,
Jake.

The following code should do the trick, just add it after the code you posted.
For i = 2 To O
Cells(i, "D").FormulaR1C1 = "=RC[-1]-RC[-2]"
Next i
FormulaR1C1 lets you insert cells references that are relative to the cell you're putting the formula into, so R[2]C[3] would insert a reference to a cell three rows down and three columns to the right.

Related

Excel sum if meets condition

I currently have two columns that look like this:
value | condition
50 | Y
60 | N
30 | Y
10 | Y
I cant seem to make use of IF function to get a sum of all the rows. Basically the aim here is to only sum the values if condition is Y and display the total in a cell. And if condition column is N, it will see value as 0. I want to be able to do this without the need of creating an additional column even though I understand this is easily done with a brand new column.
as Nick mentioned, you can use Sumif:
A | B
1 value | condition
2 50 | Y
3 60 | N
4 30 | Y
5 10 | Y
sumif structure:
=sumif(Range, Criteria, Sum_Range)
sumif for table above:
=sumif(B2:B5,"Y",A2:A5)
Excel formulas are not case-sensitive and there is no difference between A1:A5 and A2:A5 because the table titles are not important but start row and end row is important in both Range and Sum_Range.

Retrieve the value of the column excel

I need your help, I would like to retrieve the value of the column where the cell contains 1 here is an example:
Image
A | B | C | D
1 | 0 | 0 |
0 | 1 | 1 |
1 | 1 | 0 |
The desired result:
A | B | C | D
1 | 0 | 0 | A
0 | 1 | 1 | B,C
1 | 1 | 0 | A,B
Thank you !
Here is a VBA approach that works for any number of columns:
Function SelectedColumns(R As Range) As String
Dim i As Long, n As Long, count As Long
Dim cols As Variant
n = R.Columns.count
ReDim cols(1 To n)
For i = 1 To n
If R.Cells(1, i).Value = 1 Then
count = count + 1
cols(count) = Split(R.Cells(1, i).Address, "$")(1)
End If
Next i
If count > 0 Then
ReDim Preserve cols(1 To count)
SelectedColumns = Join(cols, ",")
End If
End Function
Put the above code in a standard code module. The, in your example, if you enter =SelectedColumns(A1:C1) in cell D1 and copy down then it will work as expected.
Here is the TEXTJOIN formula that can be used in Office 365 Excel:
=TEXTJOIN(",",,IF(A1:C1=1,{"A","B","C"},""))
This is an array formula and must be confirmed with Ctrl-Shift-Enter instead if Enter When exiting edit mode.
For Earlier versions you can use an if for each and concatenate:
=MID(IF(A1=1,",A","") & IF(B1=1,",B","") & IF(C1=1,",C",""),2,100)
I am a little unclear of your formatting (how you want the answer etc), but perhaps this will help you out a bit.
I am assuming your headers are in cells A1 through C1, then your data in cells A2 through C4. Ane you want the data in Cells D2 to F4.
If you copy the following into cell D2 then use the drag function it will produce the result you are after.
=IF(A2=1,A$1,"")
Have a look at the screen capture where I have displayed the formulas then another with the result displayer.
Formulars Displayed
Just the results
Hope this helps --- Best of Luck !!!

How to copy and process data in the columns based on texts in the Header but header is not in first row

I am new to Excel and been told that I may find the solution in VBA.
I am working on a system generated report from which I need to remove few columns, but the report contains some important information in first 25 rows. After this information, we get 15 to 40 rows of actual report data (number of rows varies by centres).
I need to process this actual data by removing blank columns, sorting by A to Z, and then inserting the ‘Average’ in the last column.
Currently, I am copying actual report data, trim down unnecessary columns, make the necessary changes, applying VLOOKUP with last month’s report to verify opening and closing counts are matching or not (they almost always do, but why to take chances?) and then pasting it at the same location. Can it be done using VBA?
Format of report
> For the period 01-11-2011 to 30-11-2011
> *Parameter Selection List
>From 01-11-2011
>Date 30-11-2011
> Partner SAM
>Code TWO
>Location 999
>Report For All
>Code : TWO
>Location : ABC
Product Name |LastCount|AddedInPeriod |Left In The Period |Net Total | Average
SUPER GLUE |123456 |0 | 0 | 234567 |
CRICKET BAT |345678 |0 | 0 | 346899 |
NICON |2345 |0 | 0 | 2456 |
OLD STICKS |45689 |0 | 0 | 56778 |
Total |517168 |0 | 0 | 640700 |
Product Name is in Column B, Column C is blank, Last Count is in Column D, Header AddedInPeriod is mearged in Column D and F but data is in Column F, same is with Left In The Period(Header is merged inColumn G and H,but data is in column H), Col I is blank, Net Total is in J, Col K is blank and Average is in Col L
Data below the headers Product name, Last Counts and Net Total is necessary, rest of the range should be removed. (Please note, few cells are merged)
Final Report should look like this
For the period 01-11-2011 to 30-11-2011
*Parameter Selection List
From 01-11-2011
Date 30-11-2011
Partner SAM
Code TWO
Location 999
Report For All
Code :TWO
Location : ABC
Product Name|Last Count |Net Total|Average
CRICKET BAT |345678 |346899 |346288.5
NICON |2345 |2456 |2400.5
OLD STICKS |45689 |56778 |51233.5
SUPER GLUE |123456 |234567 |179011.5
**Total |517168 |640700 |578934**
How to do that?
Here is a function that will get the letter of the column with the header you suggest.
Function Letter(oSheet As Worksheet, name As String, Optional num As Integer)
If num = 0 Then num = 1
Letter = Application.Match(name, oSheet.rows(num), 0)
Letter = Split(Cells(, Letter).Address, "$")(1)
End Function
just create a new variable, and pass the header to the function, i.e.,
newvar = letter(sheets("Sheets1"), "SUPER GLUE", 4)
where the 4 is, where you indicate the row where the header can be found, in this instance I put row 4. Once you have the letter, then use
Sheets("Sheet2").Range(newvar & "4:" & newvar & Range("A1").End(xlDown).Row).Copy Destination:=Sheets("Sheet2").Range("A1")
This will take the information from the particular column, with the column header, and paste it into sheet2 A1

Only add cells in column when the total of multiple other cells in that row equals 5

So I am getting data fed into a spreadsheet on Google Sheets. I cannot edit that spreadsheet.
I have an additional sheet in the document that totals up the columns in this sheet. The sheet received info such as:
A B C D This info is not actually in the sheet
|------------| \/ \/
| 4 1 0 0 | <-- Valid
| 3 1 1 0 | <-- Valid
| 3 1 0 2 | <-- Invalid
| 3 0 1 1 | <-- Valid
|------------|
The total of each individual row should be 5, but I do not currently have a way of validating this in the form itself. So I need to disregard or remove the data if it is in violation.
So basically, I want to add all the values of column A together, but only of the rows in which the total of these 4 cells are exactly 5; No more, no less.
The furthest/closest I have gotten was using SUMIF, but the I need a single cell indicating whether or not the row totals up to 5, and as I said before, I cannot edit the cells in that specific sheet.
Try this:
=SUMPRODUCT((($A$1:$A$4+$B$1:$B$4+$C$1:$C$4+$D$1:$D$4)=5)*$A$1:$A$4)

Auto calculate average over varying number values row by row

I have an Excel file with several columns in it and many rows. One column, say A has ID numbers. Another column, say G has prices. Column A has repeating ID numbers, however not all numbers repeat the same amount of times. Sometimes just once, other times 2, 3 or several times. Each column G for that row has a unique price.
Basically, I need to average those prices for a given ID in column A. If each ID was repeated the same number of times, this would be quite simple, but because they are not I have to manually do my average calculation for each grouping. Since my spreadsheet has many many rows, this is taking forever.
Here is an example (column H is the average that I am currently calculating manually):
A ... G H
1 1234 3.00 3.50
2 1234 4.00
3 3456 2.25 3.98
4 3456 4.54
5 3456 5.15
11 8890 0.70 0.95
13 8890 1.20
...
So in the above example, the average price for ID# 1234 would be 3.50. Likewise, the average price for ID# 3456 would be 3.98 and for #8890 would be 0.95.
NOTICE how rows are missing between row 5 and 11, and row 12 is missing too? That is because they are filtered out for some other reason. I need to exclude those hidden rows from my calculations and only calculate the average for the rows visible.
Im trying to write a VBA script that will automatically calculate this, then print that average value for each ID in column H.
Here is some code I have considered:
Sub calcAvg()
Dim rng As Range
Set rng = Range("sheet1!A1:A200003")
For Each Val In rng
Count = 0
V = Val.Value '''V is set equal to the value within the range
If Val.Value = V Then
Sum = Sum + G.Value
V = rng.Offset(1, 0) '''go to next row
Count = Count + 1
Else
'''V = Val.Value '''set value in this cell equal to the value in the next cell down.
avg = Sum / Count
H = avg '''Column G gets the avg value.
End If
Next Val
End Sub
I know there are some problems with the above code. Im not too familiar with VBA. Also this would print the avg on the same line everytime. Im not sure how to iterate the entire row.
This seems overly complicated. Its a simple problem in theory, but the missing rows and differing number of ID# repetitions makes it more complex.
If this can be done in an Excel function, that would be even better.
Any thoughts or suggestions would be greatly appreciated. thanks.
If you can add another row to the top of your data (put column Headers in it) its quite simple with a formula.
Formula for C2 is
=IF(A2<>A1,AVERAGEIFS(B:B,A:A,A2),"")
copy this down for all data rows.
This applies for Excel 2007 or later. If using Excel 2003 or earlier, use AVERAGEIF instead, adjusting ranges accordingly
If you can't add a header row, change the first formula (cell C1) to
=AVERAGEIFS(B:B,A:A,A1)
In my way ..
Sub calcAvg()
Dim x, y, i, y2, t, Count, Mount As Integer
Dim Seek0 As String
x = 1 '--> means Col A
y = 1 '--> means start - Row 1
y2 = 7 '--> means end - Row 19
For i = y To y2
If i = y Then
Seek0 = Cells(i, x)
t = i
Count = Cells(i, x + 6)
Mount = 1
Else
If Cells(i, x) <> Seek0 Then
Cells(t, x + 7) = Count / Mount
Count = Cells(i, x + 6)
Mount = 1
t = i
Seek0 = Cells(i, x)
Else
Count = Count + Cells(i, x + 6)
Mount = Mount + 1
End If
End If
Next
End Sub
Hope this helps ..

Resources