Ignoring specific rows with VBA Excel - excel

I have a table in Excel like such, where the number of rows will vary each day:
Column A
Column B
Column C
Cell 1
Cell 2
Show
Cell 3
Cell 4
Show
Cell 5
Cell 6
Ignore
I am using vba to convert the range to a html table, and then email it.
I have a helper column (Column C), and I want to use a formula there to filter out certain rows.
However, that filter is not excluding hidden cells from being displayed in the html table.
I currently use this
Dim LastRow As Long LastRow = rInput.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
to find the last row of my table. This works great in projects where you want all of the table included.
I tried to change it to Find("Ignore", which gets me Object variable or With block variable not set
I tried including 'SpecialCells(xlCellTypeVisible)' in my
ConvertRangeToHTMLTable(Sheet2.Range("$A:$J").Rows("5:" & LastRow), 5)
and using a filter to hide the 'Ignore' cells. But that did not stop them showing in the emailed html table.

You probably have some sort of loop which goes over the rows right? It will not automatically skip the hidden rows just because they are filtered out, you need to specifically tell it to skip them. You can do something like:
For Each r In myRange.Rows
If Not r.EntireRow.Hidden Then
doSomething
End If
Next r

Ended up adjusting the table (and thus the range I cared about) to start at row 1 rather than row 5, and using
strBody = dsaEmailHeader & ConvertRangeToHTMLTable(Sheet2.Range("$A:$H").Rows("1:" & LastRow).SpecialCells(xlCellTypeVisible))
worked, where it didn't previously.

Related

How to adjust VBA for formula use?

My apologies up front if this post contains too much information. I am new to VBA and this site.
After some difficulties trying to run a Macro I recorded, I have tried to break it up into smaller portions. One of those portions includes appending two columns of data, which will then be used to create a table. The data in these columns is coming from two other worksheets in the same workbook.
When the data is transferred directly by me, the shortened Macro works fine. However, when I use a formula to transfer the data, the Macro does not work. I would appreciate suggestions on how to edit the shortened Macro to either adjust for the formula or edit the VBA to transfer the data and then append, so I might then proceed with attempting to create the table. The code I have been using is:
Dim col As Range, _
found As Range
Dim currRow As Integer
currRow = ActiveSheet.Range("A:A").Find("", after:=ActiveSheet.Range("A1"), lookat:=xlWhole, searchdirection:=xlNext).Row
For Each col In ActiveSheet.UsedRange.Columns
If col.Column <> 1 Then
Set found = col.EntireColumn.Find("", after:=col.Cells(1, 1), lookat:=xlWhole, searchdirection:=xlNext)
Set found = ActiveSheet.Range(col.Cells(1, 1), found)
found.Copy
ActiveSheet.Cells(currRow, 1).PasteSpecial
currRow = currRow + found.Cells.Count - 1
End If
Next col
End Sub
I should have mentioned the columns of data being copied to the worksheet will have headers and vary in the number of rows from workbook to workbook. I will try to attach images of the start and desired endpoints.
The formulas are applied to 200 rows in each column. When I use the Macro on the data copied using the formula, it seems to append the 200 cells of formula from column 2 to the 200 cells of formula in column 1. The data stays in each column, and after my last data point in column 1 I now have blank cells down to row 400 that have the formula instead of data.
BEginning View
Possible Append Result 1
Possible Append result 2

Excel VBA Sort when Inputting Data, Updated in All Other Sheet?

I am new to VBA Excel.
I wanna create a database for each month, with 1 'Main Sheet' for the list of names, and the list on 'Main Sheet' will sort automatically as a row when I entered data along with the update of the other sheet.
I found this code, and it's only updated/sorting in the sheet entered (let's say the 'Main Sheet'). Is that possible if the entered data and sorting updated automatically in all other sheets?
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
If Target.Column = 1 Then
Dim lastRow As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
Range("A2:BN2" & lastRow).Sort key1:=Range("A2:A" & lastRow), order1:=xlAscending, Header:=xlNo
End If
End Sub
I tried referencing/paste the link to the name for each month (start from A2), but I have no idea to keep the column beside A2 (B2, C2, etc) sticking with the A2 as a full row.
Thanks!
Look at this part of your code for ideas how to solve your problem.
Range("A2:BN2" & lastRow).Sort Key1:=Range("A2:A" & lastRow)
The instruction is to sort Range("A2:BN2" & lastRow) on Key1. The range to sort starts at A2 and ends with the last used row in column BN. All columns of all rows are included, as they should. But lastRow was determined in column 1, which is column A. We hope that all columns have the same length. Observe that we don't know on which tab the range is located. By default, if no sheet is specified, Excel will presume the ActiveSheet. This is borne out by the fact that the code is located in a worksheet event procedure. Of course, this code is linked to the sheet on whose code module it is placed. It won't run when another sheet is active.
However, the syntax for specifying a range for a particular sheet would look like this.
With Worksheets("MySheet")
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
Set MyRange = .Range("A2:BN2" & lastRow)
End With
Please observe all the leading periods, each of which links the statement it precedes to the worksheet specified in the With statement. Imagine a loop in which the sheet name is changed on each turn, thereby defining the same range on a different sheet on each instance.
The Key argument of the Sort method specified the column on which to sort. It's called "Key" instead of "Column" because there are sheet columns and range columns. In your case the sheet rows are different from your range rows because your range starts in row 2 but the range columns are identical with the sheet columns. Anyway, Key1:=Range("A2:A" & lastRow) isn't a very good pointer to the column you want to sort on. 1 single cell would suffice, like Key1:=Range("A2") - or Key1:=Cells(2, 1) as I would prefer.
As you see, this part is a lot simpler. The only important point to observe is that the cell specifying the Key must be within the range to be sorted. This also means that you can't specify a Key on the ActiveSheet for a sort range on another tab. When you construct your loop, therefore, you will need to take a cell from the properly defined sort range as Key.

