Subscript out of range on VBA - vba

I am writing my first VBA. I have a sheet named Sheet1. That sheet has a column E; I would like to delete all rows which have an empty field on column E.
Therefore, I wrote this code:
Sub EmptyCells()
Sheets("Sheet1").Columns("E:E").SpecialCells(xlBlanks).EntireRow.Delete
End Sub
However, when I run it, I get this error:
Subscript out of range
Why is this error occurring? I am sure the column E exists in Sheet1. Are my references incorrect?
EDIT
If I try Columns("E") or Range("E:E"), instead of Columns("E:E") I get the same error

Your code will work if there are any REAL empty cells in column E (within UsedRange).
You may have cells that contain formulas returning Null. SpecialCells does not consider them empty. You may have cells in column E containing Null as a constant; SpecialCells also considers them filled.
EDIT#1:
Based upon your specific error message make sure the worksheet name is spelled correctly. Sheet1 is not the same as Sheet 1

Your code works if you have a sheet named/titled Sheet1.
Sub EmptyCells()
Sheets("Sheet1").Columns("E:E").SpecialCells(xlBlanks).EntireRow.Delete
End Sub
Note that there are different ways to call a sheet.
Sheets("Sheet1") 'means the visible name of the sheet is `Sheet1` (not the same as VBA name)
'the number doesn't tell anything about it's position, it's just a name.
Sheet1 'means the VBA name of the sheet.
'the number doesn't tell anything about it's position, it's just a name.
Worksheets(1) 'means the first worksheet (which ever is in the first position)
Sheets(1) 'means the first sheet (can also be a chart not only a worksheet)
'this has no relation to its name which could be "Sheet5"
'(If "Sheet5" is in first position).

I have tried this and it works:
Option Explicit
Sub TetsMe()
MsgBox (Worksheets(1).Parent.Name & VbCrLf & Worksheets(1).Name)
Worksheets(1).Columns("E:E").SpecialCells(xlBlanks).EntireRow.Delete
End Sub
The different syntax as the index may refer to a different sheet. In this case Worksheets(1) is the first worksheet in the workbook.
The MsgBox() will tell you which worksheet and which workbook you are changing. Once you know, what you are doing, you may remove it.
If the problem is in the workbook name, then it is easy to change it like this:
With Workbooks("NameYourWorkbook").Worksheets("NameYourWorksheet")
.Columns("E:E").SpecialCells(xlBlanks).EntireRow.Delete
End With

Related

Use cell value to activate another sheet then clear original cell value without an error

I have cell A1 on a sheet named "Data" that looks for input which when received, looks for a sheet name that matches it. If it finds a match, it opens that sheet. I'm trying to clear the value entered in A1 of "Data" after that second sheet has been opened however I'm getting a runtime error that appears to still be looking for the data used to open the second sheet. Here is the code for the "Data" sheet:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Range("A1"), Target) Is Nothing Then Exit Sub
Sheets(Target.Value).Activate
End Sub
I tried using a variable in place of Target.Value hoping that after deleting the actual data in A1, the variable would satisfy the code.
I've ran the following line on at the end of the block above as well as on the sheet which gets activated but either way I get an error.
Sheets("Data").Range("A1:A1").ClearContents
The error is "Run-time error 9 Subscript out of range.
How do I clear the contents of A1 on "Data" so it's ready to receive another request to open another sheet when I'm done with the last one?
This is the correct syntax for a single cell:
Sheets("Data").Range("A1").ClearContents
...however using a range of A1:A1 should also work, so if you're getting Subscript Out Of Range then there is likely no worksheet named Data.
If you have multiple workbooks open then by default, it's looking for the Active Workbook (whose name in contained in ActiveWorkbook.Name.) So if you're going to be working with multiple workbooks, you should explicitly state the workbook name as well:
Workbooks("Book1").Sheets("Sheet1").Range("A1").ClearContents
I didn't need to clear the value after all. I added a couple lines to ensure when returning to the "Data" sheet, cell A1 was selected. This allows for a new value to be entered replacing the previous value and serves the purpose.
Just a slight change to your code. "Is Nothing" does not work. The below code works fine for me.
If Intersect(Target, Range("A1")) = "" Then Exit Sub
Sheets(Target.Value).Activate
Target.ClearContents

Copy Row A1 from Sheet 1 into Row A1 Sheet 2

