Looping a cut and paste if criteria is met - vba

I am trying to loop the following
Dim x As Integer
Dim y As Integer
x = Range("AE4")
y = Range("AD4")
If x >= y Then
Range("AE4").Select
Selection.Copy
Range("AD4").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Else
End If
Once this cell AE4 has been checked and then copied or not depeding of it is greater or = to AD4 i would like this to then move on to AE5, AE6 etc to the end of the data set. any ideas what i need to do next? I currently have the rest of the script executed before this checking iof the a cell date is below 4 weeks and then 5 weeks, 6 weeks old up to 10 weeks. and is currenlty working as expected checking the date of the cell and then checking and copying the first cell in the data.
Full script is as follows.
Sub Test()
Range("AE4").Select
ActiveCell.Formula = _
"=IF(RC[-2]>=TODAY()-28,""1"",IF(AND(RC[-2]<TODAY()-28,RC[-2]>=TODAY()-35),""4"",IF(AND(RC[-2]<TODAY()-35,RC[-2]>=TODAY()-42),""5"",IF(AND(RC[-2]<TODAY()-42,RC[-2]>=TODAY()-49),""6"",IF(AND(RC[-2]<TODAY()-49,RC[-2]>=TODAY()-56),""7"",IF(AND(RC[-2]<TODAY()-56,RC[-2]>=TODAY()-63),""8"",IF(AND(RC[-2]<TODAY()-63,RC[-2]>=TODAY()-70),""9"",IF(RC[-2]<TODAY()-70,""10""))))))))"
Range("AE4").Select
Selection.AutoFill Destination:=Range("AE4:AE200")
Range("AE4:AE200").Select
Dim x As Integer
Dim y As Integer
x = Range("AE4")
y = Range("AD4")
If x >= y Then
Range("AE4").Select
Selection.Copy
Range("AD4").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Else
End If
End Sub

Below is some code that'll do what I think you're asking. It looks as though you're relying on the macro generator quite heavily which tends to 'select' a lot more than a developer needs to do. Have a play with your code and look at other posts to see how others do it.
Sub Test()
Dim ws As Worksheet
Dim startCell as Range
Dim fullRng As Range
Dim thisCell As Range
Dim leftCell as Range
Set ws = ThisWorkbook.Worksheets("Sheet1")
Set startCell = ws.Range("AE4")
Set fullRng = startCell.Resize(196)
startCell.Formula = "=IF(RC[-2]>=TODAY()-28,""1"",IF(AND(RC[-2]<TODAY()-28,RC[-2]>=TODAY()-35),""4"",IF(AND(RC[-2]<TODAY()-35,RC[-2]>=TODAY()-42),""5"",IF(AND(RC[-2]<TODAY()-42,RC[-2]>=TODAY()-49),""6"",IF(AND(RC[-2]<TODAY()-49,RC[-2]>=TODAY()-56),""7"",IF(AND(RC[-2]<TODAY()-56,RC[-2]>=TODAY()-63),""8"",IF(AND(RC[-2]<TODAY()-63,RC[-2]>=TODAY()-70),""9"",IF(RC[-2]<TODAY()-70,""10""))))))))"
startCell.AutoFill fullRng
For Each thisCell In fullRng.Cells
Set leftCell = thisCell.Offset(, -1)
Debug.Print("Before If: " & thisCell.Address(False, False) & "=" & thisCell.Value2 & " v. " & leftCell.Address(False, False) & "=" & leftCell.Value2)
If thisCell.Value2 >= leftCell.Value2 Then
leftCell.Value2 = cell.Value2
Debug.Print("After If: " & thisCell.Address(False, False) & "=" & thisCell.Value2 & " v. " & leftCell.Address(False, False) & "=" & leftCell.Value2)
End If
Next
End Sub

Easiest way is probably a lopp that just repeats what you are doing.
Instead of defining x and y as ranges, you would only need a count variable:
dim lastrow as integer
lastrow = Cells(Rows.count, "AE").End(xlUp).row 'counts the amount of cells you have with values in the row
for i = 2 to lastrow 'set 2 = whatever, but I guess you have header rows, if you want to start in the 4th row set it 4
if CELLS(i,31).Value >= CELLS(i,30).Value THEN 'the cell commands uses 1-indexed numbers to refer to cells on an x-y axis, rows go on the x axis so Cells(2,1) is "B1" for some reason.
'insert your loop here
Cells(i,31).Select
Selection.Copy
Cells(i,30).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End if
Next i