When trying to use autofill via vba after inserting rows, the formulas copied are incorrect

I have an dynamic range that counts an x amount of constructions in a different document. It then adds this amount of rows (-3 for the default present rows). After the rows are added, the formulas from the first 3 rows are autofilled to match the range.
The formula in the 1st row is
"=Materiaal!V14"
The formula in the 2nd row is
"=Materiaal!V15"
The formula in the 3rd row is
"=Materiaal!V16"
However, after the rows are added it skips an amount of cells
The formula in the 4th row is
"=Materiaal!V26"
This should have been
"=Materiaal!V27"
I tried to change where the new formulas, to make sure it start in the first row again, but that also won't work
Dim add_lines_p2 As Integer, formula_source_p2 As Range,
formula_destination_p2 As Range
add_lines_p2 = production_numbers_count - 3
add_lines_p2 = add_lines_p2 + 16
'now the command to add the new lines + adding the right formulas
worksheet_uitsplitsing.Rows("17" & ":" & add_lines_p2).Insert
Shift:=xlDown, CopyOrigin:=xlFormatFromRightOrAbove
Set formula_source_p2 = worksheet_uitsplitsing.Rows("14:15")
Set formula_destination_p2 = worksheet_uitsplitsing.Rows("14" & ":" &
add_lines_p2)
formula_source_p2.AutoFill formula_destination_p2
I expected the rows to count up from row 14, but after the default 3 rows, it skips a certain amount of cells.
I found my own problem and then realised it isn't visible in this post.
The code has a reference to a cell on a different page. It first added rows on the default page, than it made the reference to the cell.
After that it adds rows on the other page, thereby shifting the cell reference down.
Excuses for the therefor "bad" question...

Excel VBA filtering a column and then copying each item in the area collection to a matching row

