I am trying to have this piece of code clear the contents of a certain range, before I bring new data. This range has a header right in the above row, which is getting cleared as well, although the range doesn't include it.
I've tried specifying the range and having other cells selected before running it, but the header gets cleared anyway.
With MyResults
LastRowResults = Range("A16:K" & Rows.Count).End(xlUp).Row
.Range("A$16:$K$" & LastRowResults).Select
Selection.SpecialCells(xlCellTypeConstants, 23).Select
Selection.ClearContents
It's clearing row 15 and even the content of cell A9, some of the times I run it.
The goal is to have this range cleared, keeping formulas in some columns intact, so that filtered data down the road can be brought in, making up the report required.
Avoiding Select and Activate in VBA does miracles in performance and coding abilities (How to avoid using Select in Excel VBA). Concerning your code, try to avoid the header, if it is a default at line 16:
With MyResults
LastRowResults = .Range("A17:K" & Rows.Count).End(xlUp).Row
MsgBox LastRowResults 'Consider removing this line, once the code works.
Dim deleteArea As Range
Set deleteArea = .Range("A$17:$K$" & LastRowResults)
deleteArea.ClearContents
End With
In the OP code, there was a lack of . before the Range in this line:
LastRowResults = .Range("A17:K" & Rows.Count).End(xlUp).Row
Thus, the lastRowResults was getting its value from the ActiveSheet or the Sheet in which the code resides (if not in a module). The . is quite important in the With MyResult.
In general, when the last row is searched for multiple columns, then one should define exactly the expected output. E.g., the for the biggest last row, something like this is way better:
LastRowResults = .Columns("A:K").Find(What:="*", SearchDirection:=xlPrevious, SearchOrder:=xlByRows).Row
Related
I have an Excel workbook with multiple sheets, which are fed by data imported from multiple external excel files. To complete this action, I successfully built VBA code that allows the user to open the files.
Behind the scenes, one of the subs imports data from the General Ledger raw data into a spreadsheet with multiple columns. I am attaching a couple screen grabs here to show what is happening:
The pre-existing data looks like this:
Raw data once downloads will look like this:
Once the macro runs, the previous columns populate as intended, but because the last two columns are populated intermittently, they end up doing this:
I only summarized columns in these images, as the workbook has 28 columns preceding the two columns.
Due to the size of the data and the macro itself, I would like to maintain the structure of the code. Especially since it is intended that this macro be transferred to other general ledger workbooks.
My macro looks like this (summarized for time):
1. Sub Import_GL1001
2. Dim FileToOpen As Variant
3. Dim OpenBook As Workbook
4. Application.ScreenUpdating = False
5. FileToOpen=Application.GetOpenFileName(Title="Import_GL1001",FileFilter:="ExcelFiles (*xlsx*),*xlsx*")
6. If FileToOpen<> False Then
7. Set OpenBook=Application.Workbooks.Open(FileToOpen)
8. OpenBook.Sheets(1).Range("$A$2:$A$1500").Copy
9. ThisWorkbook.Worksheets("GL 1001.10").Range("A"&Rows.Count).End(xlUp).Offset(1,0).PasteSpecial xlPasteValues
10. OpenBook.Sheets(1).Range("$B$2:$B$1500").Copy
11. ThisWorkbook.Worksheets("GL 1001.10").Range("B"&Rows.Count).End(xlUp).Offset(1,0).PasteSpecialxlPasteValues
12. ......
13. OpenBook.Sheets(1).Range("$AC$2:AC$1500").Copy
14. ThisWorkbook.Worksheets("GL 1001.10").Range("AD"&Rows.Count).End(xlUp).Offset(1,0).PasteSpecial xlPastevalues
15. OpenBook.Sheets(1).Range("$AD$2:$AD$1500").Copy
15. ThisWorkbook.Worksheets("GL 1001.10").Range("AF"&Rows.Count).End(xlUp).Offset(1,0).PasteSpecialxlPasteValues
In an ideal world, the values would copy and paste as is, blanks and all, so when the macro is run in the future the two columns in question do not change position based on the last blank cell. I tried multiple methods and variations, but the only logical thing I could think of is if I manage to find a way to insert a "0" into each cell that is blank every time the data is imported, without changing all the blank cells (i.e. if we only have 30 rows of data, I don't want all of the blank cells in AF:AF to be "0"). If the cells have a value at all, then that means that the macro itself won't have to be dramatically retooled.
Please, try the next way:
The last row where to paste the values should be calculated only once, based on a column you know that it is all the time filled with values.
Dim lastERow As Long, sh As Worksheet
Set sh = ThisWorkbook.Worksheets("GL 1001.10")
lastERow = sh.Range("A" & sh.Rows.Count).End(xlUp).Offset(1,0).row 'last empty row
Then use this reference for all the columns where you intend pasting starting from the same empty cell row:
'your existing code
OpenBook.Sheets(1).Range("$A$2:$A$1500").Copy
sh.Range("A" & lastERow).PasteSpecial xlPasteValues
'...
'...
OpenBook.Sheets(1).Range("$AC$2:AC$1500").Copy
sh.Range("AD" & lastERow).PasteSpecial xlPastevalues
OpenBook.Sheets(1).Range("$AD$2:$AD$1500").Copy
sh.Range("AF" & lastERow).PasteSpecial xlPastevalues
In this way, the code will paste starting from the same empty row, in all columns.
If you want following your way of solving, please run the next code, but after your existing code runs. It will take the reference from the last filled cell of the A:A column:
Sub ZeroInEmptyCells()
Dim sh As Worksheet, lastRow As Long, rngEmpt As Range
Set sh = ThisWorkbook.Worksheets("GL 1001.10")
lastRow = sh.Range("A" & sh.rows.count).End(xlUp).row 'last row in column A:A
On Error Resume Next 'if no empty cells, the next code line will return an error (without this line...):
Set rngEmpt = Union(sh.Range("AD1:AD" & lastRow), sh.Range("AF1:AF" & lastRow)).SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If Not rngEmpt Is Nothing Then rngEmpt.value = 0
End Sub
I'm using VBA code to write to cells in excel. For eg.
Range("C3") = code
Or
Cells(3,3) = code
If a row is inserted in the sheet, the code does then not update accordingly and would still write to Range("C3") etc. So the code then writes to the incorrect cell.
Is there a better way I can structure my code so it will update accordingly? Perhaps using a table instead of cells?
One solution is to used Named Ranges. You can define a Named Range in Formula Tab by clicking on Name Manager.
Then you will write.
Range("Name of the Range") = code
My believe is that named ranges update automatically when a row or column is inserted, so your code will print the value in the correct cell.
Thanks, good idea. I ended up defining the column filled with values as a range, then use a for loop to search for the defined string. That way it doesnt matter what row it is in aslong as the name and string doesnt change (Using a Named Range will probably be better for that exact reason).
Worksheets("Sheet1").Select
Set WS = ActiveSheet
With WS
LastRow = .Cells(.Rows.Count, 2).End(xlUp).Row 'Determine the last row number with data in it for column B
For Each acell In .Range("B1:B" & LastRow) 'Defines the search range from B1 to last row
If acell.Value = "String Searched For" Then
'Do stuff based on found cell location
End If
If acell.Value = "String Searched For#2" Then
'Do stuff based on found cell location#2
End If
Next
End With
Please help me debug this code. I am compiling a report from 100 files. This code works for almost all the files but for some this error pops up. The format for all the files is the same only the row count differs
sh.Range("A2:H" & lastRow).Copy
Destination:=wb1.Worksheets("MainSheet").Range("A" & mainrow)
A2&last row = A2:H17408
"A" & mainrow=A1033559
There are multiple reasons to get this error message
1. When you are pasting merged cells to non-merged cells or visa-versa.
2. When you applied a filter to sheet, and tried to paste which is not same size as copied data.
your code is too limited to be sure of a 100% correct answer, as we do not see how you have defined your variables.
However, assuming they are correctly defined, it is better to use this:
Dim ws as worksheet
Set ws = wb1.Sheets("MainSheet")
' Range goes from columns A to H with mainrow and LastRow as variable rows
ws.Range(ws.Cells(mainrow, 1), ws.Cells(LastRow, 8)).Value = sh.Range(sh.Cells(mainrow, 1), sh.Cells(LastRow, 8)).Value
instead of a copy-paste.
Apart from that, make sure mainrow and LastRow are defined correctly. When in doubt, add this part of your code in an edited question, so we can have a look at it.
I am attempting to select a dynamic range of filtered data that spans from col. A: col. J without selecting the header (in row 1). From there I need to copy and paste it into a new sheet where I will manipulate it further, but I cannot come up with an efficient or functional way to do this. Based on some code I found on another forum I was able to select all of the "visable cells" in a single column, but I am running into issues trying to select the whole range. I am still very new to vba so forgive my syntax, but my code posted below was an attempt to itterate through Rows.Count and i which was an integer 1-10. If you have any advice on how to do this better and more efficiently I would really appreciate it.
Sub SelectVisibleInColD()
Dim lRow As Long, i As Integer
Set i = 1
Do While i <= 10
With ActiveSheet
lRow = .Cells(.Rows.Count, i).End(xlUp).Row
If lRow < 3 Then Exit Sub
.Cells(1, 1).Offset(1, 0).Resize(lRow - 1).SpecialCells(xlCellTypeVisible).Select
End With
i = i + 1
Loop
End Sub
You can select a range by using Range property of ActiveSheet. You already have the last row and you know that the header is in the first row, so your range starts from position A2 and goes to the last row of column J
ActiveSheet.Range("A2:J"&lRow).SpecialCells(xlCellTypeVisible)
If you want to copy this range, use Copy function like
yourRangeAsAbove.Copy
This function only moves the selection to memory, to paste it, build your destination range and call PasteSpecial function.
I came across this answer googling my issue for: deleting of filtered selection in vba.
However trying your answer &lRow gives me an runtime error 1004, application-defineed or object-defined error
I got around it with this
ActiveSheet.Range("A2:G" & Range("A" & Rows.Count).End(xlUp).Row).SpecialCells(xlCellTypeVisible).Delete
For those that may also get the same issue.
I have a dataset that I'm using a filter on. I simply want to calculate the total values in column N, that are visible. The data starts in row 2, and ends at row 2047.
I saw this thread but it gives me the same type of issue I'm having.
Here's my function:
Function sumVisible() As String
Dim rng As Range
Set rng = Range("N2:N2047").SpecialCells(xlCellTypeVisible)
' Debug.Print "Range: " & rng.Address & ", Sum: " & WorksheetFunction.Sum(rng)
sumVisible = Format(WorksheetFunction.Sum(rng), "$#,###.##")
End Function
With my current filter, my header row (1) is visible, as are rows 901 to 937. So, I want to sum N901:N937.
However, the rng keeps getting set to $N$2:$N$2047. I expected it to be $N$901:$N$937.
Using the function that is given to the thread I linked to above, I get a range of $N$2:$N$937...so at the very least, I'm getting the end row correctly, but not the start row.
But! if I type Range("N2:N2047").SpecialCells(xlCellTypeVisible).Select in the Immediate Window, outside of a macro, it correctly selects just the visible cells. And one step further, doing ?Range("N2:N2047").SpecialCells(xlCellTypeVisible).address correctly returns $N$901:$N$937.
What may be going wrong?
Edit: I just found that doing =SUBTOTAL(9,N1:N2047) will just sum the visible cells, so I'm using that. But my question still stands - why isn't SpecialCells(xlCellTypeVisible) working correctly in the macro?
Try setting your rng with the line below:
Set rng = Range("N2:N" & Cells(Rows.Count, "N").End(xlUp).Row).SpecialCells(xlCellTypeVisible)
Later using your debug line Debug.Print rng.Address, I get the following range in the immediate window:
$N$901:$N$937