Related

Any one can do Macro using loop that can transpose multiple rows into columns

Hy i have a recorded macro, i am trying to use it using loop so that i can transpose multiple rows and columns in one click. The idea is that i have a number 10000 rows with columns 1000 in which emails are there.i want to use macro that transpose my rows data into columns using do while or loop. I have record the macro but it only work for one one row and column. The code is there.
Sheets("Mastersheet").Select
Range("J2:XFD2").Select
Selection.Copy
Sheets("Sheet2").Select
Range("A1").Select
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
You can resolve your problem faster if you at least try and search for answers and information.
Excel VBA - Range.Copy transpose paste
Code:
Option Explicit
Sub test()
Dim master_sheet As Worksheet
Set master_sheet = ThisWorkbook.Sheets("Mastersheet")
Dim output_sheet As Worksheet
Set output_sheet = ThisWorkbook.Sheets.Add
Dim start_row As Long
start_row = 2
Dim last_row As Long
With master_sheet
last_row = .Cells(.Rows.Count, "J").End(xlUp).Row
.Range("J" & start_row & ":XFD" & last_row).Copy
End With
With output_sheet
.Range("A1").PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:=False, Transpose:=True
End With
End Sub
Try this:
Sub Macro9()
t = 2
Do Until t = 10000
Sheets("Mastersheet").Range("J" & t & ":XFD" & t).Copy
Sheets("Sheet2").Select
Sheets("Sheet2").Cells(1, t).Select
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
t = t + 1
Loop
End Sub

FIltering a data set in excel vba and pasting results into different tabs that are named based on filter

I am trying to filter a data set in tab "Expiring Contracts", filtered on column B (this data set can increase or decrease based at any point). The different filters come from tab "Inputs" which can change overtime (increase or decrease). I am trying to paste the results of the filter to separate tabs that are named exactly like the list, BUT I want to paste the values on the next available (blank) cell. This is what I have now:
Sub ParseList2()
Dim uwname As String
Dim lastrowUW As Long
Dim lastrow As Long
Dim N As Range
lastrowUW = Sheets("Inputs").Cells(Rows.Count, "H").End(xlUp).Row
For Each N In Sheets("Inputs").Range("H2:H" & lastrowUW).Cells
uwname = N.Text
Sheets("Expiring Contracts").Range("$A:$AA").AutoFilter Field:=2,
Criteria1:=N
lastrow = Columns(2).Find("*", SearchDirection:=xlPrevious).Row
Range("A2:AA" & lastrow).SpecialCells(xlCellTypeVisible).Select
Selection.Copy
Sheets(uwname).Select
lastrow = Columns(2).Find("*", SearchDirection:=xlPrevious).Row + 1
Range("A" & lastrow).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Next N
Sheets("Expiring Contracts").AutoFilterMode = False
End Sub
This worked thanks to some comments below!
Sub ParseList2()
Dim uwname As String
Dim lastrowUW As Long
Dim lastrow As Long
Dim N As Range
Dim rng As Range
lastrowUW = Sheets("Inputs").Cells(Rows.Count, "H").End(xlUp).Row
For Each N In Sheets("Inputs").Range("H2:H22").Cells
uwname = N.Value
Sheets("Expiring Contracts").Range("$A:$AA").AutoFilter Field:=2,
Criteria1:=uwname
'lastrow = Columns(2).Find("*", SearchDirection:=xlPrevious).Row + 1
Range("A2:AA99999").SpecialCells(xlCellTypeVisible).Select
Selection.Copy
Sheets(uwname).Select
lastrow = Columns(2).Find("*", SearchDirection:=xlPrevious).Row + 1
Range("A" & lastrow).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("A1").Select
Sheets("Expiring Contracts").Select
Sheets("Expiring Contracts").AutoFilterMode = False
Range("A1").Select
Next N
Sheets("Expiring Contracts").Select
Sheets("Expiring Contracts").AutoFilterMode = False
Range("A1").Select
End Sub
What you are attempting to do using VBA can very easily be accomplished using PivotTables and Slicers. Turn your source data into an Excel Table, make a PivotTable out of it, put the PivotTable in the Inputs tab, set up a Slicer on the field you want to filter on, put the other fields of interest in the PivotTable as row fields, and you're done. No code necessary. Let the application do the work for you.

