Excel VBA - Do Until Blank Cell - vba

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

Related

How to self reference a cell in VBA

I have 600k rows and want to remove starting and trailing whitespace. I have the following, but it is rather slow:
Sub Macro1()
'
' Macro1 Macro
'
'
Range("D1").Select
ActiveCell.FormulaR1C1 = "=TRIM(RC[-1])"
Range("D1").Select
Selection.AutoFill Destination:=Range("D1:D4")
Range("D1:D4").Select
Columns("D:D").Select
Selection.Copy
Range("C1").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Columns("D:D").Select
Application.CutCopyMode = False
Selection.ClearContents
Range("C1").Select
End Sub
Is there a way that I can apply the function on itself. I would like to avoid running a function in an empty column, then copying the values to the original column.
I tried VBA to fill formula down till last row in column as well as to speed up the formula. I have a few columns to do this with, and wonder if it is possible to only work on column C and trim the whitespace without the extra computations.
Thanks
This does not use a second column and does all the values in Column C. It moves the values to an array, iterates the array and trims the excess space and overwrites the values in C with the array.
Sub macro1()
Dim rng As Variant
Dim ws As Worksheet
Dim i As Long
Set ws = Worksheets("Sheet1") 'Change to your sheet name.
With ws
rng = .Range("C1", .Cells(.Rows.Count, 3).End(xlUp)).Value
For i = LBound(rng) To UBound(rng)
rng(i, 1) = Application.Trim(rng(i, 1))
Next i
.Range("C1", .Cells(.Rows.Count, 3).End(xlUp)).Value = rng
End With
End Sub
Change the code like this so you don't use Select. Using Select and Selection slows everything down horribly.
Sub Macro1()
Range("D1").FormulaR1C1 = "=TRIM(RC[-1])"
Range("D1").AutoFill Destination:=Range("D1:D4")
Columns("D:D").Copy
Range("C1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Application.CutCopyMode = False
Columns("D:D").ClearContents
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.

Code Cleanup for Combining Sheets

I do not have much experience with VBA but I will start by explaining my situation.
I have a workbook with 341 sheets. Each sheet is identical in layout in that they occupy the space A1:J48. I need to combine all of these into one sheet called "COMBINATION". The information of relevance is from A10:J48. I also need to have the cells from A1:J9 as they are the title which is shared across all the sheets.
What I did was write a code that copies A1:J48 for Sheet1 (to get the title and info) and pastes it into "COMBINATION" with the paste special as text, then a code that goes to Sheet2 and copies from A10:J48 and pastes it in the first empty cell in column A of "COMBINATION".
This brings me to my problem. I have realized that there must be an easier way of doing this instead of copying the code 339 more times for each of the sheets.
See below the code. It does what I want correctly but as mentioned, I would like to find a way to not do this 339 more times...
Sheets("Sheet1").Select
Range("A1:J48").Select
Selection.Copy
Sheets("COMBINATION").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Selection.Columns.AutoFit
Sheets("Sheet2").Select
Range("A10:J10").Select
Range("J10").Activate
Range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
Selection.Copy
Sheets("COMBINATION").Select
NextFree = Range("A10:A" & Rows.Count).Cells.SpecialCells(xlCellTypeBlanks).Row
Range("A" & NextFree).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
I would use code like the following:
Dim ws As Worksheet
Dim r As Long
'Copy A1:J9 from the first sheet
Worksheets("Sheet1").Range("A1:J9").Copy
WorkSheets("COMBINATION").Range("A1").PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, _
SkipBlanks:=False, _
Transpose:=False
'Now loop through every sheet (except "COMBINATION") copying cells A10:J48
r = 10 ' first sheet will be copied to row 10 in COMBINATION
For Each ws In Worksheets
If ws.Name <> "COMBINATION" Then
ws.Range("A10:J48").Copy
Worksheets("COMBINATION").Range("A" & r).PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, _
SkipBlanks:=False, _
Transpose:=False
'Set pointer ready for next sheet
r = r + 39
End If
Next
'Set column widths
Worksheets("COMBINATION").Columns.AutoFit
If your sheets don't always have data in all 39 rows (10 to 48), replace r = r + 39 with
r = Worksheets("COMBINATION").Range("A" & Worksheets("COMBINATION").Rows.Count).End(xlUp).Row + 1
Put the repeating code into a loop (untested):
Dim i as Integer
For i=2 to 341
Sheets(i).Select
Range("A10:J10").Select
Range("J10").Activate
Range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
Selection.Copy
Sheets("COMBINATION").Select
NextFree = Range("A10:A" & Rows.Count).Cells.SpecialCells(xlCellTypeBlanks).Row
Range("A" & NextFree).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Next i
Range.PasteSpecial xlPasteValues is convenient but slow. It is much faster to define your 'Target' range to be the same size as your source range and do a direct assignment.
Sub CombineData()
Application.ScreenUpdating = False
Dim ws As Worksheet
Dim Target As Range
With Worksheets("COMBINATION")
.Range("A1:J9").Value = Worksheets("Sheet1").Range("A1:J49").Value
For Each ws In Worksheets
If ws.Name <> .Name Then
Set Target = .Range("A" & .Rows.Count).End(xlUp).Offset(1)
Target.Resize(39, 10).Value = ws.Range("A10:J48").Value
End If
Next
End With
Application.ScreenUpdating = True
End Sub

Paste column width won't work on Excel

I'm beginner, and I want to ask something about my code. why paste column width wont work on VBA EXCEL??
Here's my code. thank you.
Sub merge()
Dim P As Integer
On Error Resume Next
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets.Add(After:= _
ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
ws.Name = "RAW"
Sheets(1).Activate
ActiveSheet.UsedRange.Select
Selection.Copy Destination:=Sheets("RAW").Range("A1")
Sheets("RAW").Range("A1").PasteSpecial Paste:=xlPasteColumnWidths, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
For P = 2 To Sheets.Count - 1
Sheets(P).Activate
Range("A5").Select
Selection.CurrentRegion.Select
Selection.Offset(1, 0).Resize(Selection.Rows.Count - 1).Select
Selection.Copy Destination:=Sheets("RAW").Range("A1000000").End(xlUp)(2)
Next
End Sub
:) In your code you are referencing to a range A1, which is already in "A:Z".
If you want to make the columns B to Z equal to the column A in width, use the following code.
Columns("B:Z").columnwidth = columns("A:A").columnwidth

move cell values in excel through vba

I am working on an excel sheet and need to move the same range over and over again to the column "P" + 2
So the next range would be "C15:G15" to "P14". I'm looking for a slimmer solution than to repeat this code and change the ranges for hundreds of times..
ActiveWindow.SmallScroll Down:=-3
Range("C13:G13").Copy
Application.CutCopyMode = False
Selection.Copy
Range("P12").Select
Selection.PasteSpecial Paste:=xlPasteAllUsingSourceTheme, Operation:=xlNone _
, SkipBlanks:=False, Transpose:=False
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
This quick snippet should walk down every second row in column C starting at row 13 till the last populated cell in column C.
Sub move_CG_to_PT()
Dim rw As Long
With Worksheets("Sheet4") '<~~set this worksheet reference properly!
For rw = 13 To .Cells(.Rows.Count, "C").End(xlUp).Row Step 2
.Cells(rw - 1, "P").Resize(1, 5) = _
.Cells(rw, "C").Resize(1, 5).Value
Next rw
End With
End Sub
This only transfers the values. If the formatting and/or theme is critical then those could be adjusted for with the following.
Sub move_CG_to_PT_w_Formatting()
Dim rw As Long
With Worksheets("Sheet4") '<~~set this worksheet reference properly!
For rw = 13 To .Cells(.Rows.Count, "C").End(xlUp).Row Step 2
.Cells(rw, "C").Resize(1, 5).Copy _
Destination:=.Cells(rw - 1, "P")
Next rw
End With
End Sub