.End(xlToRight) within a range - excel

I've just got a quick one wondering if I can somehow alter the following snippet to include .End(xlToRight) instead of defining L6 (the result is the same).
Sub Test()
Dim LastCol As String
With Worksheets("Sheet1")
LastCol = .Cells(5, .Columns.Count).End(xlToLeft).Address
.Range(Range("A5"), LastCol).Copy
.Range("B5:L5", Range("B5:L5").Offset(LastRow - FirstRow, 0)).PasteSpecial xlPasteFormulas
.Range("B6", .Cells.SpecialCells(xlCellTypeLastCell)).Copy
.Range("B6").PasteSpecial xlPasteValues
End With
End Sub
Many thanks for any help :)
EDIT: updated pdw TonyDallimore (see response below)
Tony, the above code is the sum of what I've been trying to get working. Within the with statement, I'm looking to copy the contents of row 5, and paste them down to the nth row - which is defined by a list already present in columnA. The last line per your advice will then paste the values of all but the top row (r5) to preserve transparency for the user, while minimising file size.
The middle bit is the remaining 'work in progress', as L5 is not certain to be the farmost column.

Both questions
.End(xxx) is the same as Ctrl+Arrow from the keyboard and stops at the first cell that is different from the current cell. So if you start at a cell with a value it stops at a cell without a value or vice versa.
The trouble with starting top left and using xlDown and xlToRight is that it will stop at a blank cell in the middle of your table. Fine if you absolutely cannot have a blank cell in the middle, but XlUp or xlToLeft from bottom right are safer.
Question 1
Is your problem that .End(xxx).Column will return 12 and you do not know how to turn it into the letter "L"?
Is so, there are lots of choices. I think the easiest is to remember that
.Cells(6,Columns.Count).End(xlToLeft).Address
would return "$L$6".
Question 2
Does .Cells(1000, ColRange) represent the bottom right cell?
.Cells.SpecialCells(xlCellTypeLastCell) might be an easier option.

Related

Excel VBA to look for the last non-blank cell in a column and convert it to a value

I have a column thats rows are currently filled with this formula:
=IF(VLOOKUP(H3,B:D,3,0)="NOT_FOUND","",VLOOKUP(H3,B:D,3,0))
That fills rows one by one with the value that it finds. I am hoping that there is a macro that will search the column (I) for the single last non-blank cell and convert the formula answer into a value so I can eventually sum all of the values. I assume it is not a very difficult macro, but I have no experience working with VBA so any help would be appreciated!
Here is a pic of part of the table I am trying to make. Where the 13.8 is I would like for that to be converted to just a value since it is the last non-blank cell in the column. Please let me know if this makes sense or if more info is needed. Thank you!
nofriendsnojo, if overwriting the formula in a cell (in this case VLOOKUP) is all you need, then please see my code below:
Sub paste_values()
Dim lastRow As Long
Dim cel As Range
'get last non-blank cell in column I
lastRow = Cells(Rows.Count, "I").End(xlUp).Row
'loop that overwrites cell contents with simple values
For Each cel In Range("I1:I" & lastRow)
cel.Copy
cel.PasteSpecial xlPasteValues
Next cel
Application.CutCopyMode = False
End Sub
This is the basic code, it copies values of the cell and then pastes them to the same cell as values. This ultimately gets rid of any formula and converts the result of the formula into a simple value. It is quite common practice.
Of course, you can then add some references like ThisWorkbook. or ActiveSheet. or whatever scope you need.
I hope this solves your issue or atleast directs you in the right way.

selection of multiple columns with end(xlDown).End(xlUp).Row