Excel VBA - Do Until Blank Cell

I'm recording a macro and need some help. I'd like copy and paste the values from the column G of the "SalesData" worksheet into cells A2, A12, A22 etc of the "Results" worksheet until there's no more values in the column G.
VBA is pretty new to me, I've tried using Do/Until, but everything crashed. Could you please help me? Please see the code I've recorded below. Thank you!
Sub(x)
Sheets("SalesData").Select
Range("G2").Select
Selection.Copy
Sheets("Results").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("A12").Select
Sheets("SalesData").Select
Range("G3").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Results").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("A22").Select
Sheets("SalesData").Select
Range("G4").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Results").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("A32").Select
Sheets("SalesData").Select
Range("G5").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Results").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub
I prefer to find the last cell in the column first then use a For loop.
Since you are only doing the values we can avoid the clipboard and assign the values directly.
Since you paste is every 10 cells we can use a separate counter to move down 10 each loop.
Sub x()
Dim ws As Worksheet
Dim lst As Long
Dim i As Long, j As Long
'use variable to limit the number of times we type the same thing
Set ws = Worksheets("Results")
'First row of the output
j = 2
'using with and the "." in front of those items that belong to it also limits the typing.
With Worksheets("SalesData")
'Find the last row with values in Column G
lst = .Cells(.Rows.Count, 7).End(xlUp).Row
'Loop from the second row to the last row.
For i = 2 To lst
'Assign the value
ws.Cells(j, 1).Value = .Cells(i, 7).Value
'Move down 10 rows on the output
j = j + 10
Next i
End With
End Sub
here is the same thing but using range variables
Sub x()
Dim src As Range
Dim dst As Range
Set dst = Worksheets("Results").Range("a2") ' point to top cell of destination
With Worksheets("SalesData")
For Each src In Range(.Cells(2, "g"), .Cells(.Rows.Count, "g").End(xlUp)) ' loop through used cell range in column G
dst.Value = src.Value
Set dst = dst.Offset(10) ' move destination pointer down 10 rows
Next src
End With
End Sub
This is just for fun/practice for another way to do it:
Sub copyFromG()
Dim copyRng As Range, cel As Range
Dim salesWS As Worksheet, resultsWS As Worksheet
Set salesWS = Sheets("SalesData")
Set resultsWS = Sheets("Results")
Set copyRng = salesWS.Range("G2:G" & salesWS.Range("G2").End(xlDown).Row) ' assuming you have a header in G1
For Each cel In copyRng
resultsWS.Range("A" & 2 + 10 * copyRng.Rows(cel.Row).Row - 30).Value = cel.Value
Next cel
End Sub

Fast Stack-Columns and Transpose

