Script in where it copies a sheet's data, and pastes it, but over pastes - excel

Here is my script.
Sub Update_OOR()
Dim wsTNO As Worksheet
Dim wsTND As Worksheet
Dim wsTNA As Worksheet
Dim lastrow As Long, fstcell As Long
Set wsTNO = Sheets("Tel-Nexx OOR")
Set wsTND = Sheets("Tel-Nexx Data")
Set wsTNA = Sheets("Tel-Nexx Archive")
With Application
.ScreenUpdating = False
.DisplayAlerts = False
.EnableEvents = False
End With
With Intersect(wsTNO.UsedRange, wsTNO.Columns("S"))
.AutoFilter 1, "<>Same"
With Intersect(.Offset(2).EntireRow, .Parent.Range("B:P"))
.Copy wsTNA.Cells(Rows.Count, "B").End(xlUp).Offset(1)
.EntireRow.Delete
End With
.AutoFilter
End With
'Blow away rows that are useless
lastrow = wsTND.Range("A2").End(xlDown).Row
wsTND.Range("O1:P1").Copy wsTND.Range("O2:P" & lastrow)
wsTND.UsedRange.Copy Sheets.Add.Range("A1")
With Intersect(ActiveSheet.UsedRange, ActiveSheet.Columns("P"))
ActiveSheet.Range("O:P").Calculate
.AutoFilter 1, "<>Different"
.SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
With ActiveSheet
lastrow = wsTND.Range("A2").End(xlDown).Row
Intersect(.UsedRange, .Range("A2:M" & lastrow)).Copy wsTNO.Cells(Rows.Count, "B").End(xlUp).Offset(1)
.Delete
End With
With wsTNO
lastrow = wsTNO.Cells(Rows.Count, "B").End(xlUp).Row
wsTNO.Range("T1:AD1").Copy
wsTNO.Range("B3:N" & lastrow).PasteSpecial xlPasteFormats
lastrow = wsTNO.Cells(Rows.Count, "R").End(xlUp).Row
fstcell = wsTNO.Cells(Rows.Count, "N").End(xlUp).Row
wsTNO.Range("AE1:AI1").Copy wsTNO.Range("O" & fstcell & ":S" & lastrow).Offset(1, 0)
End With
With Application
.ScreenUpdating = True
.DisplayAlerts = True
.EnableEvents = True
End With
End Sub
It technically works perfectly till here:
With wsTNO
lastrow = wsTNO.Cells(Rows.Count, "B").End(xlUp).Row
wsTNO.Range("T1:AD1").Copy
wsTNO.Range("B3:N" & lastrow).PasteSpecial xlPasteFormats
lastrow = wsTNO.Cells(Rows.Count, "R").End(xlUp).Row
fstcell = wsTNO.Cells(Rows.Count, "N").End(xlUp).Row
wsTNO.Range("AE1:AI1").Copy wsTNO.Range("O" & fstcell & ":S" & lastrow).Offset(1, 0)
End With
Now technically everything in this part works correctly, but the last line in the code, it pasts everything correctly, then it goes one step beyond. I'd like to know why. If I get rid of the offset it overwrites what is in the cell above in O through S. I need to know the first and last cell, because the data needs to be only written to a specific cell range.
If there is an easier way of doing this it be appreciated if someone could tell me, if not then can someone tell me how to fix this?
Thanks.
Attached is the workbook.
http://dl.dropbox.com/u/3327208/Excel/First%26LastRows.xlsm

In your 2nd piece of code add + 1 to
lastrow = wsTNO.Cells(Rows.Count, "R").End(xlUp).Row
So you have
lastrow = wsTNO.Cells(Rows.Count, "R").End(xlUp).Row + 1
The former gives you row 2, which is your header row. What you want is row 3, the row right after your headers.
Update: To Show How To Test in Future
Although the .Select method is typically frowned upon. It can be great for testing / debugging. I ran
wsTNO.Range("O" & fstcell & ":S" & lastrow).Select
in the immediate window after I set lastrow and fstcell to find the range that was set. Therefore I knew you didn't want to copy your headers. From there you can figure out what is driving that range to be set and adjust accordingly.

Related

VBA If range [J:K] not empty, then copy [H:I] to the end of [J:K], else offset

