I will need a function to count the number of each item in column J and show the result on column K. But this code I show below keep saying that the criteria part RC[-2] is wrong. After the countif function, I will need it to be able to autofill in whatever lines are given so that I can apply this code to other files as well.
I used Macro to generate some code to start. And also try this earlier:
paste_countPTD = Worksheetfunction.CountIf(paste_conPTD,RC[-2]).
The criteria part seemed wrong.
Dim paste_conPTD As Range
Set paste_conYTD = Range("J2:J" & Range("A" & Rows.Count).End(xlUp).Row)
Range("K1").Select
ActiveCell.FormulaR1C1 = "Count_PTD"
Range("K2").Worksheetfunction.countif(paste_conPTD,RC[-2])
I appreciate any suggestion to make this code works. To do the countif for a column and autofill the formula.
You can try this code
Dim paste_conPTD As Range
Set paste_conYTD = Range("J2:J" & Range("A" & Rows.Count).End(xlUp).Row)
Range("K1") = "Count_PTD"
Dim iRng as Range
For each iRng in paste_conPTD
iRng.Offset(0,1) = Worksheetfunction.Countif(paste_conPTD, iRng)
Next iRng
To give you some notes, we need to iterate over each cells in the paste_conYTD range, that is where iRng comes in. We can't tell Excel like paste_conYTD = <some formula> and assume Excel knows we want it to compute for each cells using the formula. Excel iteration comes in a few ways, we can choose one that is easiest to apply based on scenario.
For each ... in ... Next
https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/for-eachnext-statement
For ... Next
https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/fornext-statement
Do... Loop
https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/doloop-statement
While... Wend
https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/whilewend-statement
If you want the actual formula in the cells try this.
Dim paste_conPTD As Range
Set paste_conYTD = Range("J2:J" & Range("A" & Rows.Count).End(xlUp).Row)
Range("K1").Value = "Count_PTD"
paste_conYTD.Offset(, 1).FormulaR1C1 = "=COUNTIF(" & paste_conYTD.Address(ReferenceStyle:=xlR1C1) & ",RC[-2])"
Related
The below code does vlookup then autofills the data then applies the filter to #N/A. Here I need to do another VLOOKUP in the same column with the filter as #N/A but I am not sure about this as how do we select the cells below F1 and apply VLOOKUP on the visible data. Could you help me out with this?
Sub Vlookup()
Worksheets("error rate").Activate
Range("F2") = "=Vlookup(B2,'sales'!B:C,2,0)"
Range("F2").Select
Range("F2").AutoFill Range("F2:F" & Range("B" & Rows.Count).End(xlUp).Row)
Range("F:F").Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues
Range("B1").AutoFilter Field:=6, Criteria1:="#N/A"
Range = Rng.Offset(1).SpecialCells(xlCellTypeVisible).Cells(1, 6)
End Sub
Few things
Avoid using Activate/Select. You may want to see How to avoid using Select in Excel VBA
Define and work with objects. Becomes much easier to work with your code.
Instead of entering formula in one cell and then autofilling it, simply enter the formula in the entire range in one go as shown below.
I see the objective is to get all the values. Then there is no need to enter a formula, filter and renter the formula. Use a single nested formula using IFERROR and IF. For example, if the formula "=Vlookup(B2,'sales'!B:C,2,0)" doesn't give you the result and you want to pull up the values from say column D then use the formula =IFERROR(VLOOKUP(B2,Sales!B:C,2,0),VLOOKUP(B2,Sales!B:D,3,0)). I have simply nested VLOOKUP(B2,Sales!B:D,3,0) inside IFERROR(). What the formula does is checks if there is an error with VLOOKUP(B2,Sales!B:C,2,0) and if there is, then it attempts to find the value using VLOOKUP(B2,Sales!B:D,3,0)
CODE
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim lRow As Long
'~~> Set this to the relevant sheet
Set ws = ThisWorkbook.Sheets("error rate")
With ws
'~~> Find last row
lRow = .Range("B" & .Rows.Count).End(xlUp).Row
'~~> Work with the relevant range
With .Range("F2:F" & lRow)
'~~> Enter the formula in the entire range in one go
.Formula = "=IFERROR(VLOOKUP(B2,Sales!B:C,2,0),VLOOKUP(B2,Sales!B:D,3,0))"
'~~> OPTIONAL
'~~> Instead of copy and paste as values use this.
'.Value = .Value
End With
End With
End Sub
Semi-new to VBA but need help. I have the following code that I am trying to convert into a loop to provide the number of days between today's date and a date found in column A. The number of rows can change based on data entered and want it to stop when the cell in column A is blank. I also want only the value to appear. Any help is greatly appreciated. The below works great for the first row. I believe the loop should appear on row 2 but don't know how to go about it. Thank you in advance.
Range(ActiveSheet.Range("E2"), ActiveSheet.Range("E2").End(xlDown).Select
ActiveCell.FormulaR1C1 = "=SUM(TODAY()-OFFSET(R2C1,0,0,COUNTA(c[-4]),1))"
ActiveCell.Value = ActiveCell.Value
You do not need a loop for this. This will determine the used range in Column A and apply the formula (but only paste value) in the same used range down Column E
Also, notice that you do not need to use .Select, .Active, or .Selection. here. Directly qualify your ranges and you will save yourself trouble down the road. For learning purposes, it is best to act like those lines do not exist :)
Sub DateDif()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim LRow As Long: LRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
With ws.Range("E2:E" & LRow)
.Formula = "=NOW() - A2"
.Value = .Value 'If you want the formula to remain, remove this line
End With
End Sub
Hi All.
I need your help please.
I want to apply a formula to the new rows that I've just added. I have a line of code I use for a full set of data, but I'm not sure how to modify it, or if there is a better way to do it.
I'm a bit out of my league with this line of code, I understand what it's doing but I didn't write it.
Sheets("Closed Loop").Range(varPastePos).Offset(0, 2).Resize(ActiveSheet.UsedRange.Rows.Count - 1, columnsize:=1).FormulaR1C1 = "My Formula"
varPastePos is the position the new data was pasted, in this case $F$28
Any ideas?
Use Range().FillDown to extend a pre-existing formula.
Dim lastRow As Long
lastRow = Range("F" & Rows.Count).End(xlUp).Row
Range("A2", "A" & lastRow).FillDown
You can FillDown multiple columns at once like this:
Range("A2", "D" & lastRow).FillDown
You can do it all in one line like this:
Range("A2", Range("F" & Rows.Count).End(xlUp)).FillDown
.UsedRange would also include formatted blank cells so it is not reliable for finding the last used row.
Set ws = Sheets("Closed Loop")
Set cell1 = ws.Range(varPastePos) ' F28
Set cell2 = cell1.End(xlDown) ' F32 ? the last cell with data below F28. Similar to clicking on F28 and pressing Ctrl + down
Set rngF = ws.Range(cell1, cell2) ' F28:F32
Set rngH = rngF.Offset(, 2) ' H28:H32
rngH.FormulaR1C1 = "My Formula"
VBA newbie here. I have a dynamic list of multiple groups. Each group lists the leader of the group at the top with the members of the group below. There is a primary key in Column A next to each listed person. I want to take the leader's key # and apply it to Column F for the leader and each member of the group, such that each member has their own primary key # in Column A and is associated with their leader's primary key # in Column F. Here are two images of what I need for the before and after:
Before
After
Here is the code I am playing around with conceptually:
Sub Apply_Leader_Code()
Dim wSht As Worksheet
Dim lStart As Long, lEnd As Long, lLdrID As Long
Set wSht = ThisWorkbook.Sheets("Upload")
With wSht.Range("A1:G" & Range("A" & Rows.Count).End(xlUp).Row)
lStart = .Rows.Find("78") 'Find the first row for each group
lEnd = .Rows.FindNext("78") - 1 'Find the last row for each group
If .Range("G" & lStart & ":G" & lEnd).Value = "" Then
'If there is no leader ID yet, then continue...
lLdrID = .Cells(lStart, 1).Value 'Assign leader's primary key to the variable
.Cells(lStart, 7).Value = lLdrID 'Place lLdrID value into Column G
.Range("F" & lStart & ":F" & lEnd).FillDown 'Fill value to end of group range
Else
'..otherwise, set start/end rows for next group.
lStart = .Rows.FindNext("Leader")
lEnd = .Rows.FindNext("Leader") - 1
End If
End With
End Sub
The above code isn't actually applicable, but I hope represents what I think is a reasonable way to solve this problem. I can (maybe?) figure out how to do this for the first group, but how do I then perform the same .FillDown function for each subsequent group?
--EDIT--
In regards to Siddarth Rout's answer below, here is my newer code:
Range("G2").Select
ActiveCell.FormulaR1C1 = "=RC[-6]"
Range("G3").Select
ActiveCell.FormulaR1C1 = "=IF(RC[-1]=78,RC[-6],R[-1]C)"
Range("G3").Select
Selection.AutoFill Destination:=Range("G3:G" & Range("G" & Rows.Count).End(xlUp).Row)
I used the Macro creator in Excel and then edited it to what I thought would enable it to have a dynamic range instead of a set range. Now I'm getting a 400 error. Any ideas why? Any ideas on how to input the formulas w/o "selecting" the range? I am gathering that many programmers think that selecting cells is bad programming...
Do you need VBA for this? This can be achieved using excel formulas
Formula in Cell G2
=A2
Formula in Cell G3
=IF(F3=78,A3,G2)
now simply copy the formula from G3 down to G14
If you still need VBA then simply record a macro for the above steps and amend it :)
FOLLOWUP (From Comments)
Yes .Select should be avoided.
INTERESTING READ
Also no need to use R1C1 format. You can directly specify the formula
And one more thing. You don't need to use Autofill. You can skip that step by directly filling all the relevant cells with the relevant formula in ONE GO
Is this what you are trying?
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim lRow As Long
'~~> Change this to the relevant sheet
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
'~~> Find the last cell in Col A which has data
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Enter first formula
.Range("G2").Formula = "=A2"
'~~> Enter 2nd formula in all the
'~~> cells in one go rather than autofill
.Range("G3:G" & lRow).Formula = "=IF(F3=78,A3,G2)"
End With
End Sub
I'm new to vba programming and I would like to work on a function to fix salutations in an excel file.
To start, I would just like to append a Dear " to a name in the first column, and put this value in the next column, so that I would end up with the name in the first column and "Dear name" in the next column.
The function I have so far, is putting "Dear " in the next column, but it is not appending that to the text in the first column. Could someone help me correct my code?
Sub letterSalutationFixer()
Dim letterSalutationColumn As Range
Set letterSalutationColumn = Columns(1)
For Each Cell In letterSalutationColumn
Cell.Offset(, 1).Value = "Dear " & Cell.Text
Next
End Sub
PS. I do realise that I don't necessarily need to do this programmatically since it doesn't take that long to do with the functions already available, but I eventually want to expand this to fix other data with more complexity - and just thought I could start with something simple.
Many thanks in advance!
The reason it's blank is that Cell is equivalent to the whole column. You're close though. If you did...
For Each Cell In letterSalutationColumn.Cells
..l it would cycle through each cell.
However, the way it's written, it would cycle through each cell in the whole column, which could crash Excel, or at least slow things way down.
Here's a reworked version of what you're trying to do. It only acts on the cells in column A with content:
Sub Salutation()
Dim ws As Excel.Worksheet
Dim LastRow As Long
Dim NameRange As Excel.Range
Dim cell As Excel.Range
Set ws = ActiveSheet
With ws
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
Set NameRange = .Range("A2:A" & LastRow)
For Each cell In NameRange
cell.Offset(, 1) = "Dear " & cell.Text
Next cell
End With
End Sub
It also declares all variables, something you want to get in the habit of doing. Do a search on Option Explicit to learn how to force yourself to.
It also uses a With statement to fully qualify Object references, so that instead of just referring to Column(1) or Range(something) you're specifying that it's in ws, which has been set to the ActiveSheet.
Another way is the VBA alternative of
Using a formula in column B that runs the concatenation against the used part of column A (ie in B1 ="Dear " &A1 etc)
The formula then is copied over itself as a value to remove the formula
code
Sub QuickCon()
Dim rng1 As Range
Set rng1 = Range([a1], Cells(Rows.Count, "A").End(xlUp))
With rng1.Offset(0, 1)
.FormulaR1C1 = "=""Dear "" &RC[-1]"
.Value = .Value
End With
End Sub