Difference between filtering range and table - vba

Can someone explain why there is a difference between filtering a range and a table? I get the difference between the two, but I dont see why a range filter cannot filter the underlying data when its formatted as a table.
I've been having issues filtering files due to the difference. I am consolidating x number of user files with the same headers. However, some people (thanks a lot, Charles across the hall) decide to format as a table which is causing issues.
Is there a universal way (or more effective way) to filter data that is independent of the format? As an example, I am trying to filter for text "NORAM" in Col A, and then copy/paste visible cells elsewhere.
Do I need to do something like this?
If Range("A1") is range Then
Filter Range("A1") with range method ("NORAM")
Copy Visible Cells
Paste to Destination
Else
Filter Range("A1") with table method ("NORAM")
Copy Visible Cells
Paste to Destination
End If
Or is there a way to do something like this, which is independent of range or table?
Range("A1") filter range regardless of format ("NORAM")
Copy Visible Cells
Paste to Destination
I do not need help copying or pasting data. The above are just generic steps. I'm hoping to see the most effective way to filter a range, a table, and hopefully a way to filter both regardless of format.

I'm not sure what error you're getting but here's a quick filter, tested on both a table (Sheet1) and a range not formatted as a table (Sheet2).
Option Explicit
Private Sub FilterTableOrRange(ws As Worksheet)
Dim lastRow As Long, lastCol As Long
With ws
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
lastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
.Range(.Cells(1, 1), .Cells(lastRow, lastCol)).AutoFilter _
Field:=1, Criteria1:="NORAM"
End With
End Sub
Sub Master()
FilterTableOrRange Sheets("Sheet1")
FilterTableOrRange Sheets("Sheet2")
End Sub
If this is not helpful, then please specify the exact issues you've had.

Related

Excel VBA Dynamic Range / Loop issue

I am developing a financial model for a bank and come across the below issue which I am not able to resolve in Excel VBA, and would appreciate your help.
I have built a simple macro which essentially does two things: (i) it clears contents in a given range, (ii) it populates the same range with a formula. In a very abbreviated way it looks like the following:
Sub AutoCalculateCashFlows()
Range(D208:L208).ClearContents
Range("L208").FormulaR1C1 = "=+R[-34]C-R[-34]C[-1]"
Range("L208").AutoFill Destination:=Range("E208:L208"), Type:=xlFillDefault
End Sub
My problem is that the range that should be auto populated is dependent on how many cells did the user fill in within the range of E10:L10. Users will start populating this range from right to left, but I don't know how far they will go from column L to the left. The formula that my macro auto populates needs at least two data, ie. at least L10 and K10 should be populated and if the latter is the case then the macro only needs to auto populate L208 with formula, in case J10:L10 is filled out then the macro needs to auto populate the range L208:K208 and so on to the point that in case the full D10:L10 range is filled out then E208:L208 should be populated with formula.
I have thought to resolve this issue via two routes: (i) approaching it as a dynamic range problem in which case I need a vba code to determine the previous to the last cell populated by the user in the range D10:L10 and use the column code of that cell in "Destination:=Range("E208:L208")", or (ii) run a loop which will populate range E208:L208 with formula until the cell in the previous column within range D10:L10 is filled in by the user and stop when it is not.
Hope this makes sense and thanks in advance for the help.
When you need a dynamic range in VBA, you should simply build one. This is probably the easiest method:
Sub TestMe()
Dim colRange As Long
Dim rowRange As Long
Dim rngMain As Range
rowRange = 10
With Worksheets(1)
colRange = .Cells(1, .Columns.Count).End(xlToLeft).Column
Set rngMain = .Range(.Cells(rowRange, colRange), .Cells(100, 200))
MsgBox rngMain.Address
End With
End Sub
It is dynamic, based on the last used column in row 1 of the first Worksheet.
Concerning the second used column in Row 1, one of these 3 would probably do it for you, depending on what exactly do you want:
.Cells(1, 1).End(xlToRight).End(xlToRight).Column
.Cells(1, 1).End(xlToRight).Column
.Cells(1, 1).End(xlToRight).Column + 1

Copy and paste data from dynamic table while exluding formula blanks

I'm trying to copy only data (excluding blanks created by If statement) from "Data" tab then paste to the bottom of a data column on the "Summary" tab. The trouble arises from trying to figure out how to get VBA to recognize the range of usable data.
There are a couple of different ways to do this, depending on what you need. Here's one SO thread that discusses a few uses. Here's another page that discusses using UsedRange or .Rows. And, as #findwindow noted, you can use .xlEnd.
This is a pretty common use of VBA, so if you Google around (or even look through SO), you'll find some information.
Edit: Per your comment, just set a range, and loop through the cells in the range until you find a non-numeric number:
Dim rng as Range, cel as Range
Dim lastRow as Integer
Set rng = Range("A1:A10000")
for each cel in rng
If not isnumeric(cel.value) then
'Do whatever code you want, when the cell is NOT numeric, ie
lastRow = cel.Row
End if
next cel

Excel VBA For each sheet get contents of a row and put in an array