After few days learning VBA, I managed to get a simple macro to take some data from a sheet and transpose to another, then stack the columns together.
Macro
Sub pivotsourcedata()
Dim HeaderSelect As Range
Dim DataSelect As Range
Dim ID As Range
'Variabile Declaration for Progress bar
Dim x As Integer
Dim MyTimer As Double
For i = 1 To 7589
'Progress bar
Application.StatusBar = "Progress: " & i & " of 7589: " & Format(i / 7589, "0%")
'Copy ID Range
Sheets("Opps Closed FY15").Select
Range("A13").Offset(i, 0).Select
Set ID = Selection
'Copy Header Range
Range("EX13:HA13").Select
Set HeaderSelect = Selection
'Copy Data Range
Range("EX13:HA13").Offset(i, 0).Select
Set DataSelect = Selection
'Select ID and copy it to the next sheet and fill it down
ID.Copy
Sheets("Sheet1").Select
If i = 1 Then
Else
Selection.Resize(1, 1).Offset(0, 1).Select
End If
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
Selection.Resize(HeaderSelect.Columns.Count).FillDown
'Select the Header, copy it in the adjacent column
Selection.Resize(1, 1).Select
Selection.Offset(0, 1).Select
Sheets("Opps Closed FY15").Select
HeaderSelect.Copy
Sheets("Sheet1").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
'Same for the data, copy to the right of Header
Selection.Resize(1, 1).Select
Selection.Offset(0, 1).Select
Sheets("Opps Closed FY15").Select
DataSelect.Copy
Sheets("Sheet1").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
'Stack the columns one over the other 3 by 3.
' take the 4th, 5th and 6th columns and stuck'em
' below 1st, 2nd and 3rd
If i = 1 Then
Else
Range("A1:C1").Offset(56 * (i - 1), 0).Resize(56, 3).Select
Dim PasteSelect As Range
Set PasteSelect = Selection
Range("D1:F56").Select
Selection.Cut Destination:=PasteSelect
Selection.Resize(1, 1).Offset(0, -1).Select
End If
Next i
Application.StatusBar = False
End Sub
As you can see for each of the 7589 times, I copy and transpose 3 times a range of 56 columns. This is taking a while, around 1.5h. Since I need to run it every week, I'm asking if I wrote badly some code portions...maybe I don't know I can seed it up in some areas...
any thoughts?
Update
After yours suggestions i get to tune up a bit the code, I'd like to know if there are others "imperfections"
Sub pivotsourcedata()
Dim OppsClosed As Worksheet
Set OppsClosed = Worksheets("Opps Closed FY15")
Dim Shadow2 As Worksheet
Set Shadow2 = Worksheets("Shadow2")
Dim ID As Range
Dim ID0 As Range
Set ID0 = OppsClosed.Range("A14")
Dim HeaderSelect As Range
Set HeaderSelect = OppsClosed.Range("EX13:HA13")
Dim DataSelect As Range
Set DataSelect = HeaderSelect
Dim PasteSelect As Range
Dim PasteSelect0 As Range
Set PasteSelect0 = Shadow2.Range("A1:C1").Resize(56, 3)
Dim CopySelect As Range
Set CopySelect = Shadow2.Range("D1:F56")
Dim Inizialize As Range
Set Inizialize = Shadow2.Range("D1:D1")
'Variabile Declaration for Progress bar
Dim x As Integer
Dim MyTimer As Double
'Set ScreenUpdating to False
Application.ScreenUpdating = False
For i = 1 To 7589
'Progress bar
Application.StatusBar = "Progress: " & i & " of 7589: " & Format(i / 7589, "0%")
'Copy ID Range
Set ID = ID0.Offset(i, 0)
'Copy Data Range
Set DataSelect = HeaderSelect.Offset(i, 0)
'Select ID and copy it to the next sheet and fill it down
ID.Copy
Shadow2.Select
If i = 1 Then
Range("A1").PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
Range("A1").Resize(HeaderSelect.Columns.Count).FillDown
Else
Range("D1").PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
Range("D1").Resize(HeaderSelect.Columns.Count).FillDown
End If
'Select the Header, copy it in the adiacent column
HeaderSelect.Copy
If i = 1 Then
Shadow2.Range("B1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
Else
Shadow2.Range("E1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
End If
'Same for the data, copy to the right of Header
DataSelect.Copy
If i = 1 Then
Shadow2.Range("C1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
Else
Shadow2.Range("F1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
End If
'Stack the columns one over the other 3 by 3.
' take the 4th, 5th and 6th columns and stuck'em
' below 1st, 2nd and 3rd
If i = 1 Then
Else
Set PasteSelect = PasteSelect0.Offset(HeaderSelect.Columns.Count * (i - 1), 0)
Shadow2.Range("D1:F56").Cut Destination:=PasteSelect
End If
Next i
Application.StatusBar = False660858
'Set ScreenUpdating to True
Application.ScreenUpdating = True
End Sub
Take a look at this link for several other things that you can turn off, such as formula recalculation: http://datapigtechnologies.com/blog/index.php/ten-things-you-can-do-to-speed-up-your-excel-vba-code/
I agree that the multiple selects are unnecessary and likely slowing down the code significantly. In many cases, they can simply be combined - as in using
Selection.Resize(1, 1).Offset(0, 1).Select
instead of
Selection.Resize(1, 1).Select
Selection.Offset(0, 1).Select
But also, why not reference your ranges explicitly using your counter value, and avoid using resize and offset so frequently?
Another thought is to see if you can remove the final operation that stacks the columns after they are pasted to a new sheet - would it be possible to rearrange your source data, perhaps at the top of your macro before you get into the loop? That way you would have to perform that stacking once instead of 7589 times. Or, alternatively, find a way to combine the columns after the end of the loop.
The answer to my question was: "Use arrays" :)
The code now is this:
Sub pivotsourcedata()
'Set ScreenUpdating to False
Application.ScreenUpdating = False
Application.StatusBar = True
Dim OppsClosed As Worksheet
Set OppsClosed = Worksheets("Opps Closed FY15")
Sheets.Add.Name = "Shadow2"
Dim Shadow2 As Worksheet
Set Shadow2 = Worksheets("Shadow2")
Dim ID As Range
Dim ID0 As Range
Set ID0 = OppsClosed.Range("A13")
Dim HeaderSelect As Range
Set HeaderSelect = OppsClosed.Range("FB1")
Dim DataSelect As Range
Set DataSelect = OppsClosed.Range("FC14")
Dim RowSize As Integer
OppsClosed.Activate
Dim lastrow, records, nHeader As Integer
lastrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row - 13
nHeader = 56
records = lastrow * nHeader
'Stack DataSelect on column C of Shadow 2
ReDim TempTableData(1 To nHeader, 1 To lastrow) As Variant
ReDim TempTableHeader(1 To nHeader, 1 To lastrow)
ReDim FixedHeaders(1 To nHeader, 1 To 1)
ReDim Temp_Array1(1 To records, 1 To 1) As Variant
ReDim Temp_Array2(1 To records, 1 To 1) As Variant
FixedHeaders = OppsClosed.Range("FC1").Resize(1, nHeader)
FixedHeaders = Application.Transpose(FixedHeaders)
For j = 1 To lastrow
'Progress bar
Application.StatusBar = "Progress: " & j & " of " & lastrow & ": " & Format(j / lastrow, "0%")
For i = 1 To nHeader
TempTableData(i, j) = DataSelect.Offset(j - 1, i - 1)
TempTableHeader(i, j) = FixedHeaders(i, 1)
Next i
Next j
For j = 1 To nHeader
For i = 0 To lastrow - 1
Temp_Array1((i * nHeader) + j, 1) = TempTableData(j, i + 1)
Temp_Array2((i * nHeader) + j, 1) = TempTableHeader(j, i + 1)
Next i
Next j
Shadow2.Range("C1:C" & records).Value2 = Temp_Array1
Shadow2.Range("B1:B" & records).Value2 = Temp_Array2
'Copy and Replicate ID
ReDim TempTableID(1 To records, 1 To 1)
k = 1
For i = 1 To records
'Progress bar
Application.StatusBar = "Progress: " & i & " of " & records & ": " & Format(i / records, "0%")
DoEvents
'FixedID = OppsClosed.Range("A13").Offset(k, 0)
TempTableID(i, 1) = OppsClosed.Range("A13").Offset(k, 0)
variable = i / nHeader
If Fix(variable) = variable Then
k = k + 1
End If
Next i
Shadow2.Range("A1:A" & records).Value2 = TempTableID
Application.StatusBar = False
Application.ScreenUpdating = True
End Sub

Copying the data in Excel through VBA

As you can see down, I am copy 4 columns of data from one workbook to another. I am stuck at a case where the destination has 8 columns and my area of columns are 1,2,5,7. can you suggest me some changes in the code please. The one below will work only for first 4 columns. Thanks.
Sub Copymc()
Dim x As Workbook
Dim y As Workbook
Dim rng As Range
Set x = Workbooks.Open("H:\testing\Q4 2014\US RMBS Q4.xlsx")
Set y = Workbooks.Open("H:\testing\demo\test1.xlsx")
Dim LastRow As Long
Dim NextRow As Long
x.Worksheets("RL Holdings").Activate
Range("A65536").Select
ActiveCell.End(xlUp).Select
LastRow = ActiveCell.Row
Range("A2:D" & LastRow).Copy
y.Worksheets("Sheet1").Range("a65536").End(xlUp).Offset(1, 0)
Application.CutCopyMode = False
End sub
The line Range("A2:D" & LastRow).Copy has column D hardcoded into it. This means that it will always copy A2 to D65536. If you want specific columns(A, B, E, G) then I would recommend simply repeating your code for each column.
For example
Range("A65536").Select
ActiveCell.End(xlUp).Select
Selection.Copy
y.Worksheets("Sheet1").Range("a65536").End(xlUp).Offset(1, 0).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
then copy the code four times and replace the A to whatever column you want to copy or paste to. If this isn't what you are looking for please elaborate on what you want.