I have a macro that runs on cell changes but every time I want to run it it keeps giving me "Next without for" or "double declaration within given range"
Here's the code:
Dim Lvl As Range
Set Lvl = Range("A5:A44")
Dim Full, Medium, Poor
Dim r As Long
For r = 5 To 44
Full = StrComp(Range("A" & r), Data.Range("A2"), 0)
Medium = StrComp(Range("A" & r), Data.Range("A3"), 0)
Poor = StrComp(Range("A" & r), Data.Range("A4"), 0)
If Not Intersect(Target, Lvl) Is Nothing Then
Dim i As Integer
For i = r To 44
If Full = 0 Then
Range("I" & r).Value = Application.WorksheetFunction.RoundDown((Range("B" & r) * 1), 0)
ElseIf Medium = 0 Then
Range("I" & r).Value = Application.WorksheetFunction.RoundDown((Range("B" & r) * (3 / 4)), 0)
ElseIf Poor = 0 Then
Range("I" & r).Value = Application.WorksheetFunction.RoundDown((Range("B" & r) * (1 / 2)), 0)
Else
Range("I" & r).Value = 0
End If
If Not Range("A" & r) = Range("A" & r).Offset(-1, 0) And Not Range("A" & r) = A5 Then
If Range("A" & r).Offset(-1, 0) = Full And Range("A" & r) = Medium Then
Range("I" & i).Value = Range("I" & i).Value + 1
ElseIf Range("A" & r).Offset(-1, 0) = Medium And Range("A" & r) = Poor Then
Range("I" & i).Value = Range("I" & i).Value + 1
ElseIf Range("A" & r).Offset(-1, 0) = Full And Range("A" & r) = Poor Then
Range("I" & i).Value = Range("I" & i).Value + 2
End If
End If
Next
End If
Next
The Double Declaration Error I am getting probably has to do with the fact that I am using r = 5 To 44 AND i = r To 44
But I needed a way to get the Range("I" & i).value to work
There is an End If missing right before Next
Dim Lvl As Range
Set Lvl = Range("A5:A44")
Dim Full, Medium, Poor
r = 5
Full = StrComp(Range("A" & r), Data.Range("A2"), 0)
Medium = StrComp(Range("A" & r), Data.Range("A3"), 0)
Poor = StrComp(Range("A" & r), Data.Range("A4"), 0)
If Not Intersect(Target, Lvl) Is Nothing Then
Dim i As Integer
For i = r To 44
If Full = 0 Then
Range("I" & r).Value = Application.WorksheetFunction.RoundDown((Range("B" & r) * 1), 0)
ElseIf Medium = 0 Then
Range("I" & r).Value = Application.WorksheetFunction.RoundDown((Range("B" & r) * (3 / 4)), 0)
ElseIf Poor = 0 Then
Range("I" & r).Value = Application.WorksheetFunction.RoundDown((Range("B" & r) * (1 / 2)), 0)
Else
Range("I" & r).Value = 0
End If
If Not Range("A" & r) = Range("A" & r).Offset(-1, 0) And Not Range("A" & r) = A5 Then
'^^-- this one is not closed by End If
If Range("A" & r).Offset(-1, 0) = Full And Range("A" & r) = Medium Then
'^^-- this is AAA
Range("I" & i).Value = Range("I" & i).Value + 1
ElseIf Range("A" & r).Offset(-1, 0) = Medium And Range("A" & r) = Poor Then
Range("I" & i).Value = Range("I" & i).Value + 1
ElseIf Range("A" & r).Offset(-1, 0) = Full And Range("A" & r) = Poor Then
Range("I" & i).Value = Range("I" & i).Value + 2
End If '<-- this closes the one I marked with AAA
End If '<-- missing here !!!
Next
End If
Related
This is looping through a worksheet that is about 10k rows and it is taking a considerable amount of time. Is there a way to do this faster aside from an array? thank you
For i = 2 To spberowcnt
With spbe30
.Range("b" & i).Value = LCase(.Range("b" & i).Value)
.Range("d" & i).Value = LCase(.Range("d" & i).Value)
.Range("i" & i).Value = LCase(.Range("i" & i).Value)
.Range("j" & i).Value = LCase(.Range("j" & i).Value)
.Range("l" & i).Value = LCase(.Range("l" & i).Value)
.Range("m" & i).Value = LCase(.Range("m" & i).Value)
.Range("n" & i).Value = LCase(.Range("n" & i).Value)
.Range("p" & i).Value = LCase(.Range("p" & i).Value)
.Range("q" & i).Value = LCase(.Range("q" & i).Value)
.Range("r" & i).Value = LCase(.Range("r" & i).Value)
.Range("z" & i).Value = LCase(.Range("z" & i).Value)
.Range("aa" & i).Value = LCase(.Range("aa" & i).Value)
End With
Next i
For i = 2 To spberowcnt
With spbe60
.Range("b" & i).Value = LCase(.Range("b" & i).Value)
.Range("d" & i).Value = LCase(.Range("d" & i).Value)
.Range("i" & i).Value = LCase(.Range("i" & i).Value)
.Range("j" & i).Value = LCase(.Range("j" & i).Value)
.Range("l" & i).Value = LCase(.Range("l" & i).Value)
.Range("m" & i).Value = LCase(.Range("m" & i).Value)
.Range("n" & i).Value = LCase(.Range("n" & i).Value)
.Range("p" & i).Value = LCase(.Range("p" & i).Value)
.Range("q" & i).Value = LCase(.Range("q" & i).Value)
.Range("r" & i).Value = LCase(.Range("r" & i).Value)
.Range("z" & i).Value = LCase(.Range("z" & i).Value)
.Range("aa" & i).Value = LCase(.Range("aa" & i).Value)
End With
Next i
This is the array solution
Sub test()
Application.ScreenUpdating = False
Dim arrWorksheets(1) As Variant, ws As Worksheet
Set arrWorksheets(0) = spbe30
Set arrWorksheets(1) = spbe60
Dim arrColumns As Variant
arrColumns = Array("B", "D", "AA") 'adjust to your needs
Dim arrValues As Variant
Dim iWs As Long, iC As Long, i As Long
For iWs = 0 To UBound(arrWorksheets)
Set ws = arrWorksheets(iWs)
For iC = 0 To UBound(arrColumns)
arrValues = ws.Range(arrColumns(iC) & "2").Resize(spberowcnt).Value
For i = 1 To UBound(arrValues, 1)
arrValues(i, 1) = LCase(arrValues(i, 1))
Next
ws.Range(arrColumns(iC) & "2").Resize(spberowcnt).Value = arrValues
Next
Next
Application.ScreenUpdating = True
End Sub
Alternative: helper columns ...
You could try something like the following, looping over the columns instead of the individual cells and using Evaluate and Lower on the entire column. You could also process adjacent columns together.
cols = Array("B", "D", "I:J", "L:N", "P:R", "Z:AA")
For i = LBound(cols) to Ubound(cols)
Dim col As String
col = cols(i)
With spbe30
Dim rng As Range
Set rng = .Rows("2:" & spberowcnt).Columns(col)
rng.Value = .Evaluate("LOWER(" & rng.Address & ")")
End With
Next
But as mentioned in comments, an array is probably the way to go.
I have written a program that counts bins that are empty (verified), empty (unverified), and not accessible (bins locked).
I am trying to count the bins that are locked from my Bin Conversions sheet that if they are TRUE (there are 20 that are true), then they are locked and will be counted on my Bin Report sheet.
My Bin Reports sheet counts 1 too many for each group (all groups total 23 instead of 20). A group example would be 4-Pallet, 2.5ft, 2 bins locked (instead of 1).
Bin Report
Bin Conversions
Sub getBinStatusArray()
calc (False)
Dim dSH As Worksheet
Dim brSH As Worksheet
Dim bcSH As Worksheet
Set dSH = ThisWorkbook.Sheets("data")
Set brSH = ThisWorkbook.Sheets("Bin Report")
Set bcSH = ThisWorkbook.Sheets("Bin Conversions")
Dim binLockCell As Byte, binType As String, binSize As Variant, binLocked As Boolean, b As Long, i As Long
Dim dataArray() As Variant
Dim binIDArray As Variant
'Create empty array cells
ReDim Preserve dataArray(1 To dSH.Range("A" & Rows.Count).End(xlUp).Row, 1 To 3)
'Navigates cells
With dSH
lastrow = .Cells(Rows.Count, 1).End(xlUp).Row
dataArray = .Range(.Cells(lastrow, 1), .Cells(1,
.Columns.Count).End(xlToLeft)).Value
End With
'Count Bin Conversion Cells
With bcSH
lastrow = .Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastrow
.Range("E" & i).Value2 = Application.WorksheetFunction.CountIf(dSH.Range("A:A"), .Range("A" & i).Value2)
Next i
End With
'Generate Bin Report
With brSH
.Cells.ClearContents
.Range("H1").Value = "Filter Input"
.Range("B1").Value = "Bin Type"
.Range("I1").Value = "Bin Type"
.Range("C1").Value = "Bin Height"
.Range("J1").Value = "Bin Height"
.Range("D1").Value = "Verified"
.Range("K1").Value = "Verified"
.Range("E1").Value = "Unverified"
.Range("L1").Value = "Unverified"
.Range("F1").Value = "Bins Locked"
.Range("M1").Value = "Bins Locked"
For i = 2 To lastrow
If bcSH.Range("E" & i).Value = 1 Or Application.WorksheetFunction.CountIfs(bcSH.Range("G" & i), "true") Then
binType = bcSH.Range("B" & i).Value
binSize = bcSH.Range("C" & i).Value
binLocked = bcSH.Range("H" & i).Value
If .Range("b2") = "" Then
.Range("b2").Value = bcSH.Range("B" & i).Value
.Range("c2").Value = bcSH.Range("C" & i).Value
.Range("F2").Value2 = Application.WorksheetFunction.CountIfs(bcSH.Range("G" & i), "true")
ElseIf .Range("b2") <> "" Then
lastrow = brSH.Cells(Rows.Count, 2).End(xlUp).Row
For b = 2 To lastrow + 1
If brSH.Range("B" & b) = binType And brSH.Range("C" & b) = binSize Then
brSH.Range("D" & b) = brSH.Range("D" & b) + bcSH.Range("E" & i)
binLockCell = Application.WorksheetFunction.CountIfs(bcSH.Range("G" & i), "true")
brSH.Range("F" & b) = binLockCell + brSH.Range("F" & b)
Exit For
ElseIf b = lastrow Then
.Range("b" & b + 1).Value = bcSH.Range("B" & i).Value
.Range("c" & b + 1).Value = bcSH.Range("c" & i).Value
.Range("D" & b + 1).Value = bcSH.Range("E" & i).Value
binLockCell = Application.WorksheetFunction.CountIfs(bcSH.Range("G" & i), "true")
.Range("F" & b + 1) = binLockCell + .Range("F" & b + 1)
End If
Next b
End If
End If
Next i
Range("b1").CurrentRegion.sort key1:=Range("b1"), order1:=xlAscending, _
key2:=Range("C1"), order2:=xlAscending, Header:=xlYes
End With
calc (True)
End Sub
You are looping For b = 2 To lastrow + 1 but adding a new line when b = lastrow i.e. before the loop has ended. So on the last iteration when b = lastrow + 1 it summates the record again. One fix would be use a flag.
ElseIf .Range("b2") <> "" Then
Dim bExists: bExists = False
lastrow = brSH.Cells(Rows.Count, 2).End(xlUp).Row
' increment existing
For b = 2 To lastrow
If brSH.Range("B" & b) = binType And brSH.Range("C" & b) = binSize Then
brSH.Range("D" & b) = brSH.Range("D" & b) + bcSH.Range("E" & i)
binLockCell = Application.WorksheetFunction.CountIfs(bcSH.Range("G" & i), "true")
brSH.Range("F" & b) = binLockCell + brSH.Range("F" & b)
bExists = True
Exit For
Next b
' or add new line
If Not bExists Then
.Range("b" & b + 1).Value = bcSH.Range("B" & i).Value
.Range("c" & b + 1).Value = bcSH.Range("c" & i).Value
.Range("D" & b + 1).Value = bcSH.Range("E" & i).Value
binLockCell = Application.WorksheetFunction.CountIfs(bcSH.Range("G" & i), "true")
.Range("F" & b + 1) = binLockCell + .Range("F" & b + 1)
End If
End If
I've been tried to find something to fix my problem two days ago but nothing works. My first question here and I am non-native english speaker, so I'm sorry for something bad in my text, but here we go:
I have a macro that create a new sheet and feed some data (in this new sheet) that came from home sheet that users will input data, besides some formulas that I create in VBA that will feed that new sheet too. Ok, so, after that, I have to use Offset + Match to create a variable (works fine in Excel) --I called "ParcelaHoje"-- that return a value based on a cell value right on the side. Them problem is that the two variables that I use in Match function is different. One of them is Date ("MesAtual") and the another is a Range, I think. I'm kind of confused with what type of variable will be a variable that contains dates in each cell. An array I suppose.
I've tried to use Application.Match instead of WorksheetFunction.Match, the return error is diferent, but still an error. That's not where the problem is, I think.
I've tried to declare a variable that contains that Range("B:B"), but not working too.
All the code below:
Sub criar_fluxo()
'ATIVAR ABA MACRO
Worksheets("MACRO").Activate
'DECLARA VARIAVEIS INPUTADAS PELO USUARIO
Dim MesAtual As Date
Dim MesFormalizacao As Date
ValorBruto = Range("E" & "2").Value
TaxaDeJuros = Range("D" & "2").Value
ValorParcela = Range("H" & "2").Value
NumeroDeParcelas = Range("F" & "2").Value
Carencia = Range("G" & "2").Value
MesFormalizacao = Range("J" & "2").Value
MesAtual = Range("I" & "2").Value
ParcelaInicial = Range("K" & "2").Value
ParcelaFinal = Range("L" & "2").Value
'ADD NOVA ABA
Sheets.Add
Range("A1", "H1").Interior.Color = vbBlue
'COLA VALORES DA ABA MACRO NA NOVA ABA
With ActiveSheet
Range("A1", "H1").Interior.ColorIndex = 16
Range("A1", "H1").Font.ColorIndex = 1
Range("A" & "1") = "N° PARCELA"
Range("B" & "1") = "MES PARCELA"
Range("C" & "1") = "JUROS"
Range("D" & "1") = "AMORTIZACAO"
Range("E" & "1") = "PARCELA ATUAL"
Range("F" & "1") = "SALDO DEVEDOR"
Range("G" & "1") = "VALOR PARCELA ADIANTADA"
Range("H" & "1") = "# MESES ADIANTADOS"
Range("F" & "2") = ValorBruto
SaldoDevedor = ValorBruto
Cells(2, 1) = 0
numRow = 3
Columns("A:H").AutoFit
'LOOP DA CARENCIA
For numRow = 3 To numRow + Carencia - 2
Juros = SaldoDevedor * TaxaDeJuros
Range("C" & numRow) = Juros
SaldoDevedor = SaldoDevedor + Juros
Range("F" & numRow) = SaldoDevedor
Range("A" & numRow) = 0
Range("B" & numRow - 1) = MesFormalizacao
MesFormalizacao = WorksheetFunction.EoMonth(MesFormalizacao, 1)
Next
Range("B" & numRow - 1) = MesFormalizacao
MesFormalizacao = WorksheetFunction.EoMonth(MesFormalizacao, 1)
numRow = numRow
Amortizacao = 0
NumeroDaParcela = 1
'LOOP DAS PARCELAS REGULARES
For numRow = numRow To numRow + NumeroDeParcelas - 1
Juros = SaldoDevedor * TaxaDeJuros
Range("C" & numRow) = Juros
Range("E" & numRow) = ValorParcela
Amortizacao = ValorParcela - Juros
SaldoDevedor = SaldoDevedor - Amortizacao
Range("D" & numRow) = Amortizacao
Range("F" & numRow) = SaldoDevedor
Range("A" & numRow) = NumeroDaParcela
NumeroDaParcela = NumeroDaParcela + 1
Range("B" & numRow) = WorksheetFunction.EoMonth(MesFormalizacao, 0)
MesFormalizacao = WorksheetFunction.EoMonth(MesFormalizacao, 1)
Next
Range(Cells(2, 2), Cells(2, 2).End(xlDown)).NumberFormat = "m/d/yyyy"
FirstRow = Cells(2, 2).Row
LastRow = Cells(Rows.Count, 1).End(xlUp).Row
'ACHAR NUMERO DA PARCELA DE HOJE
ParcelaHoje = WorksheetFunction.Offset(Range("A1"), Application.Match(MesAtual, Range("B2:B" & LastRow), 0), 0)
'ParcelaAdiantada = ValorParcela / (1 + TaxaDeJuros) ^ 'DIFERENCA ENTRE ParcelaInicial e ParcelaHoje
End With
End Sub
The problem is in the line:
ParcelaHoje = WorksheetFunction.Offset(Range("A1"), Application.Match(MesAtual, Range("B2:B" & LastRow), 0), 0)
that return error "Run-time error '438': Object doesn't support this property or method"
I've tried to use that below, create a new variable type Variant with the range values:
Dim MonthRange As Range
Set MonthRange = Range("B2:B" & LastRow)
Meses As Variant
Meses = MonthRange.Value
And then use that variable "Meses" instead of "MonthRange", but it won't works anyway :(
I don't know what else to do, and it looks like that there is something very very simple and I can't see it.
I'm trying to modify the below function to include logic where if the variables PPD_1_Date, PPD_2_Date and TSpot_Date are all empty (blank) then output to my "Error" worksheet.
I have rows that should fall under this logic, however they are falling under the Else condition instead.
Function PPDdate()
Dim PPD_1_Date As Date
Dim PPD_2_Date As Date
Dim TSpot_Date As Variant
Dim i As Long, j As Long, k As Long
j = Worksheets("PPDCI").Range("A" & Rows.Count).End(xlUp).Row + 1
k = Worksheets("Error").Range("A" & Rows.Count).End(xlUp).Row + 1
For i = 2 To lstrow
PPD_1_Date = Worksheets("Data").Range("AW" & i)
PPD_2_Date = Worksheets("Data").Range("BA" & i)
Entity = Worksheets("Data").Range("J" & i)
Dept = Worksheets("Data").Range("M" & i)
TSpot_Date = Worksheets("Data").Range("AS" & i)
If PPD_1_Date > PPD_2_Date Then
Worksheets("PPDCI").Range("A" & j & ":C" & j).Value = Worksheets("Data").Range("A" & i & ":C" & i).Value
Worksheets("PPDCI").Range("F" & j).Value = PPD_1_Date
Worksheets("PPDCI").Range("G" & j).Value = Worksheets("Data").Range("AX" & i).Value
Worksheets("PPDCI").Range("H" & j).Value = Worksheets("Data").Range("AZ" & i).Value
Worksheets("PPDCI").Range("I" & j).Value = Worksheets("Data").Range("AY" & i).Value
j = j + 1
Else
If PPD_1_Date < PPD_2_Date Then
Worksheets("PPDCI").Range("A" & j & ":C" & j).Value = Worksheets("Data").Range("A" & i & ":C" & i).Value
Worksheets("PPDCI").Range("F" & j).Value = PPD_2_Date
'Worksheets("PPDCI").Range("G" & j).Value = "ELSE IF CONDITION"
Worksheets("PPDCI").Range("G" & j).Value = Worksheets("Data").Range("BB" & i).Value
Worksheets("PPDCI").Range("H" & j).Value = Worksheets("Data").Range("BD" & i).Value
Worksheets("PPDCI").Range("I" & j).Value = Worksheets("Data").Range("BC" & i).Value
j = j + 1
Else
'If IsEmpty(Worksheets("Data").Range(PPD_1_Date & i).Value) = True And IsEmpty(Worksheets("Data").Range(PPD_2_Date & i).Value) = True Then
'GoTo EmptyRange
'Else
If (InStr(1, Entity, "CNG Hospital") Or InStr(1, Entity, "Home Health") Or InStr(1, Entity, "Hospice") Or InStr(1, Dept, "Volunteers") Or ((IsEmpty(PPD_1_Date) = True) And (IsEmpty(PPD_2_Date) = True))) And IsEmpty(TSpot_Date) = True Then
Worksheets("Error").Range("A" & k & ":H" & k).Value = Worksheets("Data").Range("A" & i & ":C" & i).Value
Worksheets("Error").Range("F" & k).Value = "REVIEW PPD DATA"
k = k + 1
Else
Worksheets("PPDCI").Range("A" & j & ":C" & j).Value = Worksheets("Data").Range("A" & i & ":C" & i).Value
Worksheets("PPDCI").Range("F" & j).Value = TSpot_Date
Worksheets("PPDCI").Range("G" & j).Value = Worksheets("Data").Range("AX" & i).Value
Worksheets("PPDCI").Range("H" & j).Value = Worksheets("Data").Range("AY" & i).Value
Worksheets("PPDCI").Range("I" & j).Value = "NO PPD DATES BUT HAS TSPOT DATE1"
j = j + 1
End If
End If
End If
'EmptyRange:
'k = k + 1
Next i
End Function
Here is the code I added to the other OR logic;
Or ((IsEmpty(PPD_1_Date) = True) And (IsEmpty(PPD_2_Date) = True))
Example row has empty cells in columns AW, BA, and AS, so it should write to my Error worksheet. Is there a syntax or logic issue? I did initially have TSPOT_Date defined as a Date variable, however I was getting a '1004' runtime error (I think because some column rows are empty) so I changed to Variant, however logic still doesn't work as I expect.
The problem you're running into is that you can't check if Date variables are "empty" using isEmpty() or even with Len() because the default value for a date is 30-Dec-1899 00:00:00, so there is always a value in a Date variable.
Instead, you should check to see that a Date variable is empty/has not been filled like this
If PPD_2_Date = 0 Then
...
How to set range for cells like with formula "102."&H2 and give value 102.1
H2 will give different number after loops
Count = 2
For I = 7 To N
If Range("E" & Count) = Range("E" & I) And Range("A" & I) = "102." & [H2] Then
Something
This is not working "102." & [H2]
If Range("E" & Count) = Range("E" & I) And Range("A" & I) > 0 Then
If i switch with > 0 this works:D
If Range("E" & Count) = Range("E" & I) And Range("A" & I) = "102." & [H2] Then
Something
This is not working with "102." & [H2]
If Range("E" & Count) = Range("E" & I) And Range("A" & I) > 0 Then
If i switch with > 0 this works:D