I have two ranges, [H23:I32] and [J23:K50].
I need to copy values from [H23:I32] to [J23:K50] if [J23:K50] is empty, and if [J23:K50] is not empty I need to find the last row and add [H23:I32] below.
The "copy if empty" works, but the "add to the end of the list" doesn't unfortunately.
It does something, but clearly not the thing I need.
Sub Total_Loop()
Application.ScreenUpdating = False
Dim c As Range
For Each c In Range("J23:K50" & Cells(Rows.Count, "J").End(xlUp).Row)
If c.Value <> "" Then
Range("J23:K50" & Cells(Rows.Count, "J").End(xlUp).Row + 1) = Range("H23:I32")
Else: c.Value = c.Offset(, -2).Value
End If
Next
Application.ScreenUpdating = True
End Sub
Any suggestions how to fix this?
EDIT: After a lot of struggle I found a suitable solution!
Sub MoveData()
Dim lrow As Long
Dim ws As Worksheet
Set ws = Sheets("Loot")
If WorksheetFunction.CountA(ws.Range("J23:K50")) = 0 Then
ws.Range("H23:I32").Copy
ws.Range("J23").PasteSpecial xlPasteValues
Else
lrow = ws.Range("J23:K50").Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
ws.Range("H23:I32").Copy
ws.Range("J" & lrow + 1).PasteSpecial xlPasteValues
End If
End Sub

Copy data range in one sheet to another as values until a specific value arise

In below code I need to copy a range from "Output for qualifying" and insert as values in "Output".
It works, but I need the code to stop copy the range when column A start to contain the value zero (0).
Is there a smart way to do that? Hope you guys can help me.
Sub Copy_to_output()
Worksheets("Output for qualifying").Range("A2:A400").Copy
Worksheets("Output").Range("A9").PasteSpecial Paste:=xlPasteValues
Worksheets("Output for qualifying").Range("B2:H400").Copy
Worksheets("Output").Range("E9").PasteSpecial Paste:=xlPasteValues
Worksheets("Output for qualifying").Range("J2:K400").Copy
Worksheets("Output").Range("L9").PasteSpecial Paste:=xlPasteValues
Worksheets("Output for qualifying").Range("Q2:Y400").Copy
Worksheets("Output").Range("N9").PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False
End Sub
The only thing I can think of in your situation is to use the Find method.
So, in your code, find the first 0 value, then use that as your row reference for the copy. This is by no means a clean way for the operation, but will do the task.
Sub Copy_to_output()
Dim lZeroRow As Long
lZeroRow = Worksheets("Output for qualifying").Range("A:A").Find(What:="0", LookIn:=xlValues, LookAt:=xlWhole).Row
Worksheets("Output for qualifying").Range("A2:A" & lZeroRow).Copy
Worksheets("Output").Range("A9").PasteSpecial Paste:=xlPasteValues
Worksheets("Output for qualifying").Range("B2:H" & lZeroRow).Copy
Worksheets("Output").Range("E9").PasteSpecial Paste:=xlPasteValues
Worksheets("Output for qualifying").Range("J2:K" & lZeroRow).Copy
Worksheets("Output").Range("L9").PasteSpecial Paste:=xlPasteValues
Worksheets("Output for qualifying").Range("Q2:Y" & lZeroRow).Copy
Worksheets("Output").Range("N9").PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False
End Sub
Try the next code, please:
Sub Copy_to_output()
Dim shOFQ As Worksheet, shO As Worksheet, lastRow As Long
Set shOFQ = Worksheets("Output for qualifying")
Set shO = Worksheets("Output")
lastRow = shOFQ.Range("A:A").Find(What:="0", LookIn:=xlValues, LookAt:=xlWhole).row
shO.Range("A9").Resize(lastRow, 1).Value = shOFQ.Range("A2:A" & lastRow).Value
shO.Range("E9").Resize(lastRow, shOFQ.Range("B2:H" & lastRow).Columns.Count).Value = shOFQ.Range("B2:H" & lastRow).Value
shO.Range("L9").Resize(lastRow, shOFQ.Range("J2:K" & lastRow).Columns.Count).Value = shOFQ.Range("J2:K" & lastRow).Value
shO.Range("N9").Resize(lastRow, shOFQ.Range("Q2:Y" & lastRow).Columns.Count).Value = shOFQ.Range("Q2:Y" & lastRow).Value
End Sub
No need to use Copy Paste...

Moving Data from One Sheet to Another Based on Cell Value

