I have a macro that copies a row(s) from one "master" worksheet up to several other worksheets based on a set of rules, but not every row will be copied to every worksheet. So I have a set of variables which serve as "counters" for each row on the different worksheets so that I can keep track of the current row and not overwrite any rows on any given worksheet. This leads to a lot of ugly code similar to the following.
.Rows(material.Row).Copy Destination:=Worksheets("QM").Range("A" & QMCounter)
I would like to make this into a single sub that I can call where I pass it the row number from the master worksheet, the intended worksheet and then the counter variable for the worksheet.
What I would like to do is create an array of the different counter variable names so that I could do something similar to the following
For i = 0 to Ubound(VarNameArray)
Counter = VarNameArray(i)
Call CopyRow(Material, DestWorksheet, Counter)
Next i
My problem is translating the string value of the variable name into the actual variable name so that VarNameArray(i) can become not the string "QMCounter" but the variable QMCounter. Since not every row from the "master" worksheet will be copied to every other worksheet, I need to be able to control the value of each counter variable independently. Is this possible with VBA?
Edit: This aim of this spreadsheet is to look at specific cell values in rows on the "master" sheet and then based on those values, copies that row to a combination of 10 "subordinate" worksheets. So, for example, Row 1 of the "master" sheet may be copied only to subordinate sheet 9, but Row 2 of the master sheet may be copied to subordinate sheets 1, 2, 3, 6, 7, 9 and 10. Then Row 3 may be copied to a different set of subordinate sheets. It all depends on values of specific cells, which I do not know in advance.
I have counter variables for each of the 10 subordinate sheets to keep track of the current row and make sure that I do not simply keep copying everything to the first row on that sheet. Call them Sheet1 through 10 and Counter1 through 10, Sheet1 and Counter1 being linked on through 10. So if I copy a row from the master sheet to Sheet1, and only if I copy from the master sheet to Sheet1, I increment Counter1. However, as I have already stated, the specific subordinate sheets a row is copied to is determined at run time based on values of specific cells filled in by the users.
So I want to take a highly repetitive bit of code like
.Rows(material.Row).Copy Destination:=Worksheets("Sheet1").Range("A" & Counter1)
.Rows(material.Row).Copy Destination:=Worksheets("Sheet3").Range("A" & Counter3)
.Rows(material.Row).Copy Destination:=Worksheets("Sheet4").Range("A" & Counter4)
where 99% of the code is the same, with something cleaner and more generic.
There's no need for an array of variable names when you can just use an array directly...
Dim Counters
Counters = Array(1,2,3,4,5)
For i = LBound(Counters) to Ubound(Counters)
CopyRow Material, DestWorksheet, Counters(i)
Next i
EDIT: if you're just appending new rows below any existing ones:
.Rows(material.Row).Copy _
Destination:=Worksheets("Sheet1").Cells(Rows.Count,1).End(xlUp).offset(1,0)
Works as long as there's always a value in ColA for any copied row.
Related
This is the formula I'm using to get the value of an indirectly referenced cell in another worksheet:
=OFFSET(INDIRECT("'"&SheetName"'!$A$1");Row;Col)*BooleanValue
As you can see I add a specific cell (referenced Row and Col) from the also referenced SheetName and then, that value is multiplied by 1 or 0. This is needed because the need to add a specific worksheet changes.
When extending this to more than one worksheet, I copied and added this same formula 10 times for the 10 Sheets I need to take in account, but the formula becomes too long and difficult to read or edit and being used to array formulas I think there is surely a better way but I don't know how to do it.
In the forum I've seen solutions to filter the cells in different to be added but I don't see the way to adapt them to my situation as I sum the cells from 10 worksheets and multiply them by an array of boolean values.
Thank you very much in advance for any help.
Enrique
Before I begin, I know all of this can be accomplished with a SQL query. Just take my word that currently building an active directory is in the works, but right now this is what i have:
An excel spreadsheet of about 30k rows with about 25 columns with a list of items, using the item # as the level 1 match. Let's call it the "master" sheet.
The item #'s, which are unique identifiers, may appear multiple times, i.e.:
Item # 10000 can appear multiple times in this sheet.
So I created a dynamic array, and inserted the entire master sheet into the array using
Sub Items()
Dim Items() As Variant
Sheets("Master").Activate
Items = Range("A3", "AL" & Range("a1").End(xlDown).Row)
End Sub
The user will be on another sheet within the workbook ("itemlist"), and will enter some items they need like this: Item List
I need all occurrences (whether it be a single or duplicate value) of each of the items in the "Master" to output to individual rows on another sheet.
I'm stuck how to achieve this in VBA. I'm finding it difficult to find examples of this.
Would i want to sort the array first to make finding the duplicates faster? Should I turn the user created list into a single dimensional array and try to find intersecting points with the 2d array? I'm not sure where to start after the creation of the "master" array.
The reason I'm using arrays instead of a bunch of index matching or iterative looping in the "Master" sheet is because the processing power/physical memory available will be inconsistent due to computing environment, so arrays seem to be the most efficient method to avoid some users taking several minutes for return values if it can process at all.
What do you mean 'may appear multiple times'? It sounds like you need xto group and sum, as you would in a database (Access or SQL Server) or do some ranking and pick the highest/lowest element in the array. Or, are you saying you want to copy/paste certain element in your array to a new sheet???
Let's say you want to copy items in column B, which have a value of 'x', and paste them into another sheet, well, just run the script below.
Sub CopyData10()
Dim Rng As Range, cell As Range
Dim rw As Long
Set Rng = Worksheets("Sheet1").Range("B1:B10")
rw = 1
For Each cell In Rng
If LCase(cell.Value) = "x" Then
Worksheets("Sheet2").Cells(rw, "A") = cell.Offset(0, -1)
rw = rw + 1
End If
Next
End Sub
Ok so I ahve too worksheets and I am pulling in data from one worksheet to another I am using array in the form
=TRANSPOSE('Z:\MI 2015\[MIdata.xlsx]Capital'!F452:F462)
Now I my VBA is password protected and to be honest I don't want use VBA
The cells change every 11th cell(from first elememt) for range 10 cells long in array for next row in worksheet to pulled out e.g.
=TRANSPOSE('Z:\MI 2015\[MIdata.xlsx]Capital'!F463:F473)
is next row in worksheet and so forth in that fashion.
So how can I run a loop to update new cell references to automate this data extract?
I have a range with 170000 rows in it. I'm filtering column A for a single value and returning the corresponding values in column B.
I want these values to dump into an array so I can quickly toss them into a dictionary (with the key being the value I filtered column A with).
The problem is that SpecialCells(xlCellTypeVisible) is acting inconsistent.
If I do the same test on a smaller range, the values dump into the array just fine. But with a range as large as mine, it only returns the first value in the range. Also, I can use the same line to copy to another sheet. I just can't get it to populate the array.
foo = ws1.Range(tbl1Name & "[ID]").SpecialCells(xlCellTypeVisible)
Works with small ranges, but returns only the first result in a range as large as mine (less than 50 results.) foo becomes an array containing all the variables.
ws1.Range(tbl1Name & "[ID]").SpecialCells(xlCellTypeVisible).Copy ws2.Range("A1")
Works with the large range and copies all the relevant data successfully.
So my question: How do I populate the array without the extra step of copying to a blank worksheet when autofiltering a large table range? (Excel 2013)
EDIT: requires a reference to "Microsoft Forms 2.0 Object Library" (should be near the top of the list of available references). Or add a userform to your project and that will auto-add the reference (you can then remove the form...)
This should work for a single column:
Sub Tester()
Dim rng, txt As String, cb As New DataObject, arr
Set rng = ActiveSheet.Range("A2:A28").SpecialCells(xlCellTypeVisible)
rng.Copy
DoEvents
cb.GetFromClipboard
txt = cb.GetText
arr = Split(txt, vbCrLf)
Debug.Print LBound(arr), UBound(arr)
End Sub
If you had multiple columns you'd need to loop over each element of arr (splitting its value on tab) and transfer the values to a 2-d array.
When you create an array from a selection in excel it ignores the fact that some rows are hidden.
For example if you have data in columns A, B, and C and column B is hidden, the array still has 3 columns and 4 rows.
Is there a way to either
Drop columns or rows from the array once it's created or... I.e. drop column B
tell the array to consider only the non hidden columns when it;s being formed (so it would only consider column A, C.
Some code to illustrate what I want
dim v as variant
Range("A2:C4").Select
v = selection
the selection is now 3 columns wide by 4 rows deep. I just want the two columns in the selection which are not hidden.
The only two ways I can think of to do that are
(1) drop something from the original selection
(2) not select the hidden columns in the first place.
maybe I can select a non-contiguous range and then turn that into an array?
You can accomplish this by
create a temporary worksheeet
copy the "visible" cells to the temporary sheet
read the cells into a vba array
delete the temporary sheet.
Assume on Sheet2 you have data in A1:C4 with column B hidden.
The following code will result in V being a 2D array (1 to 4, 1 to 2) containing the data from only columns A and C.
Option Explicit
Sub arrUnHidden()
Dim R As Range
Dim V As Variant
Dim wsTemp As Worksheet
Set R = Worksheets("Sheet2").Range("A1", Cells(Rows.Count, "C").End(xlUp))
Worksheets.Add
ActiveSheet.Name = "Temp"
Set wsTemp = Worksheets("Temp")
R.SpecialCells(xlCellTypeVisible).Copy wsTemp.Cells(1, 1)
V = wsTemp.UsedRange
Application.DisplayAlerts = False 'suppress message when deleting a sheet
Worksheets("temp").Delete
Application.DisplayAlerts = True
End Sub
Several points:
0: Do you mean actual arrays or do you mean named ranges? Visual Basic has arrays, excel has ranges. For the purposes of this answer, I will assume that you mean named ranges, as you cannot delete items from array without resizing the array.
1: There are ways to delete rows and columns from excel, or move ranges to not include certain elements. They are too numerous to mention here, but ThisRange.Columns(1).Delete or .Offset are both options.
2: Instead of changing what the range contains, I would use a for each loop that takes into account the cell properties.
As the comment suggested, more information would enable a greator tailoring of this answer.