Excel formula in VBA code - excel

So, in Sheet1 I have base of some names and it looks like this:
In Sheet2 I'm working with these names from Sheet1. I'm doing that in a way that I'm entering Code value in column A and in column B I get the Name, in column C I get the Last Name. That looks like this:
I've done this with formulas, entering it in the formula bar. For column A(or Name) I've used this formula: =IFERROR(VLOOKUP(A2;Sheet1!A:C;2;FALSE);"") and for column B(or Last Name) I've used this one: =IFERROR(VLOOKUP(A2;Sheet1!A:C;3;FALSE);""). I've dragged these formulas to row 20 and it works great.
Now, what I'd like to do is to put these formulas into Excel VBA code and them to work for noted range. I've just started to use VBA and I don't know how to do it in it, tried something but doesn't work, ..., I've done this so far. I'm new to this Excel/Macro/VBA thing so any help would be appreciated.

The below code will work if you type in your Code values in sheet2 and highlight them, and run this macro:
Selection.Offset(0, 1).FormulaR1C1 = "=IFERROR(VLOOKUP(RC[-1],Sheet1!C[-1]:C,2,FALSE),"""")"
Selection.Offset(0, 2).FormulaR1C1 = "=IFERROR(VLOOKUP(RC[-2],Sheet1!C[-2]:C,3,FALSE),"""")"
Selection.Offset(0, 1).Value = Selection.Offset(0, 1).Value
Selection.Offset(0, 2).Value = Selection.Offset(0, 2).Value
Edit: If you are wanting to update values as you type use (thank you #PeterAlbert for added optimisation!):
Private Sub Worksheet_Change(ByVal Target As Range)
'end if the user made a change to more than one cell at once?
If Target.Count > 1 Then End
'stop system activating worksheet_change event while changing the sheet
Application.EnableEvents = False
'continue if column 1(A) was updated
'and
'dont continue if header or row 1 was changed
If Target.Column = 1 And Target.Row <> 1 Then
With Target.Offset(0, 1) 'alter the next cell, current column +1 (column B)
'RC1 = current row and column 1(A) e.g. if A2 was edited, RC1 = $B2
'C1:C2 = $A:$B
.FormulaR1C1 = "=IFERROR(VLOOKUP(RC1,Sheet1!C1:C2,2,FALSE),"""")"
.Value = .Value 'store value
End With
With Target.Offset(0, 2) 'alter the next cell, current column +2 (column C)
'C1:C3 = $A:$C
.FormulaR1C1 = "=IFERROR(VLOOKUP(RC1,Sheet1!C1:C3,3,FALSE),"""")"
.Value = .Value 'store value
End With
End If
Application.EnableEvents = True 'reset system events
End Sub
Explinatioin of RC:
The FormulaR1C1 formula types are good to use when referencing a cell with respect to the current cell. There a few rules to remember:
The R stands for Row and C is for Column and the integer after it, if any, defines the row or column;
As a basis the RC formula references itself;
Any number following the R or C wraped in [] is an offset to itself, e.g. if you are in cell A1 and use R[1]C[1] you would be referencing cell B2;
Also any number following the R and C is an exact, e.g. if you reference R2C2 no matter the cell you are in would also point to B2; and
To complicate things if you were in cell C5, e.g. using Range("C5").FormulaR1C1 = and coded the follwing:
"=RC[-1]" references cell B5
"=RC1" references cell A5, more rightly $A5
"=R[1]C[-2]" references cell A6
"=Sum(C[-1]:C5)" is =Sum(B:E), more rightly =Sum(B:$E)

If I understand your question and comments correctly, you want to ensure that columns B&C always show you the right values based on your formula, but also want to protect (and maybe even hide the formula) from the users.
I'd suggest you use sheet protection instead: all you need to do is to unlock the cells you want the users to edit, i.e. select column A and in the _ Format cells_ dialog uncheck "Locked" in the Protection tab. Similarly for columns B&C, check "Hidden". Now right click the sheet name and select Protect Sheet. Once this is done, the user can edit column A - but will not see the formula in B&C and cannot edit those cells.
If for some reasons you need to ensure this in VBA, use the following code:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False 'to prevent endless loop
With Target.Offset(, 2 - Target.Column).Resize(, 2)
.FormulaR1C1 = "=IFERROR(VLOOKUP(RC1,Sheet1!C1:C3,COLUMN(RC),0),"""")"
.Value = .Value
End With
Application.EnableEvents = True
End Sub
You need to place this in the module of the worksheet.

Related

Add value entered in cell to another cell in the same column

I want to add the value entered in a cell in a certain row to another cell in that same column
Example:
If I enter a value in cell B12, add that value to the value in B17.
If I enter a value in cell D12, add that value to the value in D17 and so on.
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If Target.Row = 12 Then
Range(Target.Column & 17).Value = Range(Target.Column & 17).Value + Target.Value
End If
Application.EnableEvents = True
End Sub
Problem is, that Target.Column is a integer and not a Character. So the Code will not run, since Range expects a char as column and not an integer (at least that is what I think the debugger wants to tell me).
Greetings,
Maverick
The presumption that Column must be a letter is mistaken. To the contrary, Column is a number which, for users' convenience (not Excel's) is displayed as a letter in some usages. Therefore this code will work.
Private Sub Worksheet_Change(ByVal Target As Range)
With Target
If .Row = 12 Then
Application.EnableEvents = False
Cells(17, .Column).Value = .Value
Application.EnableEvents = True
End If
End With
End Sub
A rule you might go by is to address individual cells using the syntax for addressing cells, which is Cells([Row], [Column]) and use range names only when addressing ranges comprising more than one cell. For this rule you need to understand that ...
When addressing cells, you can use their number or designation. Cells(3, 2) may also be written as Cells(3, "B") but the letter is more complicated and can't be used in calculations.
All ranges have names. But in the absence of a given name VBA will concatenate a name from its first and last cells, like Range("A1:D4"). You can further complicate this concatenation by interjecting other numbers into the name creation (such as you tried).
VBA defines a range by its first and last cells. Therefore VBA's preferred way to address Range("A1:D4") is Range(Cells(1, 1), Cells(4, 4)). That looks effusive but if you are in a position where you have to calculate any of the coordinates you will find that it's the simplest method.

Change colour of selected cell using values in cells based off the selected cell

I have a macro to colour a cell based on the RGB values.
I have cells A1, B1, and C1 for the RGB values.
Sub FillWithRBG()
Range("D1").Interior.Color = RGB(Range("A1").Value, Range("B1").Value, Range("C1").Value)
End Sub
I can select anywhere in the worksheet, run the macro and only cell D1 will change colour.
I want to select cell D2, run the macro and Cell D2 changes colour based off values in A2, B2, and C2.
I imagine I need to set the active cell with a reference, then 1, 2 and 3 will be offset from the selected cell.
An added bonus would be that the macro can only run in the D column to prevent errors.
This would be a simple approach
In the code Me. is refering to the current sheet
You have to place this code in the sheet's module
Columns in VBA are noted by numbers (so column A is referenced as column 1)
Code:
Private Sub Worksheet_Change(ByVal Target As Range)
' Prevent change if changed values are no in these columns (1,2,3) numbers are equivalent to A, B, C
If Target.Column > 3 Then Exit Sub
' Change color of D column (4 = D)
Me.Cells(Target.Row, 4).Interior.Color = RGB(Me.Cells(Target.Row, 1).Value, Me.Cells(Target.Row, 2).Value, Me.Cells(Target.Row, 3).Value)
End Sub
If you want it to work only if you're changing one cell at a time add these lines:
' Prevent change when more than one cell is changed
If Target.Cells.Count > 1 Then Exit Sub

VBA Conditional Formatting with changable conditions

I am trying to set conditional formatting in 18 cells in third column ("C"). I have merged each 6 cells in first column ("A"), and unmerged (normal) cells in second column ("B"). I am trying to check for each next cell in row of column "C" if there is a "yes" in first row of column "A" or whether there is a "no" in "A" column and "pass" in "B" column. The trick is, I want to check only first row of "A" column, seventh, thirteenth and nineteenth (so with the step = 6) and check every row in "B" column. I try something like this:
Sub try()
Dim i As Integer
Dim j As Integer
i = 1
For j = 1 To 12
With Range("C1:C18")
.FormatConditions.Delete
.FormatConditions.Add Type:=xlExpression, Formula1:="=OR(Cells(i, 1) = ""Yes""; AND(Cells(i, 1) = ""No""; Cells(j, 2) = ""Pass""))"
End With
If j Mod 6 = 0 Then
i = i + 6
Next j
End Sub
But it does not work like that, I saw examples with specific Cells like "A1" or "A3" but I want a number to increase with every loop (so I tried it with Cells(row,column)).
You can do it in one statement on the whole range by using relative addresses, so what applies to C1 relatively to A1 and B1 will follow automatically in the subsequent rows of the range.
The only trick is to retrieve the value in column A, since this value is only available in cells A1, A7, etc. This is achieved by the expression OFFSET(A1,-MOD(ROW(C1)-1,6),0).
Sub doIt()
With Sheet1.Range("C1:C30").FormatConditions
.Delete
.Add(xlExpression, , _
"=OR(OFFSET(A1,-MOD(ROW(C1)-1,6),0)=""yes"",AND(OFFSET(A1,-MOD(ROW(A1)-1,6),0)=""no"",B1=""pass""))") _
.Interior.ColorIndex = 6
End With
End Sub
You can also do it from the GUI using the same formula; select cell C1 then select the whole range C1:C30, and click
Conditional Fomatting -> New rule -> Use a formula... and enter the same formula.
BTW, the expression can be further simplified if you dont care to check for "no", meaning if column A is assured to be either "yes" or "no".

SUMIF returning zero

Here are snippets of two worksheets
This is the code that I have on the first sheet meant for change in selection of the dropdown. There will be more Cases, but my issue is with the SUMIF. Anytime column B on Sheet2 matches the corresponding column A item on Sheet2, sum column C on Sheet2.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("D1")) Is Nothing Then
Select Case Range("D1")
Case "2014-2015": Cells(2, "B") = WorksheetFunction.SumIf(Worksheets("2014-2015").Range("B2:B22"), A2, Worksheets("2014-2015").Range("C2:C22"))
Case Else: Cells(2, "B") = 8
End Select
End If
End Sub
The problem is that it is always returning 0. Hoping for help as to an edit to the code to make it display the proper total.
Thanks,
It looks like the problem is with the value it is trying to match, specified only as A2 in your Sumif formula. It isn't recognizing that you want to match the value in cell A2. It would need to be referenced with something similar to Worksheets("SummarySheet").Range("A2").Value like you did for the other parameters of that function.

VBA - Enter a formula into all active rows of the current column (when you don't know the column letter, or if the column changes)

Hi guys this is my first post, I'm wondering if you can possibly assist me.
I'd like to write a macro / script that will allow me to put a formula into the column to the right of the currently selected one (for all active rows of the current column) based on what column I've selected. The issue I'm having is that I don't always know the current column letter (as my selection changes from worksheet to worksheet).
To give you an example:
One of my columns currently contains dates, that dates are entered in different formats though, some are separated with ".", some with "-", some with spaces and so on. I have a formula that will deal with this so I need to put this formula in the column to the right of the selected column (which has the dates).
I have been able to do this when I specify the column letter, but not if it changes.
Please can you help?
Give this a go,
Sub SomethingNeat()
Dim rng As Range, x
x = Selection.Column
On Error Resume Next
Set rng = Columns(x).SpecialCells(xlCellTypeConstants, 23)
If Not rng Is Nothing Then rng.Offset(, 1) = "'=MyFormula"
End Sub
You can use ActiveCell.Offset(0,1).Value = Variable
That means that whetever your current cell is you can move and "select" to put a value to the right cell of the one you have activated. You can move the selection using a loop.
Do
Workbooks("Yur workbook name").Worksheets(1).Range(Adress you want to start adding).Offset(0, 1).formula = "=FORMULA"
i = i + 1
ActiveCell.Offset(1, 0).Activate
Loop While i <= max_row
Edit: 2nd
Put the formula in a cell lets say C1
'Select a range
Set take = Worksheets(1).Range("C1")
take.Copy 'copy the formula
Worksheets(1).Paste Destination:=Worksheets(1).Range("B1:B10")
That will copy your function whenever you want it to

Resources