I have the following Excel Table:
Create Date Last Active Date Age
4/12/2017 5:54 4/17/2020 8:54 5 Days
4/19/2017 7:43 #N/A
4/12/2017 20:43 #N/A
4/1/2017 23:20 4/3/2017 6:54 10 Days
4/15/2017 22:20 #N/A
What I want to do is to filter the Age Column by #N/A, and then copy each Last Active Date value to the same row in Create Date. Seems easy enough, but I keep running into issues. I am using the SpecialCells(xlCellTypeVisible) property to then do a for each on each Area in there(non-contiguous rows), but when I go to copy the rows, it either copies the rows starting at Row 1 of the Create Date column, meaning the values get all out of whack OR it throws an error saying the ranges don't match. Here is the code I have so far that I pulled from another page that talked about how to do this, but it doesn't seem to work for me.
ActiveSheet.ListObjects("Table1").Range.AutoFilter Field:=8, Criteria1:= _
"#N/A"
Dim lngrow As Long
Dim FinalDest As Range
Dim Rng As Range
lngrow = Sheets("Sheet1").UsedRange.Rows.Count
Set FinalDest = Sheets("Sheet1").Range("C2:C" & lngrow)
Range("F2:F" & lngrow).Select
For Each Rng In Cells.SpecialCells(xlCellTypeVisible).Areas
Set FinalDest = FinalDest.Offset(Rng.Rows.Count)
Rng.Copy Destination:=FinalDest
Next Rng
Application.CutCopyMode = False
How can I accomplish this? I want to filter it by #N/A, and then for each filtered row that remains, copy the value in Last Active Date to Create Date, (which will always be blank for these rows) and make sure they get copied to the proper rows, ie if Row 3 is the first filtered row, the value gets copied to rows 3 instead of row 2.
You don't need to filter your table. You have two feasible solutions:
Solution 1 (without VBA):
Assuming that Create Date is at A1:
-Insert a new column between Create Date and Last Active Date.
-Insert this function to B2--> =IF(A2="",IFNA(D2,C2),A2)
-Copy paste B2 till end of your column
-Copy all B column and paste them as values.
-Delete Column A
Solution 2 (with VBA):
You can loop through each row and check if the Age cell is #N/A, if true(#N/A), then you do the copy/paste from Last Active Date cell to Create Date Cell.
Solution 1 is much faster and easy. If you are interested in VBA solution let us know.
Edit: You can always change the following code for different conditions but since you said --> Create date value (which will always be blank for these rows):
Dim i As Long
For i = 2 To Range("C1").End(xlDown).Row
If IsEmpty(Cells(i, 1).Value) Then
Cells(i, 1) = Cells(i, 2)
End If
Next i

LastRow in spreadsheet

I always see on SO that people use this to find the last row in a column
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
I have always used this function in my projects to find it as I want the last unused row but now that i always see people using End xlUp approach i am wondering why since it only gives that column which may not be correct.
Function GetLastRow(sh As Worksheet) As Long
Dim X As Long
X = sh.UsedRange.Rows.Count 'force excel to recalculate last row
GetLastRow = sh.Cells.SpecialCells(xlLastCell).Row
End Function
Is there any situation where this function fails to give the last row and why it happens?
Some times it happens that it give me a row that could be many lines after the last row of data I assume due to formatting(exported reports generally - I then work my way back up in a loop to remove these rows if fully blank)
What is UsedRange actually considering as used?
I really want a reliable function that I can depend on in the future
Excel tracks cells sparsely: think of it as tracking a row and column pair for each cell that has ANY information (actually its a bit more complex than that but its still a good way of thinking about it). The information can be formatting or data or formulas or ...
So the last used cell is the last entry in the cell tracking table. But the cell tracking table is not reset just by clearing information.
And since Excel 2007 sh.UsedRange.Rows.Count does not (unfortunately) always reset the cell table.
Mostly when you want to find the last used cell you want to find the last cell that actually contains data or formulas rather than the last cell in the cell table.
Using Range.End(xlUp) etc finds the last VISIBLE cell that contains data or formulas, so needs to be used with care if you hide rows or use filtering. And requires looping code when considering multiple columns. But its the fastest of the 3 main methods.
Using Find is usually the most reliable method (but it ignores shapes and comments, and has problems with merged cells and empty pivot tables):
jLastRow = oSht.Cells.Find(What:="*", LookIn:=xlFormulas, SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
jLastCol = oSht.Range("A1:A" & CStr(jLastRow)).EntireRow.Cells.Find(What:="*", LookIn:=xlFormulas, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
In Excel, if you enter data from A1 to Z100, then the used range goes from A1 to Z100.
If you delete rows 50 to 100, the used range is still A1 to Z100. Just clearing cells does not reduce the used range. Excel will mark the last row/last column where data was entered previously.
UsedRange can give you an unexpected result if you want to find the last populated cell in the spreadsheet, because it takes into account rows and columns that may have been in use previously.
If you want to find the last row in a column, the method with rows.count and end(xlUp) is more accurate, because it considers the current values. UsedRange may be bigger.

Resources