Excel VBA - For Each - In & end(xltoright) - excel

So here's what I got so far:
Sub SortByGen()
Dim Gen As Range
For Each Gen In Worksheets("Sheet1").Range("B3:G3")
If Gen.Value = "XXX" Then
Gen.EntireColumn.Copy _
Worksheets("XXX").Range("A2").End(xlToRight).Offset(0, 1).EntireColumn
If Gen.Value = "YYY" Then
Gen.EntireColumn.Copy _
Worksheets("YYY").Range("A2").End(xlToRight).Offset(0, 1).EntireColumn
End If
Next Gen
End Sub
I'm trying to sort certain columns from one worksheet to multiple worksheets based on a certain criterion. I accidentally placed a values on
Worksheets("XXX").Range("B2") and Worksheets("YYY").Range("B2")
so when the
.end(xltoright)
ran, the code worked. Now when I try to get rid of the values in B2, the code will get an error.

If you use xlToRight and you're starting from the last occupied cell in that row then it will go to the very end of the row: you can't offset 1 more column from there...
Use this instead:
Gen.EntireColumn.Copy _
Worksheets("XXX").Cells(2, Columns.Count).End(xlToLeft).Offset(0, 1).EntireColumn

Related

Referencing formula for row number in Excel Macro

I'm attempting to make a macro which will autofill a number of pages based on how many is actually needed. Each item, imported from another workbook, would receive its own 'page'. These pages are on one sheet, separated by print area. Currently I have a counter which counts the number of items that need pages (11 in my example), then I have a value for number of rows per page (34). Those are multiplied together to determine how many rows to autofill to (374). The issue is getting the macro to replace the range variable with the number (374).
I've tried to use the Indirect function but receive a compile error: "Expected: List separator or )"
I've also attempted the Offset function but receive the same error.
This is my Macro so far:
Sub Sheet_Fill()
Sheet_Fill Macro
ActiveCell.Range("A1:I34").Select
Selection.AutoFill Destination:=ActiveCell.Range("A1:I68"), Type:= _
xlFillDefault
ActiveCell.Range("A1:I68").Select
End Sub
Essentially, I want to replace the "I68" with something that will autofill the row number of the I column with my formula mentioned earlier. In the example case of 11 parts, the number would be autofilled with "374"
The raw version of your macro should be something like this:
Sub Sheet_Fill()
'Sheet_Fill Macro
Dim rownum As Long
rownum = 374 'Or a range? Where is this number located?
ActiveCell.Range("A1:I34").Select
Selection.AutoFill Destination:=ActiveCell.Range("A1:I" & rownum), Type:= _
xlFillDefault
ActiveCell.Range("A1:I" & rownum).Select
End Sub
Cleaned up a bit (this should work):
Sub Sheet_Fill()
Dim rownum As Long
rownum = 374 'Or a range? Where is this number located?
Range("A1:I34").AutoFill Destination:=ActiveCell.Range("A1:I" & rownum), Type:=xlFillDefault
End Sub
Need some more details from you on where you're storing this 374 - is it in a cell? Can it be calculated from your table setup? Until those answers are given, this is the best I can do.
Try:
Selection.AutoFill Destination:=ActiveCell.Range("A1:I" & lr), Type:= xlFillDefault
Where lr is last row... you would either want to determine this dynamically, or you could assign the to pull a value from a cell, e.g.:
'dynamic
lr = sheets(1).cells(sheets(1).rows.count,1).end(xlup).row
'from a cell
lr = sheets(1).range("A1").value
General comment... avoid using select/activate!

Loop with two table and last row

I'm trying to build a formula:
=BDS(Bonds!J2& " ISIN","ISSUE_UNDERWRITER","Headers","Y")
In one sheet that takes a unique identifier from another table.
These formula builds me a table. After it builds me the table, I need to take the next row in the other sheet:
=BDS(Bonds!J3& " ISIN","ISSUE_UNDERWRITER","Headers","Y")
Then insert that formula a the end of the previous table built by the previous formula.
What I tried was getting the last row and then offsetting it by one, but I'm trying to figure out how to loop through it.
This is what i have tried:
Sub Formula2()Formula2 Macro
Range("A1").Select
ActiveCell.FormulaR1C1 = _
"=BDS(Bonds!R[1]C[9]& "" ISIN"",""ISSUE_UNDERWRITER"",""Headers"",""Y"")"
lRow = Cells(Rows.Count, 1).End(xlUp).Select
Selection.Offset(1, 0).Select
ActiveCell.FormulaR1C1 = _
"=BDS(Bonds!R[-53]C10& "" ISIN"",""ISSUE_UNDERWRITER"",""Headers"",""Y"")"
Range("A57").Select
End Sub
Image of Table, Im trying to iterate through the ISIN Column. It is column "J"
Although selection and .select are used by the macro recorder, they cause big problems when developing code. It's worth your time to learn how to replace them with range objects. So, while I'm not directly answering your question, I'm trying to give you the tools to do so.
I've shown an example below to illustrate (although I do not work with the BDS() function so I'm undoubtedly getting the details wrong). The main point is that if you learn to move around using the range object you'll be much better off.
Sub formula()
Dim r As Range, sh As Worksheet, bondR As Range, bondSh as Worksheet
set sh = ActiveSheet
set r = sh.range("A1")
Set bondSh = Worksheets("Bonds")
Set bondR = bondSh.Range("J1")
For i = 1 To 10
r.formula = "=BDS(bondR.offset(i,0) & "" ISIN"",""ISSUE_UNDERWRITER"",""Headers"",""Y"")"
Set r = r.Offset(i, 0)
Next i
End Sub
Here I'm defining one range object, r, to track the location on the active sheet, and another, bondR, for the location on the "Bonds" sheet. Once the initial locations of these ranges are defined, you can manipulate them using the .offset(row,col) function as I've done with the simple for-loop, moving down 1 row (but 0 columns) in each loop.
Feel free to ask questions.