I have a Spreadsheet "upload" I run a macro to compile the data on the sheet. I have a column "D" which attributes the data to client. I want to look for a specific client and automatically move those rows to another worksheet. I have tried this code, but I am making an error "Upload.Range("D1", Upload.Range("D" & Upload.Rows.Count)"
I anticipate future clients information to need be separated from the initial spreadsheet as well.
Any Help would be much appreciated
Sub TransferData()
Dim ar As Variant
Dim i As Integer
Dim lr As Long
ar = Array("3032")
Application.ScreenUpdating = False
Application.DisplayAlerts = False
For i = 0 To UBound(ar)
Upload.Range("D1", Upload.Range("D" & Upload.Rows.Count).End(xlUp)).AutoFilter 1, ar(i), 4, , 0
lr = Upload.Range("D" & Rows.Count).End(xlUp).Row
If lr > 1 Then
Upload.Range("A2", Upload.Range("G" & Upload.Rows.Count).End(xlUp)).Copy Sheets(ar(i)).Range("A" & Rows.Count).End(3)(2)
Upload.Range("A2", Upload.Range("G" & Upload.Rows.Count).End(xlUp)).Delete
Sheets(ar(i)).Columns.AutoFit
End If
Next i
[G1].AutoFilter
Application.DisplayAlerts = True
Application.CutCopyMode = False
Application.ScreenUpdating = True
MsgBox "Data transfer completed!", vbExclamation, "Status"
End Sub
There is a substantial difference between the worksheet Name property and the worksheet Codename property.
While it is possible to change the worksheet's Codename, it isn't a common practice and if you are unsure then it is most likely that you are referring to the worksheet Name property.
Your narrative says nothing about wanting the 'bottom 10 results' but your code uses 4 for the xlBottom10Items operator (see xlAutoFilterOperator enumeration ).
I have no idea what the 3 in Sheets(ar(i)).Range("A" & Rows.Count).End(3)(2) is intended to represent. I would suppose that you meant xlUp which has a numerical value of -4162. (see xlDirection enumeration).
Sub TransferData()
Dim ar As Variant
Dim i As Long, lr As Long
ar = Array("3032")
' ... app environment settings removed for brevity
'reference the filter worksheet properly
With Worksheets("Upload")
lr = .Range("D" & Rows.Count).End(xlUp).Row
If .AutoFilterMode Then .AutoFilterMode = False
For i = LBound(ar) To UBound(ar)
'there was no mention of 'bottom 10 items in your narrative but your code shows that option
With .Range("D1:D" & lr)
'.AutoFilter field:=1, Criteria1:=ar(i), _
Operator:=xlBottom10Items, VisibleDropDown:=False
.AutoFilter field:=1, Criteria1:=(ar(i)), VisibleDropDown:=False
With .Resize(.Rows.Count - 1, .Columns.Count).Offset(1, 0)
If CBool(Application.Subtotal(103, .Cells)) Then
.Offset(0, -3).Resize(, 7).Copy _
Destination:=Worksheets(ar(i)).Range("A" & Rows.Count).End(xlUp)(2)
Worksheets(ar(i)).Columns.AutoFit
.Delete shift:=xlUp
End If
End With
End With
Next i
If .AutoFilterMode Then .AutoFilterMode = False
End With
' ... app environment settings removed for brevity
MsgBox "Data transfer completed!", vbExclamation, "Status"
End Sub
That should get you started. It seems you still have a few decisions o make based on my notes.
Application.CutCopyMode = False
See Should I turn .CutCopyMode back on before exiting my sub procedure?.

VBA - How do I speed up the time to copy and paste [duplicate]

This question already has answers here:
Copy from one workbook and paste into another
(2 answers)
Closed 4 years ago.
The full code is listed below, I'm copying and data from cell DB10 from the PivotTables sheet to column N in the Checklists sheet - also note that the rows in the Checklists sheet is dynamic and grows by 3018 rows each weekly...this is the part that slows down the processign time (I timed it and it takes ~8 minutes to complete processing when running the code)
This part is where things slow down:
Sheets("PivotTables").Select
Range("DB10").Select
Selection.Copy
Sheets("Checklists").Select
Dim rng As Range
NRowCount = Cells(Rows.Count, 1).End(xlUp).Offset(-3017).Row
ARowCount = Cells(Rows.Count, 1).End(xlUp).Row
For Each rng In Range("N" & NRowCount & ":N" & ARowCount)
rng.PasteSpecial xlPasteValues
Next rng
Full code:
Sub WeeklyUpdate()
Application.ScreenUpdating = False
'
' WeeklyUpdate Macro
'
'
Sheets("Checklists").Select
Dim LR As Long
LR = Range("A" & Rows.Count).End(xlUp).Row
Range("A3:M" & LR).SpecialCells(xlCellTypeVisible).Select
'
Selection.Copy
Selection.End(xlDown).Select
Selection.End(xlUp).Select
Sheets("Checklists").Cells(Rows.Count, 1).End(xlUp).Offset(1).PasteSpecial
xlPasteValues
Sheets("Checklists").AutoFilterMode = False
Sheets("PivotTables").Select
Range("DB10").Select
Selection.Copy
Sheets("Checklists").Select
Dim rng As Range
NRowCount = Cells(Rows.Count, 1).End(xlUp).Offset(-3017).Row
ARowCount = Cells(Rows.Count, 1).End(xlUp).Row
For Each rng In Range("N" & NRowCount & ":N" & ARowCount)
rng.PasteSpecial xlPasteValues
Next rng
Sheets("Home").Select
Application.ScreenUpdating = True
End Sub
If I'm understanding correctly, you're just pasting the value in cell DB10 into the range N[NRowCount]:N[ARowCount].
Rather than doing a For loop, just try something along the lines of:
Range("N" & NRowCount & ":N" & ARowCount).Value = Range("DB10").Value
It eliminates the loop and should be immediate.
Your final code would look roughly as follows:
...
Sheets("Checklists").AutoFilterMode = False
Sheets("Checklists").Range("N" & NRowCount & ":N" & ARowCount).Value = Sheets("PivotTables").Range("DB10").Value
Sheets("Home").Select

