Putting R1C1 formula on variable rows to reference the same column - excel

I need help to write a code which puts an R1C1 formula into a row’s cells.
The start position of the row’s will vary each time the macro is run.
Ie. If the macro is run the first time, the formula will be entered into Row B16 as R[-5]C[3]. R[-5] in the case is E12.
However, when the macro is run another time, & its entered into row B25, I still want it to reference to E3, but it references to E20.
Here is my code
Dim cell As Range, MyRange As Range
Set MyRange = Range("B1:B5000")
For Each cell In MyRange
If cell = " " And cell.Offset(, 1) <> "Record" Then
cell.FormulaR1C1 = "=SUM(R[-5]C[3]: SUM(R[-5]C[4])"
End If
Next cell
End With
You are right, my code was trying to say This row - 5, this column + 3: this row -5, this column + 4
The problem I have is that This row could be any row & I would like to use relative referencing as this formula copies down to the next row
So what I’m trying to do is this
Cell B16 = E11+F11
Cell B17 = E12+F12
Cell B18 = E13+F13 etc
Then when the macro is run again & start cell is E25, then
Cell E25 = E20+F20
Cell E26 = E21+F21
Cell E26= E22+F22 etc
So, regardless of which cell the macro points to, it will always start the calculation from E11+F11

Here is my code
Dim cell As Range, MyRange As Range
Set MyRange = Range("B1:B5000")
For Each cell In MyRange
If cell = " " And cell.Offset(, 1) <> "Record" Then
cell.FormulaR1C1 = "=SUM(R[-5]C[3]: SUM(R[-5]C[4])"
End If
Next cell
End With

