Problems with Range - vba

Why doesn't the second format of Range(Cells(),Cells()) usage work?
Sub start()
Dim ws As Worksheet
Dim wb As Workbook
Dim cond_rng As Range
Set ws = Application.Workbooks("ndata.xlsm").Worksheet("conditionsSheet")
' This works and selects one cell
Set cond_rng = ws.Cells(4, 1)
cond_rng.Select
'this works as expected
Set cond_rng = ws.Range("A1:B10")
cond_rng.Select
'this fails with error 1004
Set cond_rng = ws.Range(Cells(1, 1), Cells(4, 4))
cond_rng.Select

Ok, well this works:
'this works
Set cond_rng = ws.Range(ws.Cells(1, 1), ws.Cells(4, 4))
cond_rng.Select
or
With Sheets("conditionsSheet")
.Range(.Cells(1, 1), .Cells(4, 4)).Select
End With
The .Cells is important, as it won't work with just Cells.

I tested with a simple sub like the below and it works. I think your error is coming from missing "s" after "worksheet".
Set ws = Application.Workbooks("ndata.xlsm").Worksheet("conditionsSheet")
should be ...Worksheets....
sub TEST()
Dim ws As Worksheet
Dim cond_rng As Range
Set ws = Worksheets("sheet1")
Set cond_rng = ws.Range(Cells(1, 1), Cells(5, 4))
cond_rng.Value = 5
End Sub

I believe it is the range.select that is confusing people. you will usually get an error if you are trying to select a range from a non-active worksheet.
If you are trying to get values from that range in another sheet or need to add info into that range, you don't have to select it. For example: the below code will loop through each sheet and copy A1:D4(excluding PasteSheet) and paste it into PasteSheet.
For this example make sure you have a sheet named, "PasteSheet"
Sub SheetLoop()
Dim ws As Worksheet
Dim sh As Worksheet
Set ws = Sheets("PasteSheet")
For Each sh In Sheets
If sh.Name <> ws.Name Then
With sh
.Range(.Cells(1, 1), .Cells(4, 4)).Copy ws.Cells(Rows.Count, "A").End(xlUp).Offset(1, 0)
End With
End If
Next sh
End Sub
You can run this code from any sheet in the workbook because you don't have to select anything.
So if for example Sheet2 A1=2 then sheet1(A1:D4) color is red else it is Blue.
Sub Button2_Click()
Dim ws As Worksheet, x
Dim sh As Worksheet, rng As Range, Crng As Range
Set ws = Sheets("Sheet1")
Set sh = Sheets("Sheet2")
Set rng = sh.Range("A1")
Set Crng = ws.Range(ws.Cells(1, 1), ws.Cells(4, 4))
x = IIf(rng = 2, vbRed, vbBlue)
Crng.Interior.Color = x
End Sub

Related

VBA - Remove Duplicates Across Multiple Sheets in Workbook