I have a current project that requires me to open an excel doc, figure out what format the doc is in (what the "headers" are as A:A contents), then figure out if it adheres to a new document layout format, and convert necessary data to conform to the new format.
I have to do this for thousands of files, so I want to automate as much of the discovery portion as possible, and plan to only need to write a few one-off solutions for some content types (docs with specific data which needs to be preserved as an exception to the new formatting).
That's the context for what I'm trying to do. I've gotten to the point of trying to populate an array of the contents of row A:A in each sheet, but my ReDim statement is failing as I guarantee I'm doing something wrong with it.
Here's what I've got from the point where I get into the sheet:
For Each Sht In SourceWorkbook.Sheets
Sht.Activate
SourceHeaderCount = ActiveSheet.UsedRange.Columns.Count
Set SourceHeaderRange = Sht.Range("A1:A" & SourceHeaderCount)
ReDim Preserve SourceHeaders(0 To UBound(SourceHeaders) + SourceHeaderCount)
SourceHeaders(UBound(SourceHeaders)) = SourceHeaderRange
Next Sht
Again, the idea is to grab the contents of A:A (used contents only), so that I have a list of what the file does have, then compare that list with what I need it to have, then from there I need to create sub functions to handle each type of conversion. First thing's first though, I need to know what the file has. Any ideas how I can make this work? I recognize that this approach has flaws when confronting non-standardized data (like what if a2 is unused but a3 is used?) but for the purposes of this context, assume all documents are easy to work with and there's no real strange data scheme to worry about.
Thanks for the help!
I find when aggregating a number of worksheets with similar (but non-conforming) layouts to a common worksheet, the brick-by-brick approach takes a little longer but it the most thorough. In the following, each sequenced worksheet has each column heading label examined to see if it already exists in the target worksheet. If not, it is inserted at the right-most end of row 1 and the cycle continues.
Dim r As Long, c As Long, tr As Long, tc As Long, ws As Worksheet, wst As Worksheet
Set wst = Sheets("All_of_Them")
For Each ws In Worksheets
With ws
If .Name <> wst.Name Then
With .Cells(1, 1).CurrentRegion
tr = wst.Cells(1, 1).CurrentRegion.Rows.Count + 1
For c = 1 To .Cells(1, .Columns.Count).End(xlToLeft).Column
If Not CBool(Application.CountIf(wst.Rows(1), .Cells(1, c).Value)) Then
wst.Cells(1, .Columns.Count).End(xlToLeft).Offset(0, 1) = .Cells(1, c).Value
End If
tc = Application.Match(.Cells(1, c).Value, wst.Rows(1), 0)
.Columns(c).Offset(1, 0).Copy Destination:=wst.Cells(tr, tc)
Next c
End With
End If
End With
Next ws
Set wst = Nothing
The above should be easily expanded to multiple workbooks in one or many folders. The target worksheet can start off as a blank worksheet and the aggregated column header labels will be constructed as new header labels are introduced with sequenced worksheets.

Copying only rows with Data, pasting them transposed into another sheet in column C onwards

I have tried various methods of selecting the rows from which I want to copy and paste to columns as the data is transposed. I keep getting intermittent run error 1004, sometimes it works but mostly doesn't, basically not reliable. I am hoping someone can tell me a reliable efficient way to complete this action.
To explain what I am trying to do. I have a workbook with a sheet of data arranged in rows ( can vary in number of rows).So I have specified last row as lrow. I am trying to copy this data transpose and paste into a different workbook and sheet, I need to ensure that the data is not pasted in either row A or B, it can be in any following column.
Dim lRows As Long
Dim lCols As Long
Dim wsData_Sheet As Worksheet
lRows = Cells(Rows.Count, "A").End(xlUp).Row
lCols = Cells(1, Columns.Count).End(xlToRight).Column
wsData_Sheet.Range(Cells(1, 1), Cells(lRows, lCols)).Copy
Set y = Workbooks.Open("C:\Matlab\R2006b\work\INCALogCommentList v01\LatestMacroSheet.xlsm")
With y.Sheets("Sheet1")
y.Sheets("Sheet1").Activate
Cells(2, 3).PasteSpecial Transpose:=True
End With
I keep getting either a range object defined error on the data being copied, for no reason I can think of or paste error.

Convert range (non-continuous) to values

I have a very large range of complicated formulas that use an external data source. My users don't have access to this data source, therefore I want to convert the range to values before sending the sheet.
Range=
=VALs!$A$1,VALs!$D$1:$D$45,VALs!$F$1:$G$45,VALs!$I$1:$J$45,VALs!$N$1:$N$45,VALs!$R$1:$T$45,VALs!$V$1:$V$45,VALs!$X$1:$Y$45,VALs!$AB$1:$AB$45,VALs!$AE$1:$AE$45,VALs!$AT$1:$AT$45,VALs!$AW$1:$BB$45,VALs!$BD$1:$BD$45,VALs!$BG$1:$BG$45,VALs!$BK$1:$BK$45,VALs!$BQ$1:$BQ$45,VALs!$BT$1:$BT$45,VALs!$CC$1:$CD$45,VALs!$CJ$1:$CJ$45,VALs!$CN$1:$CN$45,VALs!$CP$1:$CQ$45,VALs!$CU$1:$CW$45,VALs!$DA$1:$DC$45,VALs!$DH$1:$DH$45,VALs!$DJ$1:$DJ$45,VALs!$DL$1:$DL$45,VALs!$DO$1:$DO$45,VALs!$DR$1:$DS$45,VALs!$DV$1:$DV$45,VALs!$DZ$1:$EA$45,VALs!$EV$1:$EV$45,VALs!$EY$1:$EY$45,VALs!$FB$1:$FC$45,VALs!$FE$1:$FL$45
Now:
Copy & paste as values does not work on multiple selections
With Sheets("VALs").Range("values").CurrentRegion
.Value = .Value Does not work, I end up with empty cells in place of the range
The range is dynamic and will change often, that's why it's named, there is a separate sub to create the range
Would anyone be able to help out?
Do you mean something as simple as this? (In this case, the Named Range is named "RNG".)
Sub RangeToValues()
For Each cel In Range("RNG").Cells
cel.Value = cel.Value
Next cel
End Sub
Or is the problem more complex and I didn't understand?