How to loop over a multi-row/column range per column using Excel 2007 VBA? - vba

I'm looping to loop over a range with multiple rows and columns using Excel 2007 VBA.
I'm specifically trying to loop over a user selected range, and perform a calculation on each column in the range, and output the calculation two rows below each column.

You can retrieve the currently selected range by using
Application.Selection.Address
This will give you a range value (the Selection property returns a Range object) that will look something like "$B$4:$J$20".
Given you now have a range to work with, you can iterate across each column using something like:
For Each col In userSelectedRange.Columns
...
Next
The Columns property again returns a Range object that you can either iterate over further or perform other calculations on (your exact needs aren't too clear from your question).
To post the calculated result two rows above each column (e.g. a subtotal or similar), try using the Offset function:
Cells.Offset(-2, 0)
If you're able to provide more specifics around the sort of calculation you want, I may be able to add more detail into how you achieve it.

Related

VBA : re-sort/re-order rows based on column values through specific range

I'm fairly new to VBA, and have found this to be a great resource. I understand enough to generally find someone else's code and modify it to what I need it to do, but I've been stumped here. I've tried coding this several times in different ways, but can't seem to get it to work, and am not overly convinced I'm approaching it the right way to start with. I'm hoping someone is willing to help me.
Here's a theoretical example of what I'm trying to do.
I have a sheet that contains groups of orders of a certain product type with their quantities listed by the step of the process they're currently at:
Current orders in process
I need to "sort" them or re-order them so that:
1. The orders are copied into a tab based on process step, with the furthest process step being listed first working back to the closest, and...
2. Orders listed in the "complete" step need to be excluded completely, and...
3. I need to do this for multiple product types, which have different numbers of process steps, so the end column needs to be identified somehow (as a dynamic variable, or some trigger)
For the example, it would look like this:
Sorted data
I've thought through a half-dozen ways to logically go about this and tried to figure out how to then do that with code, but I'm stuck ... and I have the feeling that there is probably 1 or 2 "best" ways to go about this that someone in this community probably knows off the top of their head. Thank you in advance.
Edit: Here's my first attempt at coding the outline. I realize there are some components missing, but would love feedback on whether this seems to be a usable, or efficient approach.
Sub test1()
Dim skuStartRow As Long, skuEndRow As Long
Dim qty As Integer
Dim colCheck as long, lastCol as Long
skuStartRow = .Range("A:A").Find(what:=sku, after:=.Range("A1")).Row
skuEndRow = .Range("A:A").Find(what:=sku, after:=.Range("A1"), searchdirection:=xlPrevious).Row
' Code here to identify last column (lastCol) either by .UsedRange or by header?
For colCheck = 3 To lastCol
For rowCheck = skuStartRow To skuEndRow
qty = Cells(rowCheck, colCheck).Value
If qty <> "" Then
'copy current row and paste into destination worksheet
MsgBox qty 'test to see if correct qty is displayed
End If
Next rowCheck
Next colCheck
End Sub
Update:
Still having problems.
I've copied/pasted the whole range of orders based on product type to a new sheet where it will be sorted.
I've inserted a column and used the match/index formula provided by Variatus (autofill down) to create an index column.
Insert new column and use RANK function to create a rank ordered list, as there are duplicates in the Helper/Index column.
Used INDEX/MATCH functions to return values into rank ordered lists for both work order number and quantity value.
The code I currently have works - except that it's hard-coded using FormulaRICI = ... commands. I'm having major challenges figuring out how to convert the code to allow use of MATCH/INDEX functions with variables. I need to do this b/c depending on product type there are varying amounts of total orders, as well as varying amounts of number of steps; so I need to have a dynamic range for both rows/columns.
I've looked at a bunch of examples but can't seem to find something that works correctly. The most promising I've seen appears to be using the "replace" function in VBA, but my head's about to explode.
Any suggestions are much appreciated.
I wonder if you really need VBA for this. Please consider these steps.
Insert a column in your worksheet with this formula in row 2, copied down.
=IFERROR(MATCH(TRUE,INDEX($D2:$I2<>0,0),0),0). The range D2:I2 is defined by D2 = Step 1 and I2 = "Complete". The formula finds the first non-blank cell in the range. The column could be hidden.
Sort the sheet on the helper column, largest to smallest.
Apply a filter.
Filter on the product.
What you see at this point is the list you wish to create using VBA, however including the 'Complete' column and any other columns to the right of it.
There are a number of ways of automating this process. You might write code to either insert the formula in the helper column automatically or its result. This could be done when needed, without having a permanent extra column. You could write code to do the sorting and filtering automatically, for example, based on a currently selected product. And, finally, you might write code to copy the result to another sheet, remove the unwanted columns there, and restore the original sheet to its original condition (presumably sorted by order number).

Need VBA script to extend Excel table every week

The problem is as follows: I have several tables in Excel with given number of raws and dynamic number of columns (each week a new column should be added, currently I'm doing it manually). I want to automate it and create a script that will extend every raw range to the next column (namely the range from A2 to C2 should become from A2 to D2), and so on (such that running script N times will result in extending a table to N columns further). By "extending" I mean extending formulas, since each cell in my tables contains any formula. Is there any way to do it via VBA?
I can't just record the corresponding macro because I have now idea how to specify that I don't want to link it with any specific range, but instead always extend just to one column right.
Any help and examples will be very appreciative.
You dont need VBA to do this. Use dynamic defined names and reference them in your formulas. For example, if you add a named range and add this in the refersTo dialog
=OFFSET($A$1,0,0,COUNTA($A:$A),COUNTA($1:$1)
your range will automatically expand from cell A1 (as long as there are no blank cells in column A or Row 1). You can then use that named range in your formulae.
More here http://www.excel-easy.com/examples/dynamic-named-range.html

Delete Entire Row in Specific sheet Based on a value in Excel VBA

I have a relatively long subroutine that calls two external subs. In the sub, on one sheet=Start, VBA copies an account number and stores it under the variable name Acct (formatted as string). At the end of the sub, I would like VBA to activate another sheet=Stop, match Acct with a value in Column A (which is formatted as a number), then delete the entire row containing that number. I am just needing some assistance with finding and deleting the entire row containing that number.
It may also be worth mentioning that the numbers in column A are not in numerical order. Also, both sheets are located in the same workbook, we can call WB1.
Try Match function, which will return the row number as an integer variable. Then use Rows(row number).Delete
https://mysyntaxvba.wordpress.com/2016/08/16/what-is-the-syntax-to-return-the-row-of-a-found-value/

vba excel AdvancedFilter method for a table with dates criteria does not work

first af all i'm glad to enjoy this nice community, this is my first post so apologize me in advance for any mistake i'll do in the post.
I got a table named example generated by importing data from an access file, so the number of rows changes dynamically...I'm trying to apply the AdvancedFilter method to this table via VBA.
I've used the first row of the sheet for copying the header of the table and in the second row i set my parameters for filtering, so in the range A1:D2 i got the criteria. Starting from row 5 i have the table example: it starts with a header row and goes on with all the rows of data, all imported from the access file, for example a range A5:D20.
If i apply the advanced filter manually (click on the advanced filter button and fill the form) specifying the range of the table A5:D30 and the range of the criteria A1:D2 it works fine...but if instead of specifying the range of the data i use the name of the table example the result is different, just one row instead of the five (right) rows i expect...why?!?
Now, if the question above is just for curiosity (but i'm sure it's connected with my problem), the main problem is that i'm trying to do the same thing via VBA code. I tried
Worksheets("name").Range("example[#All]").AdvancedFilter _
Action:=xlFilterInPlace, CriteriaRange:=Range("A1:D2"), Unique:=False
and
Worksheets("name").ListObjects("example").Range.AdvancedFilter _
Action:=xlFilterInPlace, CriteriaRange:=Range("A1:D2")
but both don't work: the filtering action didn't return no lines.
Even if i try
Worksheets("name").Range("A5:D30").AdvancedFilter _
Action:=xlFilterInPlace, CriteriaRange:=Range("A1:D2"), Unique:=False
specifying manually the range (not a solution for my problem because the range changes dynamically, but for test purpose...) the problem persists, the code didn't return no lines.
Note: if i select the range in the codes above instead of AdvancedFilter it the selection is correct: the entire table with the header
The first code is the same automatically written if i start recording a macro, do the filtering manually, and stop recording the macro (code written exactly with the table reference)...the wierd thing is that when i manually do the operation (while recording the macro) it filters correctly, but if i start the macro just recorded...nothing, same as if i run the code written above.
If i open the formula->names tab i can find the example table but the range specifyed is not starting from row 5 but from 6...it's like the header is not considered, don't know why...but it's automatically generated with the importation of the data so i don't know how to change the range keeping the reference to the imported data...maybe is this the issue?!?
Don't know how to solve the problem, please help me :)
Edit:
Two of the criteria i'm using for filter are date criteria, specifically: date <= xx/yy/zzzz and date >= aa/bb/cccc and the problem it's exactly this...if i try the three codes above filtering with a string criteria, they works, if i use them with the dates criteria, they don't. So i guess the problem depends on how VBA hands the dates data types. Any suggestion?
The cells used for criteria contain this formula ("SE" is the italian version of "IF"):
=SE(filtro!F2="";"";">="&filtro!F2)
=SE(filtro!F3="";"";"<="&filtro!F3)
i take the criteria from another sheet ("filtro") and if the cell is filled i report the data inserted with <= or >= for the criteria, otherwise the cell remains empty for don't set any condition.
Thanks
Ettore
Try this below steps. It is working for me.
First we should create a named range (Define Name) (call it is Table),give the range as dynamic using the formula =OFFSET(Sheet1!A5,0,0,COUNTIF(Sheet1!$A$5:$A$100,"<>"),4).
Paste this offset formula while creating the name range - Table.
This formula will changes the range dynamically.
Write VBA code as below
Sub Advanfil()
'
' Advanfilt Macro
'
'
Range("Table").AdvancedFilter Action:=xlFilterInPlace, CriteriaRange:= _
Range("A1:D2"), Unique:=False
End Sub
I think the above should ease ur difficulty.
Ok, finally i fix the issue and whant to share the solution.
As i mentioned in the edit of my question, two criteria of the filter are dates, i found two problems and both are connected with this:
When i imported the data from other source (access file) and populated the table that i was going to filter i did not set the appropriate format to the fields, i left all as excel decided and this was a problem. The correct way is to set:
The fields in the table (the ones with the data to be filtered) as date with a preformatted format (not simple for me because they were stored as text in the access so i must made a SQL string for extract data in the correct type and format).
The field where store the condition for the filter as general (in my case this field contains the formula mentioned int the edit of my question).
The field where i insert the dates for filtering (the one referenced in the formula) as date with the same format as the fields of the table (point 1.).
The formula mentioned in the edit of my question looks at a cell (where i insert the date) and, if this cell is filled, returns something like <=data-inserted or >=data-inserted (and this is OK) BUT when nothing is inserted in the cell returns "". For a string criteria in the filter this is ok, but for a date criteria is not, this causes the filter to don't find nothing with "" in the table fields filled with dates. I tryed to use null value or other similar values but i couldn't find what is nothing for a date criteria...so the workaround i used is to return <=31/12/2100 or >=01/01/1900 when i don't whant to limit the grater or the lower dates.
Hope this could help someone.
Ettore
Fill CRITERIA for null or "" cell in date-formatted field with just an equal sign =
Excel Advanced Filter understands that means BLANK cell

Accessing Certain Column in a Range

I am trying to access column 2 in a specific range, and then counting the cells with constants in them. Right now what I have is accessing the range, but not a specific column in the range, but rather the entire range... thus counting too many constants.
X = Range("MAIN_LIST").Cells.SpecialCells(xlCellTypeConstants).Count
Is there a way for me to access a specific column in this range? I tried to do this somehow with:
X = Range("MAIN_LIST").Column(2).Cells.SpecialCells(xlCellTypeConstants).Count
but am getting a syntax error. Anyone know the specific syntax to do this?
Thanks.
Try just:
Range("MAIN_LIST").Columns(2).SpecialCells(xlCellTypeConstants).Count
The method is Columns, not Column.
http://msdn.microsoft.com/en-us/library/office/ff837125(v=office.14).aspx
Also, while it's not an error: Using the method Cells is redundant/unnecessary, the Range object itself already is comprised of its Cells, and likewise any particular column in that range is also comprised of its Cells :)