I have multiple sheets in a particular workbook, and n each sheet there are Employee Numbers. The sheets have already been sorted in a way that Column A is always the Employee Number.
So what I need to do is loop through all the sheets and apply the RemoveDuplicates function to delete all duplicate Employee Numbers found in Column A.
Note - I am not trying to have the Employee Number appear on only one sheet; I am trying to have the Employee Number appear only once on each sheet.
I have it working for when I name a specific sheet, but cannot get it to work in a loop.
Test1:
Sub deleteDuplicate()
Dim ws As Worksheet
Dim wkbk1 As Workbook
Dim w As Long
Dim lRow As Long
Dim iCntr As Long
Set wkbk1 = Workbooks("3rd Party.xlsm")
wkbk1.Activate
For Each ws In ThisWorkbook.Worksheets
' Find last row in column A
lRow = ws.Range("A" & ws.Rows.count).End(xlUp).Row
For iCntr = lRow To 1 Step -1
ws.lRow.RemoveDuplicates Columns:=1, Header:=xlYes
Next iCntr
Next ws
End Sub
Test2:
Sub deleteDuplicate()
Dim ws As Worksheet
Dim wkbk1 As Workbook
Dim w As Long
Dim lRow As Long
Dim iCntr As Long
Set wkbk1 = Workbooks("3rd Party.xlsm")
wkbk1.Activate
With wkbk1
For w = 1 To .Worksheets.count
With Worksheets(w)
.UsedRange.RemoveDuplicates Columns:=1, Header:=xlYes
End With
Next w
End With
End Sub
The issue in both tests
Set wkbk1 = Workbooks("3rd Party.xlsm") - it implies the code is not in ThisWorkbook, yet
Test 1 uses ThisWorkbook - explicitly (For Each ws In ThisWorkbook.Worksheets)
Test 2 uses ThisWorkbook - implicitly (With Worksheets(w))
For this to work the file "3rd Party.xlsm" must be open at the same time
Try the versions bellow, and if the code is not running in ThisWorkbook, update wb accordingly
(ThisWorkbook is the file where the VBA code is executed from)
.
Version 1 - determine last row and last column
Option Explicit
Public Sub DeleteDuplicates1()
Dim wb As Workbook, ws As Worksheet, lr As Long, lc As Long, ur As Range
On Error Resume Next 'Expected error: wb not found
Set wb = ThisWorkbook 'Workbooks("3rd Party.xlsm")
If Not wb Is Nothing Then
Application.ScreenUpdating = False
For Each ws In wb.Worksheets
lr = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
lc = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
Set ur = ws.Range("A1", ws.Cells(lr, lc))
ur.RemoveDuplicates Columns:=Array(1), Header:=xlYes
Next
Application.ScreenUpdating = True
End If
End Sub
.
Version 2 - UsedRange
Public Sub DeleteDuplicates2()
Dim wb As Workbook, ws As Worksheet
On Error Resume Next 'Expected error: wb not found
Set wb = ThisWorkbook 'Workbooks("3rd Party.xlsm")
If Not wb Is Nothing Then
Application.ScreenUpdating = False
For Each ws In wb.Worksheets
ws.UsedRange.RemoveDuplicates Columns:=Array(1), Header:=xlYes
Next
Application.ScreenUpdating = True
End If
End Sub
If nothing happens when you run either of these versions, the file "3rd Party.xlsm" doesn't exist.
Either it's not open currently, or the name is different - maybe "3rd Party.xlsx" (with an x)
.
If you still have errors for Version 2, .UsedRange may not be what you expect
Try cleaning extra rows and columns with this Sub
Public Sub RemoveEmptyRowsAndColumns()
Dim wb As Workbook, ws As Worksheet, lr As Long, lc As Long, er As Range, ec As Range
On Error Resume Next 'Expected error: wb not found
Set wb = ThisWorkbook 'Workbooks("3rd Party.xlsm")
If Not wb Is Nothing Then
Application.ScreenUpdating = False
For Each ws In wb.Worksheets
lr = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
lc = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
If lr > 1 And lc > 1 Then
Set er = ws.Range(ws.Cells(lr + 1, "A"), ws.Cells(ws.Rows.Count, "A"))
Set ec = ws.Range(ws.Cells(1, lc + 1), ws.Cells(1, ws.Columns.Count))
er.EntireRow.Delete 'Shift:=xlUp
ec.EntireColumn.Delete 'Shift:=xlToLeft
End If
Next
Application.ScreenUpdating = True
End If
End Sub

VBA: object doesn't support this property or method

I wrote a very simple macro, that opens another workbook and select range of data from this workbook.
However, I keep receiving this warning: object doesn't support this property or method
What is wrong?
Sub data()
Dim wb As Workbook
Dim ws As Worksheet
Dim filename As String
Dim lastrow As Integer
Dim lastcolumn As Integer
Dim range_to_copy As Range
'open workbook
filename = "C:\Users\mk\Desktop\sales report\Sales Report.xls"
Set wb = Workbooks.Open(filename)
Set ws = wb.Sheets("data")
lastcolumn = wb.ws.Cells(1, wb.ws.Columns.Count).End(xlToLeft).Column
lastrow = wb.ws.Cells(wb.ws.Roows.Count, 1).End(xlToLeft).Row
range_to_copy = Range("Cells(1,1):Cells(lastrow,lastcolumn)")
End sub
A number of things wrong.
Edit:
Dim lastrow As Integer
Dim lastcolumn As Integer
An Integer can store numbers up to 32,767. This won't be a problem for columns, but will throw an overflow error on the row number. It's better to use the Long data type - numbers up to 2,147,486,647.
The ws variable already references the workbook so you just need:
lastcolumn = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
lastrow = wb.ws.Cells(wb.ws.Roows.Count, 1).End(xlToLeft).Row
Rows only has one o in it.
Edit: xlToLeft looks at the right most cell and works to the left. As you're looking for rows you need to use xlUp which looks at the last cell and works up.
range_to_copy = Range("Cells(1,1):Cells(lastrow,lastcolumn)")
This is an object so you must Set it. The cells references are separated by a comma and should not be held as a string.
Sub data()
Dim wb As Workbook
Dim ws As Worksheet
Dim filename As String
Dim lastrow As Long
Dim lastcolumn As Long
Dim range_to_copy As Range
'open workbook
filename = "C:\Users\mk\Desktop\sales report\Sales Report.xls"
Set wb = Workbooks.Open(filename)
Set ws = wb.Sheets("data")
lastcolumn = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
lastrow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
Set range_to_copy = ws.Range(ws.Cells(1, 1), ws.Cells(lastrow, lastcolumn))
End Sub
Note: Every range reference is preceded by the worksheet reference. Without this it will always look at the currently active sheet so if you aren't on the data sheet the following will fail as the second cell reference will look at the activesheet.
ws.Range(ws.Cells(1, 1), Cells(lastrow, lastcolumn))
It might be worth checking out the With....End With code block.
There are several errors in your code.
Try
lastcolumn = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
Set range_to_copy = Range(ws.Cells(1, 1), ws.Cells(lastRow, lastcolumn))
Once you defined and set your ws worksheet object, you don't need to refer to the wb object anymore, since your ws worksheet object is fully quallified with Sheets("data") in wb workbook.
Now, all you need to do is use the With statement, like in the code below:
Set ws = wb.Sheets("data")
With ws
lastcolumn = .Cells(1, .Columns.Count).End(xlToLeft).Column
lastrow = .Cells(.Rows.Count, 1).End(xlUp).Row
Set range_to_copy = .Range(.Cells(1, 1), .Cells(lastrow, lastcolumn))
End With