I basically just need to know how to copy a header from sheet one that goes from A1-O1 into sheet two, three, four, five and so on...they all have the same header. Sheet one is on the right and sheet two is left and increases to the left. I tried this which I found on some website but it says object required. The error is Runtime Error 424
mainworkBook.Sheets(“Sheet1”).Rows(1).EntireRow.Copy
mainworkBook.Sheets(“Sheet2”).Range(“A1”).Select
mainworkBook.Sheets(“Sheet2”).Paste
A small loop code.let me know if it works.
Sub COPYPASTeHEADER()
Dim K As Integer
For K = 2 To ActiveWorkbook.Sheets.Count
Sheets("All_Data").Range("A1:O1").COPY Sheets(K).Range("A1")
Next
End Sub
You can do something like this instead of using Select:
For Each Sheet In ThisWorkbook.Sheets
ThisWorkbook.Sheets("ALL_DATA").Rows(1).Copy Destination:=Worksheets(Sheet.Name).Range("A1")
Next
This will loop through each sheet in your workbook, take the range you provided (row 1 from Sheet1), and paste it to each sheet by referencing the Name property of each Sheet you are looping through.
The error may have been from the workbook variable, as that is the only thing that is unclear.
I would also recommend looking into this post: How to avoid using Select in Excel VBA macros as it is tremendously helpful in avoiding Select/Activate when possible, which is a common occurrence among those who learn VBA through recording Macros.
Let me know if it works for you.
This is an excellent place to use a loop. For each sheet in the workbook, paste the same header.
Sub forEachWs()
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
Call pasteContents(ws)
Next
End Sub
Sub pasteContents(ws as Worksheet)
** Your code goes here
End Sub
EDIT: The ** section could be as such:
Sub pasteContents(ws as Worksheet)
ActiveWorkbook.Sheets(“Sheet1”).Rows(1).EntireRow.Copy
ActiveWorkbook.Sheets(ws).Range(“A1”).Select
ActiveWorkbook.Sheets(ws).Paste
End Sub
Or it could also be...
Sub pasteContents(ws as Worksheet)
ActiveWorkbook.Sheets("Sheet1").Rows(1).Copy Destination:=Worksheets(ws).Range("A1")
End Sub

Copy a static range on one sheet, and paste in a dynamic range in another sheet based on a single value in a cell

I have three parts to this problem. I have a single cell with a Week number in Sheet1!A1. I have a static range in Sheet1!B1:F1 that needs to be copied. Then I need to paste the value in a dynamic range in Sheet2 offset by the week number for rows. This is part of a larger macro I am writing for a sheet I use regularly, but I seem to have those parts down. I may be either oversimplifying or oversimplifying but this is what I have currently.
Sub CopyPaste()
Sheets(1).Range("B1:F1").Copy
OffsetRange = Sheets(1).Cells(1,1).Value
Sheets(2).Cells(1+OffsetRange,1).Paste
End Sub
When I run this, it either gives me a Runtime Error 9 or Runtime Error 438.
Anyone know whats causing these errors? When I paste the range, does the cells object point towards the first cell of the copied range when I paste in at the location?
Try it as,
Option Explicit
Sub CopyPasteOffset()
Dim OffsetRange As Long
OffsetRange = Worksheets(1).Cells(1, 1).Value
Worksheets(1).Range("B1:F1").Copy _
Destination:=Worksheets(2).Cells(1 + OffsetRange, 1)
End Sub
The .Paste method is a member of Worksheet, not Range or Cells. You may have it confused with .PasteSpecial which is a member of the Range object. In any event, it is unnecessary as a destination can be applied directly to the copy command.

excel vba calculate code doesn't calculate some of the formulas in merged cells

I calculate the formulas in different sheets using:
Sub Calculate_Formulas_otherSheets()
Dim Sheet As Worksheet
For Each Sheet In ActiveWorkbook.Sheets
If Sheet.Name Like "*" & strSearch & "_A" Then
Sheets(Sheet.Name).Calculate
End If
Next
For Each Sheet In ActiveWorkbook.Sheets
If Sheet.Name Like "*" & strSearch & "_B" Then
Sheets(Sheet.Name).Calculate
End If
Next
End Sub
in these sheets, three of the formulas are in merged cells.
formula 1 in AY3
=RIGHT(CELL("filename");LEN(CELL("filename"))-FIND("]";CELL("filename")))
formula 2 in AZ3
=IFERROR(RIGHT(LEFT($AY3;FIND("_";$AY3)-4);2);"")
formula 3 in BA3
=IFERROR(RIGHT(LEFT($AY3;FIND("_";$AY3)-3);1);"")
everything works perfect if i calculate them manually. But when I do it via the above code, they don't get calculated; other formulas in the sheets do get calculated except these three.
What is going wrong?
By the way, the automatic calculation is off.
UPDATE
actually it gets updated in a wrong way: the filename formula gets the sheet name of the sheet in which this vba code is saved as a macro button. How to fix it?
As documented, the second parameter of the CELL function, reference, controls the cell you want information about, and:
If omitted, the information ... is returned for the last cell that was changed.
You are omitting the second parameter, and apparently the last cell that changed happens to be inside a wrong workbook.
Provide a correct cell in the second parameter.

Get the cell reference of the value found by Excel INDEX function