You're using relative references in your formula, and the formula won't work as you're trying to say =SUM(E1:SUM(F1) if the entered in cell B6. Any rows higher than that and it will try and reference off the sheet.
To use absolute referencing use R3C5 (row 3, column 5 = E3).
At best your formula was trying to say This row - 5, this column + 3: this row -5, this column + 4
Maybe try "=SUM(R3C5:R3C4)" which is the same as =SUM($E$3:$F$3).
Also - cell = " " - the cell must contain a single space? Should it be cell = ""?
Edit:
In response to your edit - if you want the first formula to always look at E11:F11, and the next to be E12:F12, etc you can use one of these solutions:
To add the formula to all rows in one hit - this doesn't check for a cell with a space:
Public Sub Test()
Dim MyRange As Range
Dim lOffset As Long
Set MyRange = Range("B1:B5000")
With MyRange
lOffset = 11 - .Row
.FormulaR1C1 = "=IF(RC[1]<>""Record"",SUM(R[" & lOffset & "]C5:R[" & lOffset & "]C6),"""")"
End With
End Sub
To check that each cell has a space in it before adding the formula:
Public Sub Test1()
Dim MyRange As Range
Dim rCell As Range
Dim lOffset As Long
Set MyRange = Range("B30:B5000")
lOffset = 11 - MyRange.Row
For Each rCell In MyRange
If rCell = " " And rCell.Offset(, 1) <> "Record" Then
rCell.FormulaR1C1 = "=SUM(R[" & lOffset & "]C5:R[" & lOffset & "]C6)"
End If
Next rCell
End Sub
Here's the results for the second code block showing the formula always starts in row 11:
And if you change the range the formula goes in:
Edit 2:
If rows 20:24 have Record then this will place =SUM($E11:$F11) in row 25. If row 26 has a record then row 27 will have =SUM($E12:$F12)
Public Sub Test1()
Dim MyRange As Range
Dim rCell As Range
Dim lOffset As Long
Set MyRange = Range("B20:B30")
lOffset = 11
For Each rCell In MyRange
If rCell = " " And rCell.Offset(, 1) <> "Record" Then
rCell.FormulaR1C1 = "=SUM(R[" & lOffset - rCell.Row & "]C5:R[" & lOffset - rCell.Row & "]C6)"
lOffset = lOffset + 1
End If
Next rCell
End Sub

Related

VBA isEmpty() - Check if cells are empty and tell me which ones

Apologies if this has been answered already, I did search and can't seem to find an answer:
How could I change the code below to check for empty cells across two sheets and not in a continuous range and to tell me which cells are blank.
The range will be sheet "Request" Range, B5,B6,B7,b10,b11 & sheet "Data" Range A8, B8, D8,
Is it possible for the code to tell me the adjacent Cell name so can find it and put a value in, for example B5, A5 is called "request name" so I'd need to highlight to the user request name is blank for them to go and put a value and so on for the other cells.
Sub check_empty()
Dim i As Long
Dim c As Long
Dim myRange As Range
Dim myCell As Range
Set myRange = Sheets("Request").Range("B5:B8")
For Each myCell In myRange
c = c + 1
If IsEmpty(myCell) Then
i = i + 1
End If
Next myCell
MsgBox _
"There are total " & i & " empty cell(s) out of " & c & "."
End Sub
Is it correct the range for sheet "Data"?
Cause Range A8 won't have a named range adjacent to it, and B8 would have A8 as its named range... anyway, here's what I came up with:
Sub check_empty()
Dim c As Integer
Dim i As Integer
Dim sReport As String
Dim rResults() As String
c = 0
i = 0
Call loop_check_empty("Request", "B5:B7,B10:B11", rResults, c, i)
Call loop_check_empty("Data", "A8,B8,D8", rResults, c, i)
sReport = Join(rResults, vbCr)
MsgBox "There are total " & i & " empty cell(s) out of " & c & "." & vbCr & sReport
End Sub
Sub loop_check_empty(ByVal sSheet As String, ByVal sRange As String, ByRef rResults() As String, ByRef c As Integer, ByRef i As Integer)
Dim myCell, myRange As Range
Dim sColumn, sRow As String
Set myRange = Sheets(sSheet).Range(sRange)
For Each myCell In myRange
c = c + 1
If IsEmpty(myCell) Then
i = i + 1
ReDim Preserve rResults(1 To i)
sColumn = Mid(myCell.Address, 2, 1)
sRow = Mid(myCell.Address, 4, Len(myCell.Address))
Sheets(sSheet).Range(sColumn & sRow).Interior.Color = vbRed
If sColumn = "A" Then
rResults(i) = sColumn & sRow
Else
rResults(i) = sColumn & sRow & " for "
sColumn = Chr(Asc(sColumn) - 1)
rResults(i) = rResults(i) & Sheets(sSheet).Range(sColumn & sRow).Name.Name
End If
End If
Next myCell
End Sub
Assuming the ranges A5, A6, A7, A10 and A11, in sheet "Request" are named ranges.
And ranges A8 and C8 in sheet "Data".
The code will turn sheet "Request" Range, B5,B6,B7,b10,b11 & sheet "Data" Range A8, B8, D8 all into red, so the user will know where to enter data.
And the msgbox will report the empty ranges, as well as the named range adjacent to it.

VLOOKUP from another sheet, apply formula every nth row

I'm working on the below formula to Vlookup data from another sheet. The formula must be placed on the 14th column, and every 7 rows, vlookuping the first column value.
Sub test3()
'Vlookuping on Column N
Dim lastRow As Long
lastRow = Cells(Rows.Count, 14).End(xlUp).Row 'Checks last row with data
Dim cel As Range, rng As Range
Dim sheetName, lookupFrom, myRange 'variables
sheetName = "Plan2" 'the worksheet i want to get data from
lookupFrom = ActiveCell.Offset(0, -14).Address '
myRange = "'" & sheetName & "'!1:1048576"
For i = 3 To lastRow Step 7 '
Cells(i, 14).Select 'i= first value; step= lines to jump
ActiveCell.Formula = "=VLOOKUP(" & lookupFrom & ";" & myRange & "; 14; FALSE)"
Next i
End Sub
Example Sheet
I want to place the formula on the pink cells (column N), vlookuping the pink value from the first cell on another worksheet. My actual formula isn't even executing.
Try the code below, with 2 exceptions:
1.Modify "VlookRes" to your Sheet name - where you want to results to be.
2.You have Merged Cells in Column A (according to your image uploaded), you are merging Rows 2 untill 6 in column A, this means that the value of Cell A3 will be 0. If you want the values to read from the third row, start the merging from row 3 (and soon for the next values in Column A).
Option Explicit
Sub test3()
'Vlookuping on Column N
Dim ShtPlan As Worksheet
Dim ActSht As Worksheet
Dim lastRow As Long
Dim sheetName As String
Dim lookupFrom As String
Dim myRange As String
Dim i As Long
' modify this Sheet Name to your sheet name (where you want to keep your results)
Set ActSht = Sheets("VlookRes")
lastRow = ActSht.Cells(ActSht.Rows.Count, 14).End(xlUp).Row ' Checks last row with data
sheetName = "Plan2" 'the worksheet i want to get data from
Set ShtPlan = Sheets(sheetName)
myRange = "'" & sheetName & "'!1:1048576"
For i = 3 To lastRow Step 7
lookupFrom = ActSht.Cells(i, 1).Address ' ActiveCell.Offset(0, -14).Address '
Cells(i, 14).Formula = "=VLOOKUP(" & lookupFrom & "," & myRange & ", 14, FALSE)"
Next i
End Sub

Applying a different formula every nth row

So i have this sheet where i'd like to apply a formula every 7th row. But it can't be the same formula, it needs to "offset" the formula as well.
For example, for the first range the formula would be "=(C4+C5)-C3"; for the second range, "=(C11+C12) - C10"; and so on.
This is what i have so far:
Sub ApplyFormula()
ApplyCF Range("C6")
ApplyCF Range("C13")
'and so on, every 7 rows
'is there any other way i can apply these ranges instead of typing them?
'with an offset formula or something like that.
End Sub
Sub ApplyCF(rng As Range)
rng.Formula = "=(C4+C5)-C3"
'i'd like the macro to "offset" the formula,
'so for the C13 Range it would be "=(C11+C12) - C10"
End Sub
For your ApplyCF sub, you could do this:
Sub ApplyCF(rng As Range)
If rng.Count <> 1 Then Exit Sub ' in case your range is more than one cell
Dim prevCell As Range, twoPrevCell As Range, threePreCell As Range
Set prevCell = rng.Offset(-1, 0)
Set twoPrevCell = rng.Offset(-2, 0)
Set threeprevcell = rng.Offset(-3, 0)
rng.Formula = "=(" & twoPrevCell & "+" & prevCell & ")-" & threeprevcell
End Sub
It could definitely be tweaked, for instance, do you need to see the formula in the Formula Bar? We can evaluate that math in VBA and just put the answer in.
Per your comment, try this for every 6th cell (it's the whole macro, no need to split them):
Sub test()
' I assume you want to run this for every 6th cell in column C, starting with C1
Dim lastRow As Long
lastRow = Cells(Rows.Count, 3).End(xlUp).Row ' gets us our last row in column C with data
Dim cel As Range, rng As Range
For i = 6 To lastRow Step 6 'have to start at row 4, since any other row less than that messes up the formula
Cells(i, 3).Select ' because you can't have row 3-3
Cells(i, 3).Formula = "=(" & Cells(i - 2, 3).Address & "+" & Cells(i - 1, 3).Address & ")-" & Cells(i - 3, 3).Address
Next i
End Sub
If the formula needs to be displayed. Edited. Code below will work! you need to use the parmateter "address" to reference a cell. the parameters false or true are here to say if one needs the relative (Set to false) or absolute (set to true) referernce
Sub ApplyCF(rng As Range)
rng.Formula = "=(" & rng.Offset(-2, 0).Address(False, False) & _
"+" & rng.Offset(-1, 0).Address(False, False) & ")-" & rng.Offset(-3, 0).Address(False, False)
End Sub

Date Change with VBA Excel add/subtract in two different cells

How can I create a macro that will add a day in one cell and subtract a day in another cell at the same time? Here is what I have so far.
Sub ChangeDates()
Dim cell As Range
For Each cell In Range("B:B")
cell.Value = cell.Value + 1
Next cell
For Each cell In Range("C:C")
cell.Value = cell.Value - 1
End Sub
I know you've accepted an answer, but I would like to offer this approach, which is even faster and more efficient than looping through all those cells.
If your dates are in Column A, then Column B will hold date +1 and Column C will hold date -1
Option Explicit
Sub ChangeDates()
Dim myRange As range
Dim mySheet As Worksheet
Set mySheet = Sheets("Sheet7") 'change to your sheet
With mySheet
Set myRange = .range("A1:A" & .range("A" & .Rows.Count).End(xlUp).Row)
myRange.Offset(, 1).FormulaR1C1 = "=RC[-1]+1"
myRange.Offset(, 2).FormulaR1C1 = "=RC[-2]-1"
End With
End Sub
Offset to the rescue!!
Sub ChangeDates()
Dim cell As Range
For Each cell In Range("B:B")
cell.Value = cell.Value + 1
cell.offset(0,1).value = cell.offset(0,1).value - 1
Next cell
End Sub
Another thing you may consider is either looking at usedrange to not have to iterate through all of column B or put in a check to make sure the cells aren't blank... Just faster, better coding and stops you from having bad values where the cells were originally blank...
Sub ChangeDates()
Dim cell As Range
For Each cell In Intersect(Range("B:B"), ActiveSheet.UsedRange)
cell.Value = cell.Value + 1
cell.Offset(0, 1).Value = cell.Offset(0, 1).Value - 1
Next cell
End Sub

Get start range and end range of a vertically merged cell with Excel using VBA

I need to find out the first cell and the last cell of a vertically merged cell..
Let's say I merge Cells B2 down to B50.
How can I get in VBA the start cell(=B2) and the end cell(=B50)?
Sub MergedAreaStartAndEnd()
Dim rng As Range
Dim rngStart As Range
Dim rngEnd As Range
Set rng = Range("B2")
If rng.MergeCells Then
Set rng = rng.MergeArea
Set rngStart = rng.Cells(1, 1)
Set rngEnd = rng.Cells(rng.Rows.Count, rng.Columns.Count)
MsgBox "First Cell " & rngStart.Address & vbNewLine & "Last Cell " & rngEnd.Address
Else
MsgBox "Not merged area"
End If
End Sub
Below macro goes through all sheets in a workbook and finds merged cells, unmerge them and put original value to all merged cells.
This is frequently needed for DB applications, so I wanted to share with you.
Sub BirlesenHucreleriAyirDegerleriGeriYaz()
Dim Hucre As Range
Dim Aralik
Dim icerik
Dim mySheet As Worksheet
For Each mySheet In Worksheets
mySheet.Activate
MsgBox mySheet.Name & “ yapılacak…”
For Each Hucre In mySheet.UsedRange
If Hucre.MergeCells Then
Hucre.Orientation = xlHorizontal
Aralik = Hucre.MergeArea.Address
icerik = Hucre
Hucre.MergeCells = False
Range(Aralik) = icerik
End If
Next
MsgBox mySheet.Name & " Bitti!!"
Next mySheet
End Sub
Suppose you merged B2 down to B50.
Then, start cell address will be:
MsgBox Range("B2").MergeArea.Cells(1, 1).Address
End cell address will be:
With Range("B2").MergeArea
MsgBox .Cells(.Rows.Count, .Columns.Count).Address
End With
You can put address of any cell of merged area in place of B2 in above code.
Well, assuming you know the address of one of the cells in the merged range, you could just select the offset from that range and get the row/column:
Sub GetMergedRows()
Range("A7").Select 'this assumes you know at least one cell in a merged range.
ActiveCell.Offset(-1, 0).Select
iStartRow = ActiveCell.Row + 1
Range("A7").Select
ActiveCell.Offset(1, 0).Select
iEndRow = ActiveCell.Row - 1
MsgBox iStartRow & ":" & iEndRow
End Sub
The code above will throw errors if the offset row cannot be selected (i.e. if the merged rows are A1 through whatever) so you will want to add error handling that tells the code if it can't offset up, the top rows must be 1 and if it can't go down, the bottom row must be 65,536. This code is also just one dimensional so you might want to add the x-axis as well.
If you want the cell references as strings, you can use something like this, where Location, StartCell, and EndCell are string variables.
Location = Selection.Address(False, False)
Colon = InStr(Location, ":")
If Colon <> 0 Then
StartCell = Left(Location, Colon - 1)
EndCell = Mid(Location, Colon + 1)
End If
If you want to set them as ranges, you could add this, where StartRange and EndRange are Range objects.
set StartRange = Range(StartCell)
set EndRange = Range (EndCell)
If you intend to loop through the merged cells, try this.
Sub LoopThroughMergedArea()
Dim rng As Range, c As Range
Set rng = [F5]
For Each c In rng.MergeArea
'Your code goes here
Debug.Print c.Address'<-Sample code
Next c
End Sub

Resources