I'm doing debug for a VBA template.
The Macro let users choose a excel file to import, then it will check each columns whether they correpond the requirements.
When I try to import a file, I alway get error "oveeflow" with the following line:
'maxRow = ws.Range(Cells(StartRow, AdditionalInfoColumns.OtherInfo).Address).End(xlDown).Row
My colleague tells me that I just need to add end(xlDown).End(xlup) like this:
maxRow = ws.Range(Cells(StartRow, AdditionalInfoColumns.OtherInfo).Address).End(xlDown).End(xlDown).End(xlUp).Row
And it does work! I don't know why. So I try to do it in a simpler way as following:
maxRow = ws.Range(Cells(StartRow, 1).Address, Cells(StartRow, 3).Address).End(xlDown).End(xlUp).Row
It works as well.
Can someone please explain why does it work? Thank you for your answer.
PS: The value of xlDown and xlUp are -4121 and -4162.
Best Regards
Kai
First of all End(xlDown) and End(xlUp) is nothing more than …
End(xlDown) = Pressing Ctrl + Arrow down
End(xlUp) = Pressing Ctrl + Arrow up
you can test this manually by selecting a range/cell and press the combination to see the effect on your actual worksheet.
The overflow error just comes because if you eg. select cell A1 in an empty worksheet and do .End(xlDown) it selects the very last cell of the worksheet. And if you now insert something it fails because the maximum rows of Excel are exceeded.
To find the last used row of a column it's better to use End(xlUp) instead of End(xlDown) eg:
LastUsedRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
'finds the last used row in column A
End(xldown) has the same effect as pressing control and the down arrow (and End(xlright) is control and right arrow. If you try those key presses in a cell you will see it jumps to the next intersection of filled and empty cells (or the edge of the spreadsheet if there's no filled cells in the way)

Sum only visible cells in one ROW (not column)?

I have a row and I want to sum only visible cells, i know if it's a column I can use subtotal (109,range), but this one doesn't seem to work for cells in one row. Anyone knows how to sum only visible cells in a row?
Please click here for picture
If a VBA solution is okay, this will work:
Function sumVisible(rng As Range) As Double
Dim cel As Range
For Each cel In rng
If cel.EntireColumn.Hidden = False Then
sumVisible = sumVisible + cel.Value
End If
Next cel
End Function
Pretty straightforward - just checks if a cell in your range has a hidden column, if it's visible, sum it.
=sumVisible(D2:M2) is how you'd use it.
You can check the width of the cell.
=IF(CELL("width",A1)=0,"hidden","open")
you can then sum your cells as need it using IF and CELL
=IF(CELL("width",A1)=0,0,A1)
more info below:
Ignoring a hidden column in an excel sum formula
You can do this using a single worksheet formula alone, provided that none of the columns which remain unhidden will have a width of less than or equal to 0.5 (which, in practice, would be so narrow as to be virtually hidden in any case).
Assuming a range of A1:E1
=SUMPRODUCT(0+(CELL("width",OFFSET(A1,,N(INDEX(COLUMN(A1:E1)-MIN(COLUMN(A1:E1)),,))))>0),A1:E1)
Unfortunately this formula will not update automatically as changes regarding hiding/unhiding columns within the range are made. As such, it will be necessary to 'recommit' it each time you make changes in that respect; one way to do this is via going into the formula as if to edit it and then recommitting by pressing ENTER.
Perhaps of interest is this post.
Regards

Removing duplicates on two sheets in excel

I am trying to make a macro that will look at a list on sheet 2 and look for the same value on sheet 1. If/when it finds it, it would delete the row on sheet 1. Then it would end at the bottem of sheet 2. Any advice would help, thank you!
The best way to do this is to loop through the values on sheet 2. On each value, check if it exists on sheet 1, and if so, delete that row.
The key is in how you structure your loop, and how you plan for the unexpected. How does your code handle if the same value is listed more than once on sheet 1? What if there are blank spots in sheet 1?
My advice is to use a built-in function such as the .Find method. This can skip over unexpected spaces, and it can easily be called multiple times. More info on this and other methods is found by pressing F1 in VBA editor, or you can look here.
As has been pointed out elsewhere, avoiding using .Select is also good practice.
To get you started, here is an outline of what's possible, looking at information in Sheet2 rows 1 through 3, and replacing those values in Sheet1 rows 1 through 10:
Public Sub delete_selected_rows()
'look at sheet2, A1 through A3 for search values
For Each search_value In Worksheets(2).Range("A1:A3")
'as long as there is something to delete...
Do While Not Worksheets(1).Range("A1:A10"). _
Find(search_value.Value, lookat:=xlWhole) Is Nothing
'...delete that row
Worksheets(1).Range("A1:A10").Find(search_value.Value, _
lookat:=xlWhole).EntireRow.Delete
Loop
Next
End Sub

Last cell selection .End(xlup) using VBA in Excel 2003 'lists' - requires two .Select to get correct cell?

I'm a new convert from Experts-Exchange since I noticed they increased the 'Free Premium Services' points threshold.
It seems that Excel 2003 has issues with the End(xlup) command when using it in a worksheet that contains an Excel 'List'.. If I select a cell outside the 'list' boundary, and then try to select the last cell in the worksheet by using VBA, I have to call the .Select function twice to make sure I am getting the correct cell. If the original cell is inside the 'list' boundary then i only need one .Select. My hacked together solution is below, with two selects, as I can never be sure what cell may be selected on save. I include a version check at open to run different code in Excel 2007 (this code fails in 2007, where the .End(xlUp) command works properly).
Is there a more eloquent way to handle this?
Thanks for any help!
.Range("A1").Select
.Cells(.Rows.Count, "A").End(xlUp).Select
.Cells(.Rows.Count, "A").End(xlUp).Select
'two .Selects needed to select correct cell in Excel 2003 list because original selection (A1) was not in list'
.Range("A1").Select
.Cells(.Rows.Count, "T").End(xlUp)(-2, 1).Select
.Cells(.Rows.Count, "T").End(xlUp)(-2, 1).Select
'two .Selects needed to select correct cell in Excel 2003 list because original selection (A1) was not in list'
.Cells(.Rows.Count, "T").End(xlUp)(-3, 1).Select
'only one select needed here because original selection above was within the list'
See how this does:
Sub Example()
Dim rngLstCell As Excel.Range
Set rngLstCell = GetLastCell(Excel.Worksheets("Sheet1"))
MsgBox "The last cell is: " & rngLstCell.Address, vbInformation
End Sub
Public Function GetLastCell(ByVal ws As Excel.Worksheet) As Excel.Range
Dim rngRtnVal As Excel.Range
With ws.UsedRange
Set rngRtnVal = .Find("*", .Cells(1, 1), , , xlByRows, xlPrevious)
If rngRtnVal Is Nothing Then
Set rngRtnVal = .Cells(1, 1)
End If
End With
Set GetLastCell = rngRtnVal
End Function
Using find may seem weird at first but it ends up being the most reliable way due to some vagaries in the way empty cells are handled.
This may not be perfect if your data is non-normalized (jagged).
I found that my use of .End(xlUp).Select prior to acting on the .End(xlUp) cell was causing the problem. If I simply avoid the .End(xlUp).Select prior to operating on the .End(xlUp) cell, the problem is less complex. It can be easily solved by preceding any .End(xlUp) operation with .Range("A1").Select. See the code for explanation. This doesn't really fix the problem with improper .End(xlUp) cell 'selection' - but I'm not interested in 'selecting' the cells, just operating on them. I must mention that I use .Range("A1").Select because A1 is outside of the 'list' that I'm manipulating via VBA.
'commented out - just need to add a ".Range("A1").Select" prior to any .End(xlUp) usage (besides .End(xlUp).Select) to make it work in Excel 03
'.Range("A1").Select
'.Cells(.Rows.Count, "A").End(xlUp)(0, 1).Select
'.Cells(.Rows.Count, "A").End(xlUp)(0, 1).Select
''two .Selects needed to select correct cell in Excel 2003 'Lists'
'Set EntryDate = Cells(.Rows.Count, "A").End(xlUp)(0, 1) 'no need to select cell first, then operate on it, as in the code above
'fixed code below
.Range("A1").Select 'needed for Excel 03 to select correct cell
Set EntryDate = Cells(.Rows.Count, "A").End(xlUp) 'just operate on the cell instead of selecting it first
Are you sure the ranges that you were working with were identical? You shouldn't get different results using the End property in Excel 2007 versus 2003.
Looking at your code:
.Range("A1").Select
.Cells(.Rows.Count, "A").End(xlUp).Select
.Cells(.Rows.Count, "A").End(xlUp).Select
Each of these lines of code have exactly zero impact on one another. No honest explanation can be offered about why the End property is giving you different results based on the code you've provided. From what's written, you should get the same results each time. (That's assuming you're working with identical ranges.) I'd be suspicious of any other code that's being executed. I can offer a couple general tips though: If you use End starting with a blank cell, it will stop at the first non-blank cell. If you start with a non-blank cell, the opposite is true. Looking at the screenshot below:
Range("B13").End(xlUp).Select 'selects B12
Range("B12").End(xlUp).Select 'selects B2
Range("A12").End(xlUp).Select 'selects A6
So whether or not your list is contiguous is an issue. Also, it is not necessary to select a range before you do something to it. Telling Excel to select cell A1 does not impact how it executes .Cells(.Rows.Count, "A").End(xlUp).Select. Assuming that line is within a With block that refers to a worksheet, that line of code is the same thing as navigating to cell A65536 (or A1048576 in Excel 2007) and pressing Ctrl + Up. Assuming that cell is blank, Excel will navigate upwards until it finds the first non-blank cell in column A. If your With block refers to a range object, then that line of code will go to the first column, bottom row of that range and navigate upwards until it comes to the first blank or non-blank cell.

Resources