I'm trying to use a countifs statement by looking in the first 2 columns and comparing them to another table in the same Wokbook. The reference RrC1, RC1 or anything else does not work. I only get "0" as a result. If i type in constants it works. I'm sure that my arguments 2, 4, 6 are the problem. I just can' figure out why!
Sub DataBase()
'Set my tables
Dim Answers As ListObject
Dim Table As ListObject
Set Answers = Worksheets("quantitativ").ListObjects("DataQuant")
Set Table = Worksheets("Database").ListObjects("Tabelle7")
'Set my Ranges for filters (Organizational level, Location, Function...)
Set OrgRange = Answers.ListColumns(1).Range
Set LocRange = Answers.ListColumns(2).Range
'Set Ranges for Answers to Questions (Scale)
Set Q1 = Answers.ListColumns(5).Range
Dim r As Long 'Row variables for For-Loop
For r = 5 To Table.DataBodyRange.Rows.Count + 4
'Q1
Cells(r, 6).FormulaR1C1 = _
Application.WorksheetFunction.CountIfs(Q1, RrC5, OrgRange, RrC1, LocRange, RrC2)
Next r
End Sub
Cells(r, 6).FormulaR1C1 = _
Application.WorksheetFunction.CountIfs(Q1, RrC5, OrgRange, RrC1, LocRange, RrC2)
This is quite a mess. You're attempting to load a formula with the result of a worksheet function.
If you want to load the formula to the cell then I'd do this:
Cells(r, 6).Formula = "=CountIfs(" & Q1.Address & ", " & _
Cells(r, 5).Address & ", " & OrgRange.Address & ", " & _
Cells(r, 1).Address & ", " & LocRange.Address & ", " & _
Cells(r, 2).Address & ")"
Or even:
Cells(r, 6).Formula = .Formula = "=CountIfs(" & _
Q1.Address & ", E" & r & ", " & _
OrgRange.Address & ", A" & r & ", " & _
LocRange.Address & ", B" & r & ")"
However, if you want the formula evaluated and just the result dumped in the cell..
Cells(r, 6).Value = Application.WorksheetFunction.CountIfs(Q1, _
Cells(R, 5), OrgRange, Cells(R, 1), LocRange, Cells(R, 2))
Keep in mind though with all of these options, Cells(.. are not fully qualified.
Changing all to .Cells(.. would make this much better, wrapping the lot
in a
With WorkSheet("DESTINATION_SHEET")
...
...
End With
is highly advisable.
Related
I am getting a compile error on this line but everything seems right to me. I need to put a vlookup inside an if statement which is making this tricky. Can someone catch the error?
Dim k as Integer, numS as Integer
Range(Cells(k, 13), Cells(k, 13)).Formula = _
"=IF(" & Range(Cells(k, 14), Cells(k, 14)).Value & "=" & VLOOKUP(""Weeks from Event " & numS-1 & " to Event " & numS & """, R11C5:R10000C8, 4) & "," & (numS) & ", """")"
I think the error is the RC notation, try R[11]C[5]:R[10000]C[8], but to use VlookUp in VBA I like to use Application.WorksheetFunction...
Sub test()
Dim k As Long
Dim numS As Long
Dim LookUpValue As String
LookUpValue = "Weeks from Event " & numS - 1 & " to Event " & numS
Debug.Print (LookUpValue)
If (Cells(k, 14).Value = WorksheetFunction.VLookup(LookUpValue, Range(Cells(11, 5), Cells(1000, 8)), 4)) Then
Cells(k, 13).Value = numS
Else
Cells(k, 13).Value = ""
End If
End Sub
Let me know if this helps. You can pull up the immediate windows (Ctrl+G) in the VBA editor to see what the value of LookUpValue will be.
Failing againg with my project
I have formulas with variable Brand that is changed dynamically (AF Column). Basically all I want is to extract Brands into a column next (AE) to the formula column for visial convenience
For i = LBound(Brand) To UBound(Brand)
Range("AF" & i + 2).Formula = "=COUNTIFS(C:C," & RTrim(Month(Mesyaz3)) & _
",H:H,""Headphones"",F:F," & Chr(34) & Brand(i) & Chr(34) & ")"
Next i
Range("AF:AF").Sort Key1:=Range("AF2"), Order1:=xlDescending, Header:=xlYes
ActiveSheet.Range("AG2:AG8").Formula = ActiveSheet.Range("AF2:AF8").Formula
ActiveSheet.Range("AH2:AH8").Formula = ActiveSheet.Range("AF2:AF8").Formula
Dim ws As Worksheet
Set ws = Worksheets(1)
Dim j As Variant
j = Application.Match(""" & Brand(i) & """, ws.Range("AF2:AF8"))
ActiveSheet.Range("AE2").Value = Application.Index(ws.Range("AF2:AF8"), j, 0)
And I get #N/A Already lost two days for that. Would be enourmously grateful to anyone who could help.
It's not exactly clear from your question as to your desired output but here's a guess:
For i = LBound(Brand) To UBound(Brand)
Range("AF" & i + 2).Formula = "=COUNTIFS(C:C," & RTrim(Month(Mesyaz3)) & _
",H:H,""Headphones"",F:F," & Chr(34) & Brand(i) & Chr(34) & ")"
Range("AE" & i + 2).Value = Brand(i)
Next i
Range("AE:AF").Sort Key1:=Range("AF2"), Order1:=xlDescending, Header:=xlYes
I've added a line to write the brand to AE, and altered the Sort to accommodate this.
There is a particular part of my code which I cannot make work,
I'm trying to do the following command on VBA =RIGHT(LEFT(X1;Z1-2);LEN(LEFT(X1;Z1-2))-FIND(":";X1))
On cell X1, there is a text: RESULTS:NG & MODEL:IJ
My VBA code is:
LR = Cells(Rows.Count, "A").End(xlUp).Row
For i = 1 To LR
cel = "A" & i
cel2 = "Y" & i
cel3 = "Z" & i
cel4 = "X" & i
Range("M" & i).Formula = "=RIGHT(LEFT(" & cel4 & "," & cel3 & "-" & 2 & "),LEN(LEFT(" & cel4 & "," & cel3 & "-" & 2 & "))-FIND(:" & cel4 & "))"
Next i
I'm open for a better approach for this issue as well
Thanks in advance
Try writing all the formulas at once and reduce using quotes within the formula as much as possible.
Range(Cells(1, "M"), cells(lr, "M")).Formula = _
"=RIGHT(LEFT(X1, Z1-2), LEN(LEFT(X1, Z1-2))-FIND(char(58), X1))"
All range and cells reference within a sub procedure are better with a properly defined parent worksheet reference.
dim lr as long
with worksheets("sheet1")
LR = .Cells(.Rows.Count, "A").End(xlUp).Row
.Range(.Cells(1, "M"), .cells(lr, "M")).Formula = _
"=RIGHT(LEFT(X1, Z1-2), LEN(LEFT(X1, Z1-2))-FIND(char(58), X1))"
end with
The file I work on contains about 80,000 rows
I need to perform some basic checks and copy the results to the new sheet.
The whole thing takes about 8 minutes and I think its too long, is there any faster way?
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
lastCell = checkbook.UsedRange.Rows.Count
ReDim dataArray(2 To lastCell, 1 To 4)
For i = 2 To lastCell
dataArray(i, 1) = checkbook.Range(streetAddress & i).Value
dataArray(i, 2) = checkbook.Range(cityAddress & i).Value
dataArray(i, 3) = checkbook.Range(stateAddress & i).Value
dataArray(i, 4) = checkbook.Range(postCodeAddress & i).Value
Next I
For i = 2 To lastCell
If dataArray(i, 1) = "" Then
results.Range("A" & results.UsedRange.Rows.Count + 1 & ":" & lastCol & results.UsedRange.Rows.Count + 1).Value = checkbook.Range("A" & i & ":" & lastCol & i).Value
results.Range(commentAddress & results.UsedRange.Rows.Count).Value = "BLANK Street"
End If
If dataArray(i, 2) = "" Then
results.Range("A" & results.UsedRange.Rows.Count + 1 & ":" & lastCol & results.UsedRange.Rows.Count + 1).Value = checkbook.Range("A" & i & ":" & lastCol & i).Value
results.Range(commentAddress & results.UsedRange.Rows.Count).Value = "BLANK City"
End If
If dataArray(i, 3) = "" Then
results.Range("A" & results.UsedRange.Rows.Count + 1 & ":" & lastCol & results.UsedRange.Rows.Count + 1).Value = checkbook.Range("A" & i & ":" & lastCol & i).Value
results.Range(commentAddress & results.UsedRange.Rows.Count).Value = "BLANK State"
End If
If dataArray(i, 4) = "" Then
results.Range("A" & results.UsedRange.Rows.Count + 1 & ":" & lastCol & results.UsedRange.Rows.Count + 1).Value = checkbook.Range("A" & i & ":" & lastCol & i).Value
results.Range(commentAddress & results.UsedRange.Rows.Count).Value = "BLANK PostCode"
End If
Next i
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
I feel your pain, I had a sheet like that as well. Working cell by cell will be slow.
Try:
1) Can you try copy the whole Sheet not cell by cell so you have a backup before processing your blanks.
Some of my old code that you can use to modify, copy whole range in one go and put values in a brand new sheet:
Dim s1 As Worksheet
Dim s2 As Worksheet
Set s1 = ThisWorkbook.Sheets(strSourceSheet)
' What is range of source data
lastrow = s1.UsedRange.Rows.Count
lastcol = s1.UsedRange.Columns.Count
' copy across
s1.Range(s1.Cells(1, 1), s1.Cells(lastrow, lastcol)).Copy
' Create new empty worksheet for holding values
Set s2 = Worksheets.Add
s2.Range("A1").PasteSpecial Paste:=xlPasteValuesAndNumberFormats, SkipBlanks:=True
Application.CutCopyMode = False
' You can rename this s2 sheet
2) Then try SEARCH for your blank cells in each column and do a REPLACE. (Use Macro recorder to help get the syntax).
Some sample code below, you will need to clean this up by setting the range instead of using a select on whole column (which will add to blanks below your last row).
' go through each of your columns. Did street example here
Columns("A:A").Select
Selection.Find(What:="", After:=ActiveCell, LookIn:=xlFormulas, LookAt _
:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False).Activate
ActiveCell.Replace What:="", Replacement:="BLANK street", LookAt:=xlWhole _
, SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Hope this helps. You seem to know how to code, but if you are stuck then let me know.
I found an answer to the problem
instead of
results.Range(commentAddress & results.UsedRange.Rows.Count)
define for e.g. j and iterate it everytime you add new value to the sheet so
results.Range("A" & k & ":" & lastCol & k ).Value = checkbook.Range("A" & i & ":" & lastCol & i).Value
results.Range(commentAddress & k).Value = "BLANK Street"
k = k + 1
from 8 mins to 5 seconds :)
As per my Knowledge, a Sheet to sheet Traverse is always a time taking process.
i would suggest to use an array to save the details of check and then use them while assigning the values.
results.Range("A" & results.UsedRange.Rows.Count + 1 & ":" & lastCol & results.UsedRange.Rows.Count + 1).Value = array(Value)
The other recommendation is to identify the blank cells during the array assignment only and store the locations in the separate array. so directly you can iterate through only blank values instead of going through all you 80,000
I am trying to have VBA write a formula in a certain ranges of cells with row values defined by the variable: Arr(,). Because in EXCEL I would Ctrl+Shift+Enter the formula, I am using the FormulaArray command. However I am getting: Run-time error: 1004 Unable to set the FormulaArray property of the Range Class.
I have thoroughly checked the string format of the formula by VBA printing is as a string in a cell and comparing it to my normal input in EXCEL. So the formula should be fine. I have checked the length of the FormulaArray input and made sure it is well below the 255 character limit. Following a suggestion from online (http://dailydoseofexcel.com/archives/2005/01/10/entering-long-array-formulas-in-vba/), I used the .Replace command to overcome the word limit.
I have also tried to replace the With Sheets("Detail analysis").Cells(a, j) command with With Sheets("Detail analysis").Range(Cells(a,j).Address(0,0)); however this still gives the FormulaArray error.
Nevertheless, I am still getting the error: Run-time error: 1004 Unable to set the FormulaArray property of the Range Class. QUESTION EDIT: When this error is displayed the debugger points towards the line: .FormulaArray = formulaP1.
Can anyone suggest where I am going wrong with the code?
' Define variables '
Dim top As Integer
Dim bottom As Integer
Dim a As Integer
Dim sumrows As Double ' Summation of the Main Loads in a list '
Dim totalsum As Double ' Generator Loads total '
Dim etotalsum As Double ' Emergency Generator Loads total '
Dim g As Integer
Dim formulaP1 As String
Dim formulaP2 As String
Dim formulaP3 As String
Dim formulaP4 As String
Dim nill As String
nill = Chr(34) & Chr(34)
j = 6
' Loop for the number of "Actual Load" columns required '
Do While Sheets("Detail analysis").Cells(9, j).Value = Sheets("Detail analysis").Cells(9, 6).Value
totalsum = 0
etotalsum = 0
' Nested Loop for the list ranges identified by the previous code block (i.e. between orange and blue rows) '
i = 1
Do While Arr(i, 1) <> green ' Green is a previously defined row number '
''''' Identify the Orange (Top) and Blue (bottom) rows of the current list '
top = Arr(i, 1)
bottom = Arr(i, 2)
''''' Write formula in the "Actual Load" column between the Arr() rows '
For a = (top + 1) To (bottom - 1)
formulaP1 = "=IF(OR($B" & a + 1 & "=" & nill & ",$A" & a & "=" & nill & "),IF(OR($A" & a & "<>" & nill & ",$B" & a & "<>" & "X_X_X()"
formulaP2 = nill & "),$C" & a & "*$D" & a & "*" & Sheets("Detail analysis").Cells(a, j - 1).Address(0, 0) & "," & nill & ")," & "Y_Y_Y()"
formulaP3 = "SUM(" & Sheets("Detail analysis").Cells(a + 1, j).Address(0, 0) & ":INDIRECT(ADDRESS(SMALL(IFERROR(IF($A" & a + 2 & ":$A$" & bottom & "<>" & nill & "Z_Z_Z()"
formulaP4 = ",ROW($A" & a + 2 & ":$A$" & bottom & ")-1),#NULL!),1),COLUMN(" & Sheets("Detail analysis").Cells(a, j).Address(0, 0) & "),1,1,))))"
With Sheets("Detail analysis").Cells(a, j)
.FormulaArray = formulaP1
.Replace "X_X_X()", formulaP2
.Replace "Y_Y_Y()", formulaP3
.Replace "Z_Z_Z()", formulaP4
End With
Next a
Next a
i = i + 1
Loop
j = j + 2
Loop
QUESTION EDIT Following some further trials I have tried to VBA code some of the conditions in the formula. This divided the formula in two: one statement is =cell*cell*cell and so does not require FormulaArray. When I ran the code, this commands are executed well.
The second statement is the summation which considers a range of cells to calculate the value. The code is now failing specifically when my conditions call for the FormulaArray line. N.B. I checked the number of characters in formula and they add up to 250 (less than the 255 limit stated on the MSDN website http://msdn.microsoft.com/en-us/library/office/ff837104(v=office.15).aspx).
ws= Sheets("Detail analysis")
With ws
formula = "=SUM(" & .Cells(a + 1, j).Address(0, 0) & ":INDIRECT(ADDRESS(SMALL(IFERROR(IF($A" & a + 2 & ":$A$" & bottom & "<>" & nill & _
",ROW($A" & a + 2 & ":$A$" & bottom & ")-1),1E+99),1),COLUMN(" & .Cells(a, j).Address(0, 0) & "),1,1,))))"
End With
For a = (top + 1) To (bottom - 1)
If ws.Cells(a + 1, 2) = "" Or ws.Cells(a, 1) = "" Then
If (ws.Cells(a, 1) <> "" Or ws.Cells(a, 2) <> "") And ws.Cells(a, j - 1) <> "" Then
ws.Cells(a, j).formula = "=$C" & a & "*$D" & a & "*" & ws.Cells(a, j - 1).Address(0, 0)
End If
Else
ws.Cells(a, j).FormulaArray = formula
End If
Next a
I changed the #NULL! that you had to 1E+99 so it would never be SMALL. Not sure where #NULL! comes from but it isn't an accepted Excel error code. I also changed the method of assembling the array formula, choosing to assemble it as a string in the cell and only make it an array formula after the replacements were made and the formula was fully formed. With no data to test on and some vars made up (the values were missing in the sample), I came up with this.
' Write formula in the "Actual Load" column between the Arr() rows '
For a = (top + 1) To (bottom - 1)
With Sheets("Detail analysis")
formulaP1 = "'=IF(OR($B" & a + 1 & "=" & nill & ",$A" & a & "=" & nill & "),IF(OR($A" & a & "<>" & nill & ",$B" & a & "<>" & "X_X_X()"
formulaP2 = nill & "),$C" & a & "*$D" & a & "*" & .Cells(a, j - 1).Address(0, 0) & "," & nill & ")," & "Y_Y_Y()"
formulaP3 = "SUM(" & .Cells(a + 1, j).Address(0, 0) & ":INDIRECT(ADDRESS(SMALL(IFERROR(IF($A" & a + 2 & ":$A$" & bottom & "<>" & nill & "Z_Z_Z()"
formulaP4 = ",ROW($A" & a + 2 & ":$A$" & bottom & ")-1),1E99),1),COLUMN(" & .Cells(a, j).Address(0, 0) & "),1,1,))))"
With .Cells(a, j)
.Value = formulaP1
.Replace What:="X_X_X()", Replacement:=formulaP2, lookat:=xlPart
.Replace What:="Y_Y_Y()", Replacement:=formulaP3, lookat:=xlPart
.Replace What:="Z_Z_Z()", Replacement:=formulaP4, lookat:=xlPart
.FormulaArray = .Value
End With
End With
Next a
Addendunm: the .Replace functionality would have defaulted to what was last used. If this was xlWhole then the .Replace and the subsequent .FormulaArray assignment would again fail. I've modified to specify the , lookat:=xlPart parameter.