The Problem
Assume that the active cell contains a formula based on the INDEX function:
=INDEX(myrange, x,y)
I would like to build a macro that locates the value found value by INDEX and moves the focus there, that is a macro changing the active cell to:
Range("myrange").Cells(x,y)
Doing the job without macros (slow but it works)
Apart from trivially moving the selection to myrange and manually counting x rows y and columns, one can:
Copy and paste the formula in another cell as follows:
=CELL("address", INDEX(myrange, x,y))
(that shows the address of the cell matched by INDEX).
Copy the result of the formula above.
Hit F5, Ctrl-V, Enter (paste the copied address in the GoTo dialog).
You are now located on the very cell found by the INDEX function.
Now the challenge is to automate these steps (or similar ones) with a macro.
Tentative macros (not working)
Tentative 1
WorksheetFunction.CELL("address", ActiveCell.Formula)
It doesn't work since CELL for some reason is not part of the members of WorksheetFunction.
Tentative 2
This method involves parsing the INDEX-formula.
Sub GoToIndex()
Dim form As String, rng As String, row As String, col As String
form = ActiveCell.Formula
form = Split(form, "(")(1)
rng = Split(form, ",")(0)
row = Split(form, ",")(1)
col = Split(Split(form, ",")(2), ")")(0)
Range(rng).Cells(row, CInt(col)).Select
End Sub
This method actually works, but only for a simple case, where the main INDEX-formula has no nested subformulas.
Note
Obviously in a real case myrange, x and ycan be both simple values, such as =INDEX(A1:D10, 1,1), or values returned from complex expressions. Typically x, y are the results of a MATCH function.
EDIT
It was discovered that some solutions do not work when myrange is located on a sheet different from that hosting =INDEX(myrange ...).
They are common practice in financial reporting, where some sheets have the main statements whose entries are recalled from others via an INDEX+MATCH formula.
Unfortunately it is just when the found value is located on a "far" report out of sight that you need more the jump-to-the-cell function.
The task could be done in one line much simpler than any other method:
Sub GoToIndex()
Application.Evaluate(ActiveCell.Formula).Select
End Sub
Application.Evaluate(ActiveCell.Formula) returns a range object from which the CELL function gets properties when called from sheets.
EDIT
For navigating from another sheet you should first activate the target sheet:
Option Explicit
Sub GoToIndex()
Dim r As Range
Set r = Application.Evaluate(ActiveCell.Formula)
r.Worksheet.Activate
r.Select
End Sub
Add error handling for a general case:
Option Explicit
Sub GoToIndex()
Dim r As Range
On Error Resume Next ' errors off
Set r = Application.Evaluate(ActiveCell.Formula) ' will work only if the result is a range
On Error GoTo 0 ' errors on
If Not (r Is Nothing) Then
r.Worksheet.Activate
r.Select
End If
End Sub
There are several approaches to select the cell that a formula refers to...
Assume the active cell contains: =INDEX(myrange,x,y).
From the Worksheet, you could try any of these:
Copy the formula from the formula bar and paste into the name box (to the left of the formula bar)
Define the formula as a name, say A. Then type A into the Goto box or (name box)
Insert hyperlink > Existing File or Web page > Address: #INDEX(myrange,x,y)
Adapt the formula to make it a hyperlink: =HYPERLINK("#INDEX(myrange,x,y)")
Or from the VBA editor, either of these should do the trick:
Application.Goto Activecell.FormulaR1C1
Range(Activecell.Formula).Select
Additional Note:
If the cell contains a formula that refers to relative references such as =INDEX(A:A,ROW(),1) the last of these would need some tweaking. (Also see: Excel Evaluate formula error). To allow for this you could try:
Range(Evaluate("cell(""address""," & Mid(ActiveCell.Formula, 2) & ")")).Select
This problem doesn't seem to occur with R1C1 references used in Application.Goto or:
ThisWorkbook.FollowHyperlink "#" & mid(ActiveCell.FormulaR1C1,2)
You could use the MATCH() worksheet function or the VBA FIND() method.
EDIT#1
As you correctly pointed out, INDEX will return a value that may appear many times within the range, but INDEX will always return a value from some fixed spot, say
=INDEX(A1:K100,3,7)
will always give the value in cell G3 so the address is "builtin" to the formula
If, however, we have something like:
=INDEX(A1:K100,Z100,Z101)
Then we would require a macro to parse the formula and evaluate the arguments.
Both #lori_m and #V.B. gave brilliant solutions in their own way almost in parallel.
Very difficult for me to choose the closing answer, but V.B. even created Dropbox test file, so...
Here I just steal the best from parts from them.
'Move to cell found by Index()
Sub GoToIndex()
On Error GoTo ErrorHandler
Application.Goto ActiveCell.FormulaR1C1 ' will work only if the result is a range
Exit Sub
ErrorHandler:
MsgBox ("Active cell does not evaluate to a range")
End Sub
I associated this "jump" macro with CTRL-j and it works like a charm.
If you use balance sheet like worksheets (where INDEX-formulas, selecting entries from other sheets, are very common), I really suggest you to try it.