How do I get away from Select and Copy and write better code?

Can you explain how I can get away from using select and copy in this code? I want to make it run as efficiently as possible and without screen updating. I know I can set the screenupdating = false, but i prefer to just have the code written better!
Dim i As Integer
For i = 4 To 501
Sheets("Repository").Range("B" & i).Copy
Sheets("Input").Activate
Sheets("Input").Range("M13").Select
Selection.PasteSpecial Paste:=xlPasteValues
Sheets("Input").Range("M21").Copy
Sheets("Repository").Activate
Sheets("Repository").Range("E" & i).Select
Selection.PasteSpecial Paste:=xlPasteValues
Sheets("Input").Range("U12").Copy
Sheets("Repository").Activate
Sheets("Repository").Range("C" & i).Select
Selection.PasteSpecial Paste:=xlPasteValues
Sheets("Input").Range("V12").Copy
Sheets("Repository").Activate
Sheets("Repository").Range("D" & i).Select
Selection.PasteSpecial Paste:=xlPasteValues
Next i
Thanks so much.
If you're only moving values from one cell to another, there's no need to copy/paste. If you have to copy a lot of formatting over then there may be a need for it. This should accomplish the same thing, in my view it's the simplest way to go about it--
Dim wsRepository as Worksheet
Set wsRepository = ThisWorkbook.Sheets("Repository")
Dim wsInput as Worksheet
Set wsInput = ThisWorkbook.Sheets("Input")
Dim i As Integer
For i = 4 To 501
wsInput.Range("M13") = wsRepository.Range("B" & i)
wsRepository.Range("E" & i) = wsInput.Range("M21")
wsRepository.Range("C" & i) = wsInput.Range("U12")
wsRepository.Range("D" & i) = wsInput.Range("V12")
Next i
You can eliminate a lot of the activating and selecting. Here's how I would write it:
Application.ScreenUpdating = False
For i = 4 To 501
Sheets("Repository").Range("B" & i).Copy
Sheets("Input").Range("M13").PasteSpecial Paste:=xlPasteValues
Sheets("Input").Range("M21").Copy
Sheets("Repository").Range("E" & i).PasteSpecial Paste:=xlPasteValues
Sheets("Input").Range("U12").Copy
Sheets("Repository").Range("C" & i).PasteSpecial Paste:=xlPasteValues
Sheets("Input").Range("V12").Copy
Sheets("Repository").Range("D" & i).PasteSpecial Paste:=xlPasteValues
Next i
Application.ScreenUpdating = True
I would still recommend setting screenupdate to false. It will run a lot faster if it doesn't need to show the user each action it's taking.
First of all you don't need to select/activate/copy... you can simply assign values from one cell to another (with/without using variables). I would do this:
Sub test()
Dim i As Long 'Integer has a strict limit
Dim j As Integer
Dim RepositoryWs As Worksheet
Dim InputWs As Worksheet
Dim destinationCell(1 To 4) As Range
Dim sourceCell(1 To 4) As Range
Set RepositoryWs = Worksheets("Repository")
Set InputWs = Worksheets("Input")
'Static ranges
With InputWs
Set destinationCell(1) = .Range("M13")
Set sourceCell(2) = .Range("M21")
Set sourceCell(3) = .Range("U12")
Set sourceCell(4) = .Range("V12")
End With
For i = 4 To RepositoryWs.Range("B4").End(xlDown).Row 'Not hardcoded -> it works if you'll have more data on Repository sheet
'Dynamic ranges
With RepositoryWs
Set sourceCell(1) = .Range("B" & i)
Set destinationCell(2) = .Range("E" & i)
Set destinationCell(3) = .Range("C" & i)
Set destinationCell(4) = .Range("D" & i)
End With
For j = 1 To 4
destinationCell(j).Value = sourceCell(j).Value
Next j
Next i
End Sub

Resources