Copy range between workbooks

I am trying to copy a range of cells on a sheet in one workbook to the bottom of a sheet in another workbook. I keep getting "Application-defined or object-defined error" on the copy line.
Dim NewFileName As String
Dim BAHFileName As String
NewFileName = "Filename"
BAHFileName = "Other Filename"
LastRow = Sheets("All").UsedRange.Rows.Count
Workbooks(NewFileName).Sheets("All").Range(Cells(2, 1), Cells(LastRow, 15)).Copy
Windows(BAHFileName & ".xlsx").Activate
LastRow = Workbooks(BAHFileName).Sheets(1).UsedRange.Rows.Count + 1
Workbooks(BAHFileName).Sheets(1).Cells(LastRow, 1).Select
ActiveSheet.Paste
Application.CutCopyMode = False
Talking to yourself?
Practise with this code to avoid using selects.
I am not sure of the situation of your workbooks, so you will have to adjust workbook names and sheet names accordingly.
Sub Button1_Click()
Dim WB As Workbook
Dim bk As Workbook
Dim LastRow As Long
Dim Lrow As Long
Dim rng As Range
Dim ws As Worksheet
Dim sh As Worksheet
Set WB = ThisWorkbook
Set bk = Workbooks("MyWorkbook.xlsx")
Set ws = WB.Sheets("All")
Set sh = bk.Sheets(1)
With ws
LastRow = .UsedRange.Rows.Count
Set rng = .Range(.Cells(2, 1), .Cells(LastRow, 15))
End With
With sh
Lrow = .UsedRange.Rows.Count + 1
rng.Copy .Cells(Lrow, 1)
End With
End Sub
I needed to select the sheet before copying.
Dim NewFileName As String
Dim BAHFileName As String
NewFileName = "Filename"
BAHFileName = "Other Filename"
LastRow = Sheets("All").UsedRange.Rows.Count
Sheets("All").Select
Workbooks(NewFileName).Sheets("All").Range(Cells(2, 1), Cells(LastRow, 15)).Copy
Windows(BAHFileName & ".xlsx").Activate
LastRow = Workbooks(BAHFileName).Sheets(1).UsedRange.Rows.Count + 1
Workbooks(BAHFileName).Sheets(1).Cells(LastRow, 1).Select
ActiveSheet.Paste
Application.CutCopyMode = False

Issue Creating Autofill Macro with a VBA Function

I am having an issue creating a macro that will autofill a VBA function named "FindMyOrderNumber". Every time I run a macro to Autofill "FindMyOrderNumber" only the first cell in the column is populated.
This function will look up an order number in column A (A1) and return the name of the worksheet it can be found B (B1).
Option Explicit
Function FindMyOrderNumber(strOrder As String) As String
Dim ws As Worksheet
Dim rng As Range
For Each ws In Worksheets
If ws.CodeName <> "Sheet3" Then
Set rng = Nothing
On Error Resume Next
Set rng = ws.Cells.Find(What:=strOrder, LookAt:=xlWhole)
On Error GoTo 0
If Not rng Is Nothing Then
FindMyOrderNumber = ws.Name
Exit For
End If
End If
Next
Set rng = Nothing
Set ws = Nothing
End Function
I created this macro to enter my VBA function "=findmyordernumber(a1)" in cell B1 then to Autofill column B.
Sub AutofillVBAFunction()
Range("B1").Select
ActiveCell.FormulaR1C1 = "=FindMyOrderNumber(RC[-1])"
Selection.Autofill Destination:=Range("B1:B68")
Range("B1:B68").Select
End Sub
After I run this macro only B1 is populated.
Sorry if this has been discussed I am new and I tried How to fill-up cells within a Excel worksheet from a VBA function? and other questions and I could not apply it to my issue.
Please help
Add application.volatile to the function, that way it will calculate as the sheet changes.
Function FindMyOrderNumber(strOrder As String) As String
Dim ws As Worksheet
Dim rng As Range
Application.Volatile
For Each ws In Worksheets
If ws.CodeName <> "Sheet3" Then
Set rng = Nothing
On Error Resume Next
Set rng = ws.Cells.Find(What:=strOrder, LookAt:=xlWhole)
On Error GoTo 0
If Not rng Is Nothing Then
FindMyOrderNumber = ws.Name
Exit For
End If
End If
Next
Set rng = Nothing
Set ws = Nothing
End Function
It also wouldn't hurt to calculate the sheet when You add the formula to the range.
Sub Button1_Click()
Dim Rws As Long, Rng As Range
Rws = Cells(Rows.Count, "A").End(xlUp).Row
Set Rng = Range(Cells(1, 2), Cells(Rws, 2))
Rng = "=FindMyOrderNumber(RC[-1])"
End Sub

Selecting a Range with Merge Cells

So there is a workbook that runs a macro that was made by another group in the company and its GARBAGE but they locked it and wont let me modify the VBA. So I am trying to pull the output from that workbook into mine. The headers of the range are in merged rows with the first 11 rows being taken up by the buttons to run the macro.
Here is my current code
Sub Pull_Data()
Dim returnValue As Variant
Dim wb As Workbook
Dim ws As Worksheet
Dim wb2 As Workbook
Dim ws2 As Worksheet
Set wb2 = Application.Workbooks("name.xlsm")
Set ws2 = wb2.Worksheets("INPUT")
Dim rng As Range
r = Range("H65536").End(xlUp).Row
Set ws = wb.Worksheets("Report")
ws.Range("A11:A13").Select
Set rng = ws.Range(Cells(11, 1), Cells(r, 8))
rng.Select
rng.Copy
wb2.Activate
ws.Range(Cells(1, 1), Cells(r, 8)).PasteSpecial xlPasteAll
End Sub
My issue is that when i try to select the entire output it sometimes selects what i want (A11 to H then the last row with value) but sometimes it selects A1:H11 and its frustrating as hell to figure out the issue. If there is a better way I would love to know.
EDIT:
Updated code
Sub Pull_Data()
Dim returnValue As Variant
Dim wb As Workbook
Dim ws As Worksheet
Dim wb2 As Workbook
Dim ws2 As Worksheet
Set wb2 = Application.Workbooks("name.xlsm")
Set ws2 = wb2.Worksheets("INPUT")
Dim rng As Range
r = Application.Max(Range("H65536").End(xlUp).Row, 11)
Set ws = wb.Worksheets("Report")
ws.Range("A11:A13").Select
Set rng = ws.Range(Cells(11, 1), Cells(r, 8))
rng.Select
rng.Copy
wb2.Activate
ws.Range(Cells(1, 1), Cells(r, 8)).PasteSpecial xlPasteAll
End Sub
r = Application.Max(Range("H65536").End(xlUp).Row, 11) 'wich sheet is the range assiciated with ?
Set ws = wb.Worksheets("Report")
ws.Range("A11:A13").Select 'how is this line usefull at all ?
Set rng = ws.Range(Cells(11, 1), Cells(r, 8)) ' change to ws.Range(ws.Cells(11, 1), ws.Cells(r, 8))
rng.Select 'delete this line
rng.Copy '
wb2.Activate
ws.Range(Cells(1, 1), Cells(r, 8)).PasteSpecial xlPasteAll 'change to ws.Range(ws.Cells(1, 1), ws.Cells(r, 8)).PasteSpecial xlPasteAll
Rather than pulling data from garbage.xlsm into your workbook, copy the entire worksheet into your workbook.
Then in your version of the worksheet, remove the merging, etc.