Having trouble copying data from one sheet to another - vba

Developing a large macro and now it seems the second simplest part is giving me trouble.
I am able to copy the selection in one workbook, but it does not allow me to paste over to the other workbook. I am getting:
"Object doesn't support this property or method" error.
This is looping through large sets of data so it will need to be able to rinse and repeat, which shouldn't be a problem because I can just clear the clipboard as a rinse method.
Any ideas?
Code below. There is code above it, but I don't think you should need any of it to get an idea of what's going on. Error comes in on the ** line.
Do
DoEvents
'Tests condition for counter party
If InStr(1, Range(buyerCol & row_counter), clientName) > 0 Or InStr(1, Range(sellerCol & row_counter), clientName) > 0 Then
EEB.Sheets("Trades Master List").Rows(row_counter).Copy
'Activates newly created excel sheet
Workbooks(newWorkbookName).Activate
'Tests newly created sheet for already existing entries and increments newSheetRow by 1 until it finds the next empty space
Do While IsEmpty(Range("A" & newSheetRow)) = False
newSheetRow = newSheetRow + 1
Loop
**ActiveWorkbook.Range(newSheetRow & newSheetRow).PasteSpecial
EEB.masterList.Activate
row_counter = row_counter + 1
Else
row_counter = row_counter + 1
End If
Loop Until Range("A" & row_counter).Value > endDateFromSheet Or IsEmpty(Range("A" & row_counter)) = True

Related

Trying to make a table of variable columns/rows in VBA