Finding last row in column when adjacent column has data past original column end point

I have an excel sheet that has two columns G and H. Column G has 25 rows that are not empty and column H has 15 columns. I have written some vba code to find the last row in column H but it selects all the way down to column G's end not stopping at column H's end. Is there a way to write the code to not look at whats in column G? I have added the code I have below.
Thanks!
ws.Range("H2:H" & Range("H" & Rows.count).End(xlUp).Select
Quite easy to avoid any NULL cells at the bottom column column H:
Sub dural()
Dim nr As Long
nr = [MAX((H:H<>"")*(ROW(H:H)))]
Range("H" & nr).Select
End Sub
This is quite slow so consider replacing H:H with something like H1:H9999
Try this line instead of the one you have:
ws.Range("H2", ws.Range("H:H").Find("*", , , , , xlPrevious)).Select
It will find the last cell with a value that is not "".
The photo shows that there is a formula in H11:
But the following code:
Sub finnnn()
Dim ws As Worksheet
Set ws = Sheets("Sheet13")
Debug.Print ws.Range("H1", ws.Range("H:H").Find("*", , , , , xlPrevious)).Address
End Sub
When run lists $H$1:$H$5 in the immediate window:

Macro to select one cell if two other cells match

I need a Macro (must be a macro) that will select a cell if - and only if - two cells match. =IF(a3=k8) select k9. A3 is static, but the matching data can be anywhere along a row range. Therefore, I need to look for the data in a3 in the range k8:bz8, and in every case, follow by selecting the cell directly below it. Basically HLOOKUP. Once that cell is selected i will call another macro to populate that cell.
I am using Office 2016 for Mac (which sux)
Thanks
Don
Presumably you shouldn't have any trouble with the WorksheetFunction object using HLOOKUP function with a wildcard search.
dim val as variant
with activesheet
on error goto no_match
val = worksheetfunction.hlookup(chr(42) & .range("a3").value & chr(42), .range("k8:bz9"), 2, false)
on error goto 0
end with
debug.print val
no_match:
if err.number = 1004 Then _
debug.print "no match"
I think I would do a Do Until Loop. Something like:
Range("A8").Select
Do Until Selection = Range("A3").Value
ActiveCell.Offset(0, 1).Select
Loop
ActiveCell.Offset(0, 1).Select
To test it I put the value 14 in cell A3. Then I put a bunch of different values in each cell along row 8. I put 14 in k8. The macro will look at each cell and see if it equals 14 and then move on. You'll need an exit condition if you run out of data but that should get you started.

adding new rows in excel without breaking a vba macro that uses Range.Value

I've written a macro in VBA that simply fills in a given cell's value from another cell in that sheet. I do this for lots of cells in the sheet, and I'm doing it like so:
Range("B3").Value = Range("B200")
Range("B4").Value = Range("B201")
'etc.
Now, I am often adding values by inserting new rows, so I might insert a new row
between B200 and B201, which will break the macro because it doesn't autoupdate when
I insert the new row.
How can I code the macro so it autoupdates the cell references when I insert new rows or columns?
My suggestion would be to make sure the ROW you want to retrieve values from has a unique value in it that you can .FIND anytime you want, then grab your values from column B of that found cell's row. So right now you want to get a value in B200 and A200 always has the text in it: "Final Total" and that is unique.
Dim MyRNG As Range
Set MyRNG = Range("A:A").Find("Final Total", LookIn:=xlValues, LookAt:=xlWhole)
Range("B3").Value = Range("B" & MyRNG.Row)
Range("B4").Value = Range("B" & MyRNG.Row + 1)
This is not an answer but an alternative.
Naming your range is the way to go as Shiin suggested but then if you have 500 cells then like I mentioned earlier, naming 500 cells and using them in your code can be very painful. The alternative is to use smart code. Let's take an example
Let's say you have a code like this
Sub Sample()
Range("B3").Value = Range("B200")
Range("B4").Value = Range("B201")
Range("B5").Value = Range("B201")
' And
' So On
' till
Range("B500").Value = Range("B697")
End Sub
The best way to write this code is like this
Sub Sample()
Dim i As Long
For i = 200 To 697
Range("B" & i - 197).Value = Range("B" & i)
Next i
End Sub
and say if you insert a line at say row 300 then simply break the above code in two parts
Sub Sample()
Dim i As Long
For i = 200 To 299
Range("B" & i - 197).Value = Range("B" & i)
Next i
For i = 301 To 698
Range("B" & i - 197).Value = Range("B" & i)
Next i
End Sub
So every time you insert a row, simply break the for loop into an extra part. This looks tedious but is much better than naming 500 cells and using them in your code.
If you are planning to use the macro only once (i.e for 1 time use) then read ahead.
If you are worried that when the user inserts the row then the cells are not updated then you can instead of assigning a value, assign a formula.
For example
Range("B3").Formula = "=B200"
This will put a formula =B200 in cell B3. So next time when you insert a row so that the 200th row moves it's position, you will notice that the formula automatically gets updated in cell B3
HTH
Try giving a name to the range. If you refer to the range by name Excel searches for it and retrieves the rows that defines it. Range names update their definition when new rows are added.
Adding to the above, i think this tutorial illustrates my point:
http://www.homeandlearn.co.uk/excel2007/excel2007s7p6.html this is how to define the name of the range.
This tutorial explains how to use it on macros and vba:
http://excel.tips.net/T003106_Using_Named_Ranges_in_a_Macro.html
I hope this helps :D

Resources