I am trying to write some code that cycles through a range of values and return either a 1 or 0. The code will only run if I select the sheet the calculation takes place in, even though I am telling the procedure that the range it is dealing with is in that sheet. I want this sheet to be very hidden as other people will use this document and I don't want them messing with the formatting. I have named the sheet in the VB as 'Binary' as well. I am still very new to VBA and am trying to learn new things about this language.
I have tried several things to fix the issue, but it breaks when I don't explicitly say to select the sheet. I've commented below in the code where it is the code breaks and I can't find a solution. Printing my debug statements give me the correct values, and the entire project runs correctly as long as I explicitly tell the procedure to select the sheet. I would prefer if there is a solution that does not require me to tell the code to hide/unhide sheets, and have the sheet remain veryhidden.
Sub Binary_Check()
Dim binaryWS As Worksheet
Dim summaryLastRow As Long
Dim summaryLastColumn As Long
Dim BinaryRng As Range
'binaryWS.Visible = xlSheetVisible
Set binaryWS = Binary
'Taking away this next line will break where I set BinaryRng
Binary.Select
summaryLastRow = binaryWS.Range("A" & Rows.Count).End(xlUp).Row
summaryLastColumn = binaryWS.Cells(1, Columns.Count).End(xlToLeft).Column
'Debug.Print summaryLastColumn
'Debug.Print summaryLastRow
'This is what breaks and gives me an error saying Method Range of object _worksheet failed
Set BinaryRng = binaryWS.Range("B2", Cells(summaryLastRow, summaryLastColumn))
'Debug.Print BinaryRng.Address
For Each cell In BinaryRng
If InStr(cell, "(") > 0 Then
cell.Value = 1
Else
cell.Value = 0
End If
Next cell
'binaryWS.Visible = xlSheetHidden
End Sub
If you use the .Cells, .Rows, .Columns method, you have to add the Worksheet reference. Otherwise it will assign an Active Worksheet to that method.
Set BinaryRng = binaryWS.Range("B2", binaryWS.Cells(summaryLastRow, summaryLastColumn))
Usually I would use the With...End With statement:
With binaryWS
summaryLastRow = .Range("A" & .Rows.Count).End(xlUp).Row
summaryLastColumn = .Cells(1, .Columns.Count).End(xlToLeft).Column
'Debug.Print summaryLastColumn
'Debug.Print summaryLastRow
'This is what breaks and gives me an error saying Method Range of object _worksheet failed
Set BinaryRng = .Range("B2", .Cells(summaryLastRow, summaryLastColumn))
End With
Related
I need to fill a range from 10,000 all the way until the end of the column. I have the lRow variable that is finding the last row, and then I have the IF loop that is filling the range just like I need to. The clear contents part is to remove any previous values and fill new ones. The Range("E2").Value = 1 is there to start the series.
The problem is I can't get it to fill the Range("F2:F" & lRow) in a step value of 10,000. The macro just fills out in a step value of 1. Any ideas?
I've tried recording macros but it never works quite right. It needs to be sort of dynamic as the list will grow over time.
This is what it should look like:
Sub MLOS_PriorityTable_StepValues()
Dim ws As Worksheet
Dim lRow As Long
Dim featOrder As Range
Dim Style As Range
Dim dataRange As Range
Dim currentArea As Range
Set ws = ActiveSheet
Set featOrder = ws.Range("A1:ZZ1").Find("FeatureOrder")
Set Style = ws.Range("A1:ZZ1").Find("Style")
Range("E2:E1000").ClearContents
Range("F2:F1000").ClearContents
Range("E2").Value = 1
Range("F2").Value = 10000
lRow = Cells(Rows.Count, Style.Column).End(xlUp).Row
On Error Resume Next
Set dataRange = Range("E2:E" & lRow).SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If Not dataRange Is Nothing Then
For Each currentArea In dataRange.Areas
With currentArea
With .Offset(-1, 0).Resize(.Rows.Count + 1)
.Cells(1).AutoFill Destination:=.Cells, Type:=xlFillSeries
End With
End With
Next currentArea
End If
On Error Resume Next
Set dataRange = Range("F2:F" & lRow).SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If Not dataRange Is Nothing Then
For Each currentArea In dataRange.Areas
With currentArea
With .Offset(-1, 0).Resize(.Rows.Count + 1)
.Cells(1).AutoFill Destination:=.Cells, Type:=xlFillSeries
End With
End With
Next currentArea
End If
End Sub
Is the result of F just E*10000? It doesn't matter too much, there's a few ways to solve.
Find your last row number (which you did as lRow)
Iterate for i = 2 to lRow which will loop from the top row with data to the last
Do something in here like Range("F"&i) = Range("E"&i)*10000 assuming that is the relationship or Range("F"&i) = Range("F"&i-1)+10000
next i
it will just iterate cell by cell, make the calculation, and move on.
You may need to make it more robust if you have a script that hops around multiple sheets or workbooks so the range or cell or whatever references you use are correct.
Don't know how fast this would be vs the fill Series function but it doesn't look at face value like it would be too slow.
let me know how you get on!
Rob S
Hello everyone i'm doing a macros code with vba, and i would like asking something, how can i write the next operation through vba macro.
Suppose you have a sheet with two columns one called "C" and the other "D" and each cell from this column has the next operation:
ws.Range("D1") = 0
ws.Range("D2") = ws.Range(C2)- ws.Range(C1)
ws.Range("D3") = ws.Range(C3)- ws.Range(C2)
...
ws.Range(Di+1) = ws.Range(Ci+1) -ws.Range(Ci)
How can i write in vba syntax an operation like:
ws.Range("D:D").FormulaR1C1 = "= R[i+1]C[""C""] - R[i]C[""C""]"
Thank you for your helping.
There are many options. See example of the code below (assuming I understood what you are after correctly)
Sub FillCells()
Dim RangeToFill As Range
Dim CurCell As Range
Dim wks As Worksheet
Set wks = ActiveSheet
Set RangeToFill = wks.Range("D2:D8") ''' define the range as required or even better - use named ranges in the so
'''' Option 1
''' youcan use R1C1 reference style for the whole range - very fast and nice solution
RangeToFill.FormulaR1C1 = "=RC[1]-R[-1]C[1]"
'''' Option 2
''' or you can use .Offset property of the range object. Note that .Address(0,0) has two zeros for the cell address not to be frozen,
''' i.e. not =$E$2 - $E$1 but =E2-E1
''' This also works but could be slower on big ranges and formula looks pretty ugly to my taste
For Each CurCell In RangeToFill.Cells
CurCell.Formula = "=" & CurCell.Offset(0, 1).Address(0, 0) & "-" & CurCell.Offset(-1, 1).Address(0, 0)
Next CurCell
End Sub
This question already has answers here:
Aggregate, Collate and Transpose rows into columns
(3 answers)
Closed 6 years ago.
I'm pretty new to stack overflow but I've been on here as a lurker before.
So I'm having trouble reorganizing this excel output. The original output is below. I've modified the output to preserve the confidentiality of the dataset and also in the interest of time as the dataset has over 10k cells, but the ideas should be clear.
Before
As you can see, there's a lot of duplicates and useless stuff and in general annoying bits. Basically I need to reorganize the data into column headers and repopulate the spreadsheet so that the data stays with the proper code number. The current column headers of supercatagory and subcategory are worthless. I've attached what I think would be the ideal here. After
I've tried using pivot tables and that kind of serves as a half measure but that would still require me to go through the output and copy and paste by hand for over 2 hours. I've also tried using transpose in excel and while that is good for the first part of the problem, making new column headers, but it doesn't solve the problem of repopulating the spreadsheet and keeping everything straight.
Thank you so much.
Without knowing more, the below code works for me in testing with the data provided in your images. The big question of course is where the column headers in the After data came from. It appeared to come from column B of the Before data. I assumed these would be duplicated for each unique value from column A. As such, in the below code, only the first set of values is used to set the headers of the newly created sheet.
Option Explicit
Sub TransposeWithUniques()
Dim SourceSheet As Worksheet
Dim TargetSheet As Worksheet
Dim Uniques As Collection
Dim Unique As Variant
Dim UniqueData() As Variant
Dim FormulaColumn As Range
Dim CriteriaColumn As Range
Dim DataRange As Range
Dim FoundRange As Range
Dim ValueIndex As Long
Dim LastRow As Long
Dim LastColumn As Long
Dim NewRow As Long
Dim ErrorFound As Boolean
Set SourceSheet = ActiveSheet '!!! This will need to be the currently active sheet housing your data
' If sheet is protected, exit
If SourceSheet.ProtectContents Then
MsgBox "Please unprotect the worksheet first.", vbExclamation, "Transpose with Uniques"
Exit Sub
End If
' Get last row/column
LastRow = SourceSheet.Cells(SourceSheet.Rows.Count, 1).End(xlUp).Row
LastColumn = SourceSheet.Cells(1, SourceSheet.Columns.Count).End(xlToLeft).Column
Set DataRange = SourceSheet.Range("A1", SourceSheet.Cells(LastRow, LastColumn))
NewRow = 1
' Get unique UniqueData from column A
UniqueData = SourceSheet.Range("A2:A" & LastRow).Value2
Set Uniques = New Collection
For ValueIndex = LBound(UniqueData, 1) To UBound(UniqueData, 1)
If InCollection(Uniques, CStr(UniqueData(ValueIndex, 1))) = False Then
Uniques.Add UniqueData(ValueIndex, 1), CStr(UniqueData(ValueIndex, 1))
End If
Next ValueIndex
' Set application properties for better code running experience
Application.DisplayAlerts = False
Application.EnableEvents = False
Application.ScreenUpdating = False
' Add helper columns
On Error GoTo TransposeWithUniques_Error
SourceSheet.Cells(1, LastColumn).Offset(0, 1).Resize(LastRow, 2).Insert
Set CriteriaColumn = SourceSheet.Cells(1, LastColumn).Offset(0, 1).Resize(LastRow, 1)
Set FormulaColumn = SourceSheet.Cells(1, LastColumn).Offset(0, 2).Resize(LastRow, 1)
FormulaColumn(1, 1).Value = "FORMULA"
CriteriaColumn(1, 1).Value = "CRITERIA"
FormulaColumn(2, 1).Resize(LastRow - 1, 1).Formula = "=ROW(A1)"
FormulaColumn(2, 1).Resize(LastRow - 1, 1).Value = FormulaColumn(2, 1).Resize(LastRow - 1, 1).Value
' Loop through all uniques, get data and move it
For Each Unique In Uniques
CriteriaColumn(2, 1).Resize(LastRow - 1, 1).Formula = "=1/(A2=" & Chr(34) & Unique & Chr(34) & ")"
CriteriaColumn(2, 1).Resize(LastRow - 1, 1).Value = CriteriaColumn(2, 1).Resize(LastRow - 1, 1).Value
DataRange.Resize(, DataRange.Columns.Count + 2).Sort Key1:=CriteriaColumn(1, 1), Order1:=xlAscending, Key2:=SourceSheet.Range("B1"), Order2:=xlAscending, Header:=xlYes
On Error Resume Next
Set FoundRange = CriteriaColumn.SpecialCells(xlCellTypeConstants, xlNumbers)
On Error GoTo 0
If Not FoundRange Is Nothing Then
If TargetSheet Is Nothing Then
Set TargetSheet = ActiveWorkbook.Worksheets.Add(After:=SourceSheet)
TargetSheet.Range("A1").Value = SourceSheet.Range("A1").Value
TargetSheet.Range("B1").Resize(1, FoundRange.Cells.Count).Value = Application.Transpose(Intersect(SourceSheet.Range("B:B"), FoundRange.EntireRow).Value)
End If
NewRow = NewRow + 1
TargetSheet.Cells(NewRow, 1).Value = Unique
TargetSheet.Cells(NewRow, 2).Resize(1, FoundRange.Cells.Count).Value = Application.Transpose(Intersect(SourceSheet.Range("C:C"), FoundRange.EntireRow).Value)
Set FoundRange = Nothing
End If
Next Unique
' Reset data to original state
DataRange.Resize(, DataRange.Columns.Count + 2).Sort Key1:=FormulaColumn(1, 1), Order1:=xlAscending, Header:=xlYes
FormulaColumn.Delete xlToLeft
CriteriaColumn.Delete xlToLeft
TransposeWithUniques_Exit:
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
If Not ErrorFound Then
MsgBox "Process completed successfully.", vbInformation, "Transpose with Uniques"
End If
Exit Sub
TransposeWithUniques_Error:
ErrorFound = True
MsgBox "Something went wrong.", vbExclamation, "Transpose with Uniques"
GoTo TransposeWithUniques_Exit
End Sub
Public Function InCollection(CheckCollection As Collection, CheckKey As String) As Boolean
'
' Returns True if the specified key is found in the specified collection.
'
' Syntax: InCollection(CheckCollection,CheckKey)
'
' Parameters: CheckCollection. Collection. Required. The collection to search in.
' CheckKey. String. Required. The string key to search in collection for.
'
On Error Resume Next
InCollection = CBool(Not IsEmpty(CheckCollection(CheckKey)))
On Error GoTo 0
End Function
To use the above code, in your file you want to run this on, press ALT+F11 to open the Visual Basic Editor (VBE). Press CTRL+R to show the Project Explorer (PE), generally this shows by default. Find your project in the PE and right-click it, select Insert, Module. Double click the newly inserted module (should be named Module1). Copy/paste the above code into this module. Click anywhere inside the top routine (for example, click on the text near the top "TransposeWithUniques" so your cursor is on that line, or just below it). Press F5 to run the routine.
CAUTION: Make sure you save a backup copy of your file prior to running this. It resets the data to its original state, but this is always good practice. Check the newly created sheet to ensure it's what you're looking for. If this isn't what you're looking for, please be as specific as possible in explaining the input versus output.
Regards,
Zack Barresse
Okay here is my code, I'm pretty sure the error is coming from something silly in the way stuff is named. I'm just starting to learn VBA so totally noob at this and can't catch what's wrong. Any input would be appreciated.
Sub test()
Dim wsInput As Worksheet: Set wsInput = ActiveSheet
Dim wsOutput As Worksheet: Set wsOutput = Workbooks.Open("C:\output.xls").Sheets(1)
Dim OutputRowCount As Integer: OutputRowCount = 1
For i = 1 To 10000
If wsInput.Range("a12" & i) <> "" Then
wsInput.Range("D12" & i, "E12" & i).Copy
wsOutput.Range("A4" & OutputRowCount).PasteSpecial Paste:=xlPasteValues
End If
Next
End Sub
There's multiple errors/problems in your code:
Your statement wsInput.Range("a12" & i) certainly does not what you want - it'll return cells A121, A122, ..., A1210000! Instead, try wsInput.Range("A" & (12+i)) or wsInput.Range("A12").Offset(i-1). Same problem with the other ranges.
in wsInput.Range("D12" & i, "E12" & i).Copy you actually copy two cells (D12:E12, after fixing #1)- not sure you want this. If you want this, you could alternatively use the Resize method: wsInput.Range(D12).Offset(i-1).Resize(,2)
You do not increase OutputRowCount, therefore every cell will be pasted to A4 (after fix from #1, else to A41)! Add a line OutputRowCount=OutputRowCount+1.
Instead of copying and pasting, you could simply assign the .Value: wsOutputRange("A"& 4 + OutputRowCount).Resize(,2).Value = Input.Range(D12).Offset(i-1).Resize(,2).Value`
Last but not least, instead of looping over each cell, consider using .SpecialCells and Intersect, i.e. you could your whole For loop with
Application.Union( _
wsInput.Range("A4").Resize(10000).SpecialCells(xlCellTypeFormulas),
wsInput.Range("A4").Resize(10000).SpecialCells(xlCellTypeValues)) _
.Offset(,3).Resize(,2).Copy
wsOutput.Range("A4").PasteSpecial(xlPasteValues)
Hope that helps!
The maximum amount of rows you can have in Excel 32-bit is 1048576, but the last row you are trying to access here is 1210000. The below code works (all I have done is changed 10000 to 9999), but as Peter says, this probably isn't what you really want to do, unless you have some bizarre business reason or something:
Sub test()
Dim wsInput As Worksheet: Set wsInput = ActiveSheet
Dim wsOutput As Worksheet: Set wsOutput = Workbooks.Open("C:\output.xls").Sheets(1)
Dim OutputRowCount As Integer: OutputRowCount = 1
For i = 1 To 9999
If wsInput.Range("a12" & i) <> "" Then
wsInput.Range("D12" & i, "E12" & i).Copy
wsOutput.Range("A4" & OutputRowCount).PasteSpecial Paste:=xlPasteValues
End If
Next
End Sub
Error: Method 'Paste' of object '_Worksheet' failed - 1004
Solution: Need to remeber the problems in Excel before copy the shapes from one sheet to another sheet. 1. Activate the Sheet(from where you are copying). 2. Select the Shapes from Sheet. 3. Copy the shapes from the Sheet. 4. Paste to shape to target sheet
Example: Previously my code is like below:
Sheet1.Shapes(0).Copy
Targetsheet.Paste
I have modified the like below:
Sheet1.Activite
Sheet1.Shapes(0).Select
Sheet1.Shapes(0).Copy
Targetsheet.Paste
Now it is working fine.
I'm trying to loop through several worksheets that contain some source data that has to be copied to one main sheet, called "PriorityList" here.
First of all, the sub is not working and I think the error is somewhere in the "find"-method. Second, the sub takes quite long to run, and I think this is maybe because the "find"-method searches through the whole sheet instead of only the relevant range?
Thank you very much for your answers!
Patrick
Sub PriorityCheck()
'Sub module to actualise the PriorityList
Dim CurrWS As Long, StartWS As Long, EndWS As Long, ScheduleWS As Long
StartWS = Sheets("H_HS").Index
EndWS = Sheets("E_2").Index
Dim SourceCell As Range, Destcell As Range
For CurrWS = StartWS To EndWS
For Each SourceCell In Worksheets(CurrWS).Range("G4:G73")
On Error Resume Next
'Use of the find method
Set Destcell = Worksheets(CurrWS).Cells.Find(What:=SourceCell.Value, After:=Worksheets("PriorityList").Range("A1"), LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False)
'Copying relevant data from source sheet to main sheet
If Destcell <> Nothing Then
Destcell.Offset(0, 2).Value = SourceCell.Offset(0, 5).Value + Destcell.Offset(0, 2).Value
If SourceCell.Offset(0, 3).Value = "x" Then Destcell.Offset(0, 3).Value = "x"
End If
End If
On Error GoTo 0
Next SourceCell
Next CurrWS
End Sub
here short sample how to use 'Find' method to find the first occurrence of the source.Value in the priorityList.
Source cell is one of the cells from the range "G4:G73" and priorityList is used range on "PriorityList" sheet. Hope this helps.
Public Sub PriorityCheck()
Dim source As Range
Dim priorityList As Range
Dim result As Range
Set priorityList = Worksheets("PriorityList").UsedRange
Dim i As Long
For i = Worksheets("H_HS").Index To Worksheets("E_2").Index
For Each source In Worksheets(i).Range("G4:G73")
Set result = priorityList.Find(What:=source.Value)
If (Not result Is Nothing) Then
' do stuff with result here ...
Debug.Print result.Worksheet.Name & ", " & result.Address
End If
Next source
Next i
End Sub
Here is an approach using arrays. You save each range into an array, then iterate through array to satisfy your if-else condition. BTW IF you want to find the exact line with code error, then you must comment On Error Resume Next line.. :) Further, you can simply store the values into a new array, dump everything else into the main sheet later after iterating through all the sheets instead of going back and forth to sheets, code, sheets..code..
Dim sourceArray as Variant, priorityArray as Variant
'-- specify the correct priority List range here
'-- if multi-column then use following method
priorityArray = Worksheets(CurrWS).Range("A1:B10").Value
'-- if single column use this method
' priorityArray = WorkSheetFunction.Transpose(Worksheets(CurrWS).Range("A1:A10").Value)
For CurrWS = StartWS To EndWS
On Error Resume Next
sourceArray = Worksheets(CurrWS).Range("G4:J73").Value
For i = Lbound(sourceArray,1) to UBound(sourceArray,1)
For j = Lbound(priorityArray,1) to UBound(priorityArray,1)
If Not IsEmpty(vArr(i,1)) Then '-- use first column
'-- do your validations here..
'-- offset(0,3) refers to J column from G column, that means
'---- sourceArray(i,3)...
'-- you can either choose to update priority List sheet here or
'---- you may copy data into a new array which is same size as priorityArray
'------ as you deem..
End If
Next j
Next i
Next CurrWS
PS: Not front of a MS Excel installed machine to try this out. So treat above as a code un-tested. For the same reason I couldn't run your find method. But it seems odd. Don't forget when using match or find it's important to do proper error handling. Try checking out [find based solutions provided here.
VBA in find function runtime error 91
Excel 2007 VBA find function. Trying to find data between two sheets and put it in a third sheet
I have edited the initial code to include the main logic using two array. Since you need to refer to values in J column of source sheets, you will need to adjust source array into a two-dimensional array. So you can do the validations using first column and then retrieve data as you desire.
For everyone maybe interested, this is the code version that I finally used (pretty similar to the version suggested by Daniel Dusek):
Sub PriorityCheck()
Dim Source As Range
Dim PriorityList As Range
Dim Dest As Range
Set PriorityList = Worksheets("PriorityList").UsedRange
Dim i As Long
For i = Worksheets("H_HS").Index To Worksheets("S_14").Index
For Each Source In Worksheets(i).Range("G4:G73")
If Source <> "" Then
Set Dest = PriorityList.Find(What:=Source.Value)
If Not Dest Is Nothing Then
If Dest <> "" Then
Dest.Offset(0, 2).ClearContents
Dest.Offset(0, 2).Value = Source.Offset(0, 5).Value + Dest.Offset(0, 2).Value
End If
If Source.Offset(0, 3).Value = "x" Then Dest.Offset(0, 3).Value = "x"
Debug.Print Dest.Worksheet.Name & ", " & Dest.Address
End If
End If
Next Source
Next i
MsgBox "Update Priority List completed!"
End Sub