Here is all the applicable code that I'm having a hard time with (though part of a large program). I'm making an executive dashboard, and this data rolls up into a chart on a separate sheet looking at month-over-month utility usage. It is supposed to copy over a variable number of utilities from a variable number of months.
Integer m is the months (I'm using 3/March as my example), so from i=1 to 3 it's supposed to copy/paste the rows from the ns that is opened into ws. It keeps giving an error 1004, so I think I'm calling my ranges incorrectly, but I'm not sure how/why. In my code, the error is down in that For Loop, none of the lines seem to work
I need some sort of variable so that I can later roll it up into my chart. Here are some photos of what's supposed to come over (only the headers are coming over, which wasn't using the .Cell(). Also, if anyone knows the correct way to code my second to last line, please share (though not my primary challenge).
fNameAndPath = Application.GetOpenFilename(FileFilter:="Excel Files (*.XLSX), *.XLSX", Title:="Select Trend Income Statement for " & os.Range("B2") & " " & os.Range("B3"))
If fNameAndPath = False Then Exit Sub
'We are opening and pulling data from the selected workbook, so lets turn off screen updating and get to work
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set nb = Workbooks.Open(fNameAndPath)
Set ns = nb.Sheets(1)
m = Month(ws.Range("B1"))
'Build out the Utility Section
Let FindIt = "50100-000"
Set FoundCell = ns.Range("A:A").Find(What:=FindIt)
fRow = FoundCell.Row + 1 'This will be the first Util GL
Let FindIt2 = "50199-999"
Set FoundCell2 = ns.Range("A:A").Find(What:=FindIt2)
fRow2 = FoundCell2.Row - 1 ' This will be the last Util GL
ns.Range("B" & fRow - 1 & ":B" & fRow2 + 1).Copy 'Copy the header range
ws.Range("G16").PasteSpecial Paste:=xlPasteValues
For i = 1 To m
Set cRange = ns.Range(ns.Cells(fRow, 2 + i), ns.Cells(fRow2, 2 + i))
ns.Range(cRange).Copy
Set pRange = ws.Range(ws.Cells(17, 7 + i))
ws.Range(pRange).PasteSpecial Paste:=xlPasteValues
ws.Range(Cells(15, 7 + i)).Formula = "=TEXT(i*30, mmmmm)"
Next i
I had trouble getting several parts of your code to work as it seems to be a snippet of a larger program.
I think what might be causing your issue is that you are using one Cells() in some of your Range() calls. The Range() call returns a 1004 error when I tried providing it with only one Cells() object.
For example you use
'This throws 1004 error
ws.Range(ws.Cells(17 , 7 + i ))
Try to use something like this
ws.Cells(17 , 7 + i)
Also, you can use something like this
ws.Range("G17").Offset(0,i)
See if any of these works for your use case and produces the desired result.

Excel macro help - If statement with a variable range

I am creating a macro to help organize a data dump (sheet 1) into an invoice (sheet 2). I have coded most of the macro, but am stuck on the following.
I want the macro to read column Y on sheet 1, which is a variable range (can be 2 rows to 50) and check if it says "CB". If this is true, then E11 on sheet 2 is Yes, otherwise No, and so on until it reaches the end of column Y on sheet 1.
I have the following:
Sheets("Data_Dump").Select
intCounter = 1
While Range("Y" & (intCounter + 1)) <> ""
intCounter = intCounter + 1
Wend
intCardSize = intCounter
MsgBox (intCardSize)
Sheets("Data_Dump").Select
If Range("Y" & intCardSize) = "CB" Then
Sheets("Reconciliation").Select
Range("E11:E" & intCardSize).Select
Range("E11") = "Yes"
End If
The while range seems to work and it displays the number of cells with text in column Y, but I can't seem to wrap my head around how to get it to move from Y1 to Y2 and so on and then paste the response into E11 then E12 and so on.
The problem that you are having is that your code doesn't loop to try to compare. The While loop that you have only looks to see if there is something in the next cell. In fact, it actually skips the first row, but maybe that was intentional.
Dim dataSheet As WorkSheet
Dim recSheet As Worksheet
Dim lngCounter As Long 'Use long because an integer may not be big enough for large dataset.
Dim intCardSize As Long
Set dataSheet = ThisWorkbook.Sheets("Data_Dump")
Set recSheet = ThisWorkbook.Sheets("Reconciliation")
'You want to set the sheets to a variable instead of referring to the whole path each time
'Also, Note the usage of "ThisWorkbook" which guarantees the worksheet
'is coming from the one with code in it.
lngCounter = 2 'If you want to start looking at row 2, start at row 2 with
'the variable instead of starting the variable and checking var+1
While dataSheet.Range("Y" & (lngCounter)) <> ""
'While there is a value in the column
'intCardSize = intCounter 'Not sure what this is supposed to do
'MsgBox (intCardSize) 'This looks like debugging. Commenting out.
If dataSheet.Range("Y" & lngCounter) = "CB" Then
'Check each row as you go through the loop.
'Sheets("Reconciliation").Select
'Avoid selecting sheet/range. Unneccessary work for computer.
recSheet.Range("E" & (9 + lngCounter)) = "Yes"
'Set reconciliation sheet value to "Yes" if data sheet has "CB"
'The reconciliation sheet starts on row 11, whereas the datasheet
'starts at row 2 ,a difference of 9
Else
recSheet.Range("E" & (9 + lngCounter)) = "No"
'Otherwise set to no.
End If
lngCounter = lngCounter + 1
Wend
intCardSize = lngCounter - 1 'It's been increased to one past the last item.
MsgBox intCardSize 'Display the last row checked.
I hope I understood your code goal as follows
With Sheets("Data_Dump")
With Sheets("Reconciliation").Range("E11").Resize(.Cells(.Rows.Count,1).Row)
.Formula="=IF('Data_Dump'!Y1="CB", "Yes","")"
.Value= .Value
End With
End With

VBA Infinite loop - When no value is enetered by the user

I'm a newbie to VBA and I'm writing a VBA code that will accept user inputs for the serial numbers for the Start and End value and will check if the serial numbers in another sheet fall between the range specified. If it does, then my code will pick the complete record and paste it into another sheet.
Now, the challenging part is that the serial number value isn't consistent and it could be alpha-numeric string with no fixed length. So, I've used StrComp function to check if the value lies in the range specified by the user. The problem is if the user types in a value for start value and end value that doesn't exist in the sheet of serial numbers then it goes on an infinite loop.
For instance, if there is a serial number say 1120 and the user enters 1110(which doesn't exist) for start value and 1200 for end value, the code goes on a infinite loop. Technically, the code should pick the serial number 1120 and return since it does lie in the range 1110 and 1200 eventhough the value 1110 doesn't exist in the sheet.
Here is my code:
'Assigining values enterted by user to variables
start = Me.txtStart.Value
finish = Me.txtEnd.Value
'Checking Upper bound Vs Lower bound
If (Len(start) <> 0 And (Len(finish) <> 0)) Then
If (StrComp(start, finish) > 0) Then
MsgBox ("Lower Bound cannot be higher than the Upper Bound")
Exit Sub
Else
If Len(tempWorkPriority) = 0 Then
MsgBox ("Enter a value for Work Priority")
Exit Sub
Else
If Len(tempDescription) = 0 Then
MsgBox ("Enter a value for Description")
Exit Sub
Else
Goto Here
End If
End If
End If
Else
result = MsgBox("Please enter values for Upper and Lower bounds")
Exit Sub
End If
End Sub
Here:
Sheets("Imported e-Facilities Data").Activate
'Number of rows in Raw Data sheet
RowCount = Cells(Cells.Rows.Count, "A").End(xlUp).Row
'Loop to iterate and pick data that falls within the specified range
For i = 2 To RowCount
tempSerial = Range("A" & i).Value
tempAsset = Range("V" & i).Value
tempAssignedResource = Range("R" & i).Value
tempManufacturer = Range("F" & i).Value
'Condition to check if a Serial Number falls within the range
If (StrComp(start, tempSerial) <= 0 And StrComp(tempSerial, finish) <= 0) Then
'Selecting Export Sheet
Sheets("Data Ready for Import").Select
'Counting Rows in the Export sheet
RowCountExport = Cells(Cells.Rows.Count, "A").End(xlUp).Row
Range("A" & RowCountExport + 1).Value = tempSerial
End If
Next
End Sub
Please Help!!!
You're using unqualified calls to Range so you are relying on the active sheet being set correctly. When you find a serial number which falls within the range, you call Select on a different sheet which has the effect of changing the active sheet. The next time round your loop tempSerial, tempAsset etc will be read from the "Data Ready For Import" sheet which is now active rather than the "Imported e-Facilities Data" sheet which was being used before.
You should qualify your Range references instead of relying on the active sheet, Select or Activate:
Set wsInput = Worksheets("Imported e-Facilities Data")
tempSerial = wsInput.Range("A" & i).Value
or use With ... End With for repeated references to the same object:
Set wsInput = Worksheets("Imported e-Facilities Data")
With wsInput
tempSerial = .Range("A" & i).Value
tempAsset = .Range("V" & i).Value
tempAssignedResource = .Range("R" & i).Value
tempManufacturer = .Range("F" & i).Value
End With

VBA Excel 2013 Write in ActiveCells in columns "C" and "D" then copy and paste until column "A" changes

I am new to VBA and experiencing a first major problem. What I'm trying to do should be fairly easy. However, I can't seem to get it to work.
Right now, I am in the process of building a UserForm that simplifies entries in a dashboard of some sort.
I have already written code that writes values (of checked ListBox items and textboses) from the UserForm into cells, e.g. (Disclaimer: Might be the worst piece of code you've ever seen):
Public Sub Schreiben()
Range("C" & (ActiveCell.row)).Value = frmEingabe.txtStatus.Value
Dim listItems As String, i As Long
With frmEingabe.lstComment
For i = 0 To .ListCount - 1
If .Selected(i) Then listItems = listItems & .List(i) & ", "
Next i
End With
If Len(listItems) > 0 And IsNull(frmEingabe.txtFrei) Then
Range("D" & (ActiveCell.row)).Value = Left(listItems, Len(listItems) - 2)
Else
If Len(listItems) = 0 And Not IsNull(frmEingabe.txtFrei) Then
Range("D" & (ActiveCell.row)).Value = frmEingabe.txtFrei.Value
Else
If Len(listItems) > 0 And Not IsNull(frmEingabe.txtFrei) Then
Range("D" & (ActiveCell.row)).Value = Left(listItems, Len(listItems) - 2) & ", " & frmEingabe.txtFrei.Value
End If
End If
End If
End Sub
The issue now is that it does this for only one row, namely the active row. However, I want an extra functionality that writes those values into cells in columns "C" and "D", copies these values and then pastes them in columns "C" and "D" until the value in column "A" changes.
Basically, I want to fill all rows of the same "type" (i.e. same value in "A", sorted by "A") with the exact same info but don't want to write individually, as this increases the calculation time of the dashboard immensely. For this reason, a For-Loop did not work for me, as it always took to long to paste into each cell individually (I didn't build the dashboard - every time you enter something in a cell it needs a few seconds to calculate what has happened).
I have already written a code to jump to the row where column "A" is different than before:
Private Sub btnJump_Click()
cmpgn = Range("A" & (ActiveCell.row)).Value
Do
Selection.Offset(1, 0).Select
Loop Until ActiveCell.EntireRow.Hidden = False And cmpgn <> Range("A" & (ActiveCell.row)).Value
End Sub
What would be the smartest way to combine both and have the code either:
Filldown columns "C" and "D" from the row where the code first writes values from the UserForm into Worksheet until the value in column "A" changes
Select ActiveCells.Row "C" & "D", copy their values, select cells in both columns until the value in column "A" changes and paste the values.
I hope my question is clear. If not, please let me know and I will try to clarify.
Thanks a bunch in advance!
You can always disable calculation (temporarily) using Application.Calculcation = xlCalculationManual and then re-enable it using Application.Calculation = xlCaclulationAutomatic. That would allow you to use the "FillDown" option without sacrificing performance.

400 Error Excel Macro

I'm trying to run a macro that will delete rows that don't contain a particular value in column B. Here's my code:
Sub deleteRows()
Dim count As Integer
count = Application.WorksheetFunction.CountA(Range("AF:AF"))
Dim i As Integer
i = 21
Do While i <= count
If (Application.WorksheetFunction.IsNumber(Application.WorksheetFunction.Search("OSR Platform", Range("B" & i))) = False) Then
If (Application.WorksheetFunction.IsNumber(Application.WorksheetFunction.Search("IAM", Range("B" & i))) = False) Then
Rows(i).EntireRow.Delete
i = i - 1
count = count - 1
End If
End If
i = i + 1
Loop
End Sub
Now what it SHOULD be doing is the following:
1.) Find the number of rows to go through and set that as count (this works)
2.) Start at row 21 and look for "OSR Platform" and "IAM" in column B [this kind of works (see below)]
3.) If it finds neither, delete the entire row and adjust the count and row number as necessary (this works)
For some reason, whenever the code gets to the first If statement, an error window with a red X pops up that just says "400." As far as I can tell, I have written everything syntactically soundly, but clearly there's something wrong.
You may want to start by looping the other way. When you delete a line, all the previous lines are shifted. You account for this, but a reverse loop is simpler (for me anyways) to understand than keeping track of when I've offset the current position within the loop:
For i = count To 21 Step -1
Also, you're relying too much on Application.WorksheetFunction:
(Application.WorksheetFunction.IsNumber(Application.WorksheetFunction.Search("OSR Platform", Range("B" & i))) = False)
to
InStr(Range("B" & i).value, "OSR Platform") > 0
Application.WorksheetFunction takes much more processing power, and depending on what you are trying to accomplish, this can take a significantly longer amount of time. Also for this suggested change, the code size is reduced and becomes easier to read without it.
Your count can also be obtained without A.WF:
Excel 2000/03: count = Range("AF65536").End(xlUp).Row
Excel 2007/10: count = Range("AF1048576").End(xlUp).Row
Version independent: count = Range("AF" & Rows.Count).End(xlUp).Row
One more thing is that you can do (and should do in this case) is combine your If statements into one.
Making these changes, you end up with:
Sub deleteRows()
Dim count As Integer
count = Range("AF" & Rows.Count).End(xlUp).Row
Dim i As Integer
For i = count To 21 Step -1
If Len(Range("B" & i).value) > 0 Then
If InStr(Range("B" & i).value, "OSR Platform") > 0 Or InStr(Range("B" & i).value, "IAM") > 0 Then
Range("B" & i).Interior.Color = RGB(255, 0, 0)
End If
End If
Next i
End Sub
If this does not help, then can you step through the code line by line. Add a breakpoint, and step through with F8. Highlight the variables in your code, right-click, choose "add Watch...", click "OK", (Here's an excellent resource to help you with your debugging in general) and note the following:
Which line hits the error?
What is the value of i and count when that happens? (add a watch on these variables to help)
This worked for me. It uses AutoFilter, does not require looping or worksheet functions.
Sub DeleteRows()
Dim currentSheet As Excel.Worksheet
Dim rngfilter As Excel.Range
Dim lastrow As Long, lastcolumn As Long
Set currentSheet = ActiveSheet
' get range
lastrow = currentSheet.Cells(Excel.Rows.Count, "AF").End(xlUp).Row
lastcolumn = currentSheet.Cells(1, Excel.Columns.Count).End(xlToLeft).Column
Set rngfilter = currentSheet.Range("A1", currentSheet.Cells(lastrow, lastcolumn))
' filter by column B criteria
rngfilter.AutoFilter Field:=2, Criteria1:="<>*OSR Platform*", Operator:= _
xlAnd, Criteria2:="<>*IAM*"
' delete any visible row greater than row 21 which does not meet above criteria
rngfilter.Offset(21).SpecialCells(xlCellTypeVisible).EntireRow.Delete
' remove autofilter arrows
currentSheet.AutoFilterMode = False
End Sub
This code applies AutoFilter to column B to see which rows contain neither "OSR Platform" nor "IAM" in column B. Then it simply deletes the remaining rows greater than 21. Test it on a copy of your workbook first.
With a huge nod to this OzGrid thread, because I can never remember the proper syntax for selecting visible cells after filtering.