I am having issued with this code, the loop is supposed to only run once but its running 6 times and passing all of the data even though the toggle buttons are not pressed
the way this is supposed to work is that only the data that has the toggle button attached to it will be transferred to column C and E. its working but, its passing all the data and more even if the toggle buttons are not pressed
Private Sub SubmitCSR_Click()
Dim LastRow As Long
Dim ws As Worksheet: Set ws = Sheets("GP count")
Dim StockCaption(1 To 6) As String
'populate the array
StockCaption(1) = ToggleButton6.Caption
StockCaption(2) = ToggleButton2.Caption
StockCaption(3) = ToggleButton4.Caption
StockCaption(4) = ToggleButton5.Caption
StockCaption(5) = ToggleButton1.Caption
StockCaption(6) = ToggleButton3.Caption
'declare a variant to hold the array element
Dim StockCC As Variant
Dim ReceivedV(1 To 6) As String
'populate the array
ReceivedV(1) = R1.Value
ReceivedV(2) = R2.Value
ReceivedV(3) = R3.Value
ReceivedV(4) = R4.Value
ReceivedV(5) = R5.Value
ReceivedV(6) = R6.Value
'declare a variant to hold the array element
Dim ReceivingN As Variant
'loop through the entire array
Dim strNames(1 To 6) As Variant
'populate the array
strNames(1) = ToggleButton6.Value
strNames(2) = ToggleButton2.Value
strNames(3) = ToggleButton4.Value
strNames(4) = ToggleButton5.Value
strNames(5) = ToggleButton1.Value
strNames(6) = ToggleButton3.Value
'declare a variant to hold the array element
Dim StockValue As Variant
'loop through the entire array
For Each StockValue In strNames
For Each ReceivingN In ReceivedV
For Each StockCC In StockCaption
If StockValue = True Then
LastRow = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row
ws.Range("C" & LastRow + 1).Value = StockCC
LastRow = ws.Cells(ws.Rows.Count, "E").End(xlUp).Row
ws.Range("E" & LastRow + 1).Value = ReceivingN
End If
Next StockCC
Next ReceivingN
Next StockValue
End Sub
You probably only want 1 standard for loop:
Private Sub SubmitCSR_Click()
Dim LastRow As Long
Dim ws As Worksheet: Set ws = Sheets("GP count")
Dim StockCaption(1 To 6) As String
'populate the array
StockCaption(1) = ToggleButton6.Caption
StockCaption(2) = ToggleButton2.Caption
StockCaption(3) = ToggleButton4.Caption
StockCaption(4) = ToggleButton5.Caption
StockCaption(5) = ToggleButton1.Caption
StockCaption(6) = ToggleButton3.Caption
Dim ReceivedV(1 To 6) As String
'populate the array
ReceivedV(1) = R1.Value
ReceivedV(2) = R2.Value
ReceivedV(3) = R3.Value
ReceivedV(4) = R4.Value
ReceivedV(5) = R5.Value
ReceivedV(6) = R6.Value
'loop through the entire array
Dim strNames(1 To 6) As Variant
'populate the array
strNames(1) = ToggleButton6.Value
strNames(2) = ToggleButton2.Value
strNames(3) = ToggleButton4.Value
strNames(4) = ToggleButton5.Value
strNames(5) = ToggleButton1.Value
strNames(6) = ToggleButton3.Value
'declare a variant to hold the array element
Dim i As Long
For i = 1 To 6
If StockCaption(i) = True Then
LastRow = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row
ws.Range("C" & LastRow + 1).Value = strNames(i)
LastRow = ws.Cells(ws.Rows.Count, "E").End(xlUp).Row
ws.Range("E" & LastRow + 1).Value = ReceivedV(i)
End If
Next i
End Sub
Related
I have been trying to match Date with week number i.e. ("B1:F1")
then date with Year-month i.e. ("A2:A500")
If matches then copy the value from this table that i have highlighted according to the date which is available in code where week is 2 and month is May-2021. Can someone please help me to achieve this.
There are multiple dates which i need to iterate with this table to get different values according to weeks and Year-Months.
Your help will be much appreciated.
Sub findMatchingRecords()
Dim rng1 As Range
Dim rng2 As Range
Dim ws As Worksheet
Dim getdate As String
Dim GetWeek As String
Set ws = Worksheets("Sheet1")
getdate = ws.Range("N1").Value
GetWeek = Int((Day(getdate) + 6) / 7)
Set rng1 = ws.Range("B1:F1")
Set rng2 = ws.Range("A2:A500")
For Each rng1cell In rng1
For Each rng2cell In rng2
If rng1cell = GetWeek And rng2cell = Format(getdate, "yyyy-mmm") Then
'Copy value and paste into Sheet1.Range("M2")
End If
Next rng1cell
Next rng2cell
End Sub
Here are the dates which needs to match with table and get relevant the value.
5/13/2021
5/16/2021
5/19/2021
5/22/2021
5/25/2021
5/28/2021
5/31/2021
6/3/2021
6/6/2021
6/9/2021
6/12/2021
6/15/2021
6/18/2021
6/21/2021
6/24/2021
Non-VBA Method
One way this could be done without using VBA is with a INDEX/MATCH formula.
The following formula assumes the data is in B2:F500, the month/years are in A2:A500, the weeks in B1:F1 and the dates to look for are in column N, all on the same sheet Sheet1.
=INDEX($B$2:$F$13,MATCH(TEXT(N1,"yyyy-mmm"),Sheet1!$A$2:$A$13,0),MATCH(INT((DAY(N1)+6)/7),Sheet1!$B$1:$F$1,0))
VBA Method
If you want VBA to do this here's one way.
Option Explicit
Sub findMatchingRecords()
Dim ws As Worksheet
Dim rngData As Range
Dim rngDates As Range
Dim arrData As Variant
Dim arrDates As Variant
Dim arrYearMonth As Variant
Dim arrValues As Variant
Dim arrWeeks As Variant
Dim Res As Variant
Dim idxCol As Long
Dim idxDate As Long
Dim idxRow As Long
Dim wk As Long
Set ws = Sheets("Sheet1")
With ws
Set rngData = .Range("A1").CurrentRegion
Set rngDates = .Range("N1", .Range("N" & Rows.Count).End(xlUp))
End With
With rngData
arrData = rngData.Offset(1, 1).Resize(.Rows.Count - 1, .Columns.Count - 1)
arrYearMonth = .Columns(1).Offset(1).Resize(.Rows.Count - 1)
arrWeeks = .Rows(1).Offset(, 1).Resize(, .Columns.Count - 1)
End With
arrDates = rngDates.Value
ReDim arrValues(1 To UBound(arrDates, 1), 1 To 1)
For idxDate = LBound(arrDates, 1) To UBound(arrDates, 1)
idxRow = 0
idxCol = 0
Res = Application.Match(Format(arrDates(idxDate, 1), "yyyy-mmm"), arrYearMonth, 0)
If Not IsError(Res) Then
idxRow = Res
wk = Int((Day(arrDates(idxDate, 1)) + 6) / 7)
Res = Application.Match(wk, arrWeeks, 0)
If Not IsError(Res) Then
idxCol = Res
End If
End If
If idxRow <> 0 And idxCol <> 0 Then
arrValues(idxDate, 1) = arrData(idxRow, idxCol)
End If
Next idxDate
rngDates.Offset(, 1).Value = arrValues
End Sub
Please, test the next code:
Sub MatchDate_WeekNo()
Dim sh As Worksheet, lastR As Long, arr, arrN, arrfin, i As Long, strDate As String
Dim weekN As Long, arrRow, arrCol, iCol As Variant, iRow As Variant, lastRN As Long
Set sh = Worksheets("Sheet1")
lastR = sh.Range("A" & sh.Rows.Count).End(xlUp).Row
lastRN = sh.Range("N" & sh.Rows.Count).End(xlUp).Row
arr = sh.Range("A1:F" & lastR).Value
arrRow = Application.Index(arr, 1, 0)
arrCol = Application.Transpose(Application.Index(arr, 0, 1))
arrN = sh.Range("N2:N" & lastRN).Value2
ReDim arrfin(1 To UBound(arrN), 1 To 1)
For i = 1 To UBound(arrN)
strDate = StringFromDate(CDate(arrN(i, 1)))
weekN = Int((Day(arrN(i, 1)) + 6) / 7)
iCol = Application.Match(weekN, arrRow, 0)
iRow = Application.Match(strDate, arrCol, 0)
If IsNumeric(iCol) And IsNumeric(iRow) Then
arrfin(i, 1) = arr(iRow, iCol)
End If
Next i
'drop the final array content:
sh.Range("O2").Resize(UBound(arrfin), 1).Value = arrfin
End Sub
Function StringFromDate(d As Date) As String
Dim arrM
Const strMonths As String = "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec"
arrM = Split(strMonths, ",")
StringFromDate = Year(d) & "-" & Application.Index(arrM, Month(d))
End Function
Format(arrDates(idxDate, 1), "yyyy-mmm") does not return the month in case of localization different then English type and only that's why I am using a function...
I have a bunch of formulae that is meant for specific (non-contiguous) ranges in my data. Is there any way to do this in less lines with an array and/or a loop?
.Range("R" & RowA).FormulaR1C1 = "=RC[-1]"
.Range("W" & RowA).FormulaR1C1 = "=(RC[-5]*RC[-7])+RC[-2]"
.Range("Y" & RowA).FormulaR1C1 = "=RC[-12]*RC[-2]"
.Range("R" & RowB).FormulaR1C1 = "=RC[-1]"
.Range("W" & RowB).FormulaR1C1 = "=(RC[-5]*RC[-7])+RC[-2]"
.Range("Y" & RowB).FormulaR1C1 = "=RC[-12]*RC[-2]"
.Range("R" & RowC).FormulaR1C1 = "=RC[-1]"
.Range("W" & RowC).FormulaR1C1 = "=(RC[-5]*RC[-7])+RC[-2]"
.Range("Y" & RowC).FormulaR1C1 = "=RC[-12]*RC[-2]"
I would store the rows in an array, then use Union to collect all the rows in a variable and Intersect that with each column.
This way you can access all defined rows of a specific column at once.
Option Explicit
Public Sub example()
Dim RowArr() As Variant
RowArr = Array(1, 3, 17) 'define your rows here
Dim AllRows As Range
With ActiveSheet
Dim Row As Variant
For Each Row In RowArr
If AllRows Is Nothing Then
Set AllRows = .Rows(Row)
Else
Set AllRows = Union(AllRows, .Rows(Row))
End If
Next Row
'write in all rows of a specific column
Intersect(.Columns("R"), AllRows).FormulaR1C1 = "=RC[-1]"
Intersect(.Columns("W"), AllRows).FormulaR1C1 = "=(RC[-5]*RC[-7])+RC[-2]"
Intersect(.Columns("Y"), AllRows).FormulaR1C1 = "=RC[-12]*RC[-2]"
End With
End Sub
Instead of the loop you can also write:
Set AllRows = .Range("1:1,3:3,17:17")
like
Option Explicit
Public Sub example()
With ActiveSheet
Dim AllRows As Range
Set AllRows = .Range("1:1,3:3,17:17")
'write in all rows of a specific column
Intersect(.Columns("R"), AllRows).FormulaR1C1 = "=RC[-1]"
Intersect(.Columns("W"), AllRows).FormulaR1C1 = "=(RC[-5]*RC[-7])+RC[-2]"
Intersect(.Columns("Y"), AllRows).FormulaR1C1 = "=RC[-12]*RC[-2]"
End With
End Sub
but this works only for a smaller amount of rows. If you have more you need to use Union
Yes, although I suspect not quite in the way you're thinking. Use an array instead of separate variables RowA, RowB and RowC, so you'd replace
Dim RowA as Long, RowB as Long, RowC as Long
RowA = 1
RowB = 3
RowC = 7 'example figures
With -
Dim Row(1 to 3) as Long
Row(1) = 1
Row(2) = 3
Row(3) = 7
Then your above code can be shortened to the following loop:
For a = Lbound(Row) to Ubound(Row)
.Range("R" & Row(a)).FormulaR1C1 = "=RC[-1]"
.Range("W" & Row(a)).FormulaR1C1 = "=(RC[-5]*RC[-7])+RC[-2]"
.Range("Y" & Row(a)).FormulaR1C1 = "=RC[-12]*RC[-2]"
Next
Maybe something like this:
Sub Test()
Dim letters, rows, i, letter, row
letters = Array("R", "W", "Y")
rows = Array(1, 5, 17) 'RowA, RowB, and so on...
i = 0
j = 0
For Each row In rows
For Each letter In letters
Debug.Print letters(i) & rows(j)
' .Range(letters(i) & rows(i)).FormulaR1C1 = "=RC[-1]"
' .Range(letters(i) & rows(i)).FormulaR1C1 = "=(RC[-5]*RC[-7])+RC[-2]"
' .Range(letters(i) & rows(i)).FormulaR1C1 = "=RC[-12]*RC[-2]"
i = i + 1
Next letter
j = j + 1
i = 0
Next row
End Sub
Using 'Helper' Procedures
Option Explicit
Sub UsingRefRows()
Const RowA As Long = 1
Const RowB As Long = 3
Const RowC As Long = 5
Dim ws As Worksheet: Set ws = Sheet1
Dim rrg As Range: Set rrg = RefRows(ws, RowA, RowB, RowC)
Intersect(rrg, ws.Columns("R")).FormulaR1C1 = "=RC[-1]"
Intersect(rrg, ws.Columns("W")).FormulaR1C1 = "=RC[-5]*RC[-7]+RC[-2]"
Intersect(rrg, ws.Columns("Y")).FormulaR1C1 = "=RC[-12]*RC[-2]"
End Sub
Sub UsingRefRowsAndWriteRowsR1C1()
Const RowA As Long = 1
Const RowB As Long = 3
Const RowC As Long = 5
Const ColumnsList As String = "R,W,Y"
Const FormulasList As String _
= "=RC[-1]" & "," _
& "=RC[-5]*RC[-7]+RC[-2]" & "," _
& "=RC[-12]*RC[-2]"
Dim ws As Worksheet: Set ws = Sheet1
Dim rrg As Range: Set rrg = RefRows(ws, RowA, RowB, RowC)
WriteRowsR1C1 rrg, ColumnsList, FormulasList
End Sub
Function RefRows( _
ByVal ws As Worksheet, _
ParamArray DataRows() As Variant) _
As Range
Dim rg As Range
Dim n As Long
For n = 0 To UBound(DataRows)
If rg Is Nothing Then
Set rg = ws.Rows(DataRows(n))
Else
Set rg = Union(rg, ws.Rows(DataRows(n)))
End If
Next n
If Not rg Is Nothing Then
Set RefRows = rg
End If
End Function
Sub WriteRowsR1C1( _
ByVal RowsRange As Range, _
ByVal ColumnsList As String, _
ByVal FormulasList As String)
Dim Cols() As String: Cols = Split(ColumnsList, ",")
Dim Formulas() As String: Formulas = Split(FormulasList, ",")
Dim ws As Worksheet: Set ws = RowsRange.Worksheet
Dim n As Long
For n = 0 To UBound(Cols)
Intersect(RowsRange, ws.Columns(Cols(n))).FormulaR1C1 = Formulas(n)
Next n
End Sub
with the given code I am trying hard incorporate the Filldown approach until the last row but at present whatever I do only fills row number 1:
Sub FillDownApproach()
Dim destinationWs As Worksheet
Dim destinationLastRow As Long
Set destinationWs = ThisWorkbook.Worksheets("Main Board")
destinationLastRow = destinationWs.Range("A" & Rows.Count).End(xlUp).Row
RetVal = destinationWs.Evaluate("INDEX('MyData'!$E:$E,MATCH(1,($A2='MyData'!$B:$B)*(""MyItem""='MyData'!$D:$D),0))")
destinationWs.Range("C2").Value = RetVal
destinationWs.Range("C3: " & "C" & destinationLastRow).FillDown
End Sub
Any suggestion that could point towards the right direction.
Thanks
You cannot do what you want without looping. And Looping ranges is slow.
Instead load Variant arrays and loop them.
Sub FillDownApproach()
Dim destinationWs As Worksheet
Set destinationWs = ThisWorkbook.Worksheets("Main Board")
Dim destinationLastRow As Long
destinationLastRow = destinationWs.Range("A" & Rows.Count).End(xlUp).Row
Dim lkpArr As Variant
lkpArr = destinationWs.Range("A2:A" & destinationLastRow).Value
With Worksheets("MyData")
Dim retval As Variant
retval = Intersect(.Range("E:E"), .UsedRange)
Dim mtch As Variant
mtch = Intersect(.Range("B:D"), .UsedRange)
End With
Dim outArr As Variant
ReDim outArr(1 To UBound(lkpArr, 1), 1 To 1)
Dim i As Long
For i = 1 To UBound(lkpArr, 1)
Dim j As Long
For j = 1 To UBound(retval, 1)
If mtch(j, 3) = "MyItem" Then
If mtch(j, 1) = lkpArr(i, 1) Then
outArr(i, 1) = retval(j, 1)
Exit For
End If
End If
Next j
Next i
destinationWs.Range("C2").Resize(UBound(outArr, 1), 1).Value = outArr
End Sub
Hi I am trying to update cell values on all rows until the row number changes. Here is my code:
Sub MyLoop()
Dim i As Integer
Dim var As String
Dim LastRow As Long
LastRow = Range("A" & Rows.Count).End(xlUp).Row
i = 1
var = Cells(i, 4).Value
For i = 1 To LastRow
If Range("A" & i).Value = "1" Then
Cells(i, 2).Value = var
End If
var = Cells(i, 4).Value
Next i
End Sub
I have attached before and after images of how it should look once routine has been ran. Basically Loop through all rows and in column A is the number changes store the value in column D and paste it into column B until the row number changes.
Before:
After:
Kind Regards
Is it really when the number changes or when the word in Column D changes?
Columns("D:D").Cut Destination:=Columns("B:B")
Range("B1:B" & Cells(Rows.Count, "A").End(xlUp).Row).SpecialCells(xlCellTypeBlanks).FormulaR1C1 = "=R[-1]C"
Range("B1:B" & Cells(Rows.Count, "A").End(xlUp).Row).Value = Range("B1:B" & Cells(Rows.Count, "A").End(xlUp).Row).Value
Sub MyLoop()
Dim i As Integer
Dim var As String
Dim LastRow As Long
LastRow = Range("A" & Rows.Count).End(xlUp).Row
For i = 1 To LastRow
IF Cells(i, 4).Value<>"" Then 'Get new value from column 4
var = Cells(i, 4).Value
End If
Cells(i, 2).Value = var 'Assign value to column 2
Next i
End Sub
Fill Column
A Quick Fix
Sub MyLoop()
Dim LastRow As Long
Dim i As Long
Dim A As Variant
Dim D As Variant
LastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 1 To LastRow
If Cells(i, 1).Value <> A Then
A = Cells(i, 1).Value
D = Cells(i, 4).Value
End If
Cells(i, 2).Value = D
Next i
End Sub
A More Flexible Solution
Adjust the values in the constants section.
Option Explicit
Sub fillColumn()
' Define constants.
Const wsName As String = "Sheet1"
Const ColumnsAddress As String = "A:D"
Const LookupCol As Long = 1
Const CriteriaCol As Long = 4
Const ResultCol As Long = 2
Const FirstRow As Long = 2
' Define Source Range.
Dim rng As Range
With ThisWorkbook.Worksheets(wsName).Columns(ColumnsAddress)
Set rng = .Columns(LookupCol).Resize(.Rows.Count - FirstRow + 1) _
.Offset(FirstRow - 1).Find( _
What:="*", _
LookIn:=xlFormulas, _
SearchDirection:=xlPrevious)
If rng Is Nothing Then
Exit Sub
End If
Set rng = .Resize(rng.Row - FirstRow + 1).Offset(FirstRow - 1)
End With
' Write values from Source Range to Data Array.
Dim Data As Variant: Data = rng.Value
' Define Result Array.
Dim Result As Variant: ReDim Result(1 To UBound(Data, 1), 1 To 1)
' Declare additional variables.
Dim cLookup As Variant ' Current Lookup Value
Dim cCriteria As Variant ' Current Criteria Value
Dim i As Long ' Rows Counter
' Write values from Data Array to Result Array.
For i = 1 To UBound(Data, 1)
If Data(i, LookupCol) <> cLookup Then
cLookup = Data(i, LookupCol)
cCriteria = Data(i, CriteriaCol)
End If
Result(i, 1) = cCriteria
Next i
' Write from Result Array to Destination Column Range.
rng.Columns(ResultCol).Value = Result
End Sub
I am trying to program a Search button to look through all the data, return all rows with the common Number and all the date which is 9 columns of data, then populate and print the sheet with this data. the code is continuously giving me errors, any help is appreciated.
Dim erow As Long
Dim ws As Worksheet
Dim Lastrow As Long
Dim count As Integer
With Worksheets("DataSheet")
Lastrow = .Cells(.Rows.count, 1).End(x1Up).Row
For x = 1 To Lastrow
If Sheets("DataSheet").Cells(x, 1) = SearchSheet.Range("B4") Then
SearchSheet.Range("A12") = Sheets("DataSheet").Cells(x, 1)
SearchSheet.Range("B12") = Sheets("DataSheet").Cells(x, 2)
SearchSheet.Range("C12") = Sheets("DataSheet").Cells(x, 3)
SearchSheet.Range("D12") = Sheets("DataSheet").Cells(x, 4)
SearchSheet.Range("E12") = Sheets("DataSheet").Cells(x, 5)
SearchSheet.Range("F12") = Sheets("DataSheet").Cells(x, 6)
SearchSheet.Range("G12") = Sheets("DataSheet").Cells(x, 7)
SearchSheet.Range("H12") = Sheets("DataSheet").Cells(x, 8)
SearchSheet.Range("I12") = Sheets("DataSheet").Cells(x, 9)
End If
Next x
End With
Hard to see the difference between one and L but x1Up should be xlUp. All the results are being written to the same row 12, you need to use an incrementing counter.
Private Sub CommandButton1_Click()
Const SEARCH_CELL = "B4"
Const START_ROW = 12
Dim wb As Workbook, wsSource As Worksheet, wsTarget As Worksheet
Set wb = ThisWorkbook
Set wsSource = wb.Sheets("DataSheet")
Set wsTarget = wb.Sheets("SearchSheet")
Dim iRow As Long, iLastRow As Long, iTargetRow As Long
Dim sSearchTerm As String, res As Variant
iTargetRow = START_ROW
sSearchTerm = wsTarget.Range(SEARCH_CELL)
' clear results sheet
wsTarget.Range("A" & START_ROW & ":I" & Rows.count).Cells.Clear
'search
With wsSource
iLastRow = .Cells(.Rows.count, 1).End(xlUp).Row
For iRow = 1 To iLastRow
If .Cells(iRow, 1) = sSearchTerm Then
.Range("A" & iRow).Resize(1, 9).Copy wsTarget.Range("A" & iTargetRow)
iTargetRow = iTargetRow + 1
End If
Next
End With
' results
With wsTarget
.PageSetup.PrintArea = .Range("A1").Resize(iTargetRow - 1, 9).Address
res = MsgBox(iTargetRow - START_ROW & " Rows found, do you want to print results ?", vbYesNo, "Finished")
If res = vbYes Then
' print
.PrintOut Copies:=1
End If
End With
End Sub