I have some VBA code that works fine, however I'm trying to improve my code by losing the select commands. I am learning that this is not best practice. The (old) code that works is below:
With Sheets("Data")
RowCount = .Cells(.Rows.Count, "B").End(xlUp).Row
For i = 1 To RowCount
Range("B1").Offset(1, 0).Select
If ActiveCell.Offset(0, -1).Value = 2 And ActiveCell.Value = sPeril Then
ActiveSheet.Cells.Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
Sheets("DynamicCharts").Select
Sheets("DynamicCharts").Range("E" & Cells.Rows.Count).End(xlUp).Offset(1, 0).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Sheets("Data").Select
End If
next i
End With
The code switches between sheets copying and pasting using offset cells. Ive tried to change this with a WITH command and its debugging on the paste command.
With Sheets("Data")
RowCount = .Cells(.Rows.Count, "B").End(xlUp).Row
For i = 1 To RowCount
Range("B1").Offset(1, 0).Select
If ActiveCell.Offset(0, -1).Value = 1 And ActiveCell.Value = sPeril Then
ActiveSheet.Cells.Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
With Sheets("DynamicCharts")
.Range("A" & Cells.Rows.Count).End(xlUp).Offset(1, 0).Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
End With
'Sheets("EDM Data").Select
End If
next i
End With
Any help on this would be much appreicated.
Thanks in advance
Give this a shot instead - this completely removes the need for Select. We could also get rid of Copy/Paste as well, but I need to know what you're trying to bring over (maybe it's format specific?). Please include more of your code when asking a question (like what sPeril is, etc.):
Dim destrow As Long, lastcol As Long
With Sheets("Data")
RowCount = .Cells(.Rows.Count, "B").End(xlUp).Row
For i = 2 To RowCount
If Range("B" & i).Offset(0, -1).Value = 2 And Range("B" & i).Value = sPeril Then
destrow = Sheets("DynamicCharts").Cells(Sheets("DynamicCharts").Rows.Count, "E").End(xlUp).Row
lastcol = Sheets("Data").Cells(i, Sheets("Data").Columns.Count).End(xlToLeft).Column
Sheets("Data").Range(Sheets("Data").Cells(i, 2), Sheets("Data").Cells(i, lastcol)).Copy
Sheets("DynamicCharts").Range("E" & destrow + 1).PasteSpecial
End If
Next i
End With
your code but with a simple fix just look at the comment. Note I set peril to 2 just so that i can make the code fall into that condition.
Sub test2()
With Sheets("sheet1")
RowCount = .Cells(.Rows.Count, "B").End(xlUp).Row
For i = 1 To RowCount
Range("B1").Offset(1, 0).Select
sPeril = 2
If ActiveCell.Offset(0, -1).Value = 1 And ActiveCell.Value = sPeril Then
ActiveSheet.Cells.Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
With Sheets("DynamicCharts")
'remove selection on this line.
.Range("A" & Cells.Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
End With
'Sheets("EDM Data").Select
End If
Next i
End With
End Sub
Related
Dummy data of a tournament
Above is the example of the dummy data. My goal is to use VBA to group the data so that there is only one name displayed and the 3 Games populated with the Results so there would only be one line for the name as well as the 3 Games' results in the same line.
Example of the output data
Well, this is not as easy as first appears, however, this works:
So, the country is returned with classic index & match. The results are built by finding the result against each player and round. This expects blanks in the other cells for each player.
Try this:
Sub mSummarise()
'
' Macro1 Macro
'
'
Dim lData, lSummary, lFilter As String
Dim lRow1, lRow2, lRow3, lCol1, lCount As Long
lData = ActiveSheet.Name
Range("A1").Select
Selection.End(xlToRight).Select
lCol1 = ActiveCell.Column
Range("A1").Select
Selection.End(xlDown).Select
lRow1 = ActiveCell.Row
Sheets.Add After:=ActiveSheet
ActiveSheet.Name = "Summary"
Sheets(lData).Activate
Range("A1:B" & lRow1).Select
Selection.Copy
Sheets("Summary").Select
ActiveSheet.Paste
Application.CutCopyMode = False
ActiveSheet.Range("$A$1:$B$" & lRow1).RemoveDuplicates Columns:=Array(1, 2), Header _
:=xlNo
Range("A1").Select
Selection.End(xlDown).Select
lRow2 = ActiveCell.Row
Sheets(lData).Select
Range(Cells(1, 3), Cells(1, lCol1)).Select
Selection.Copy
Sheets("Summary").Select
Range("C1").Select
ActiveSheet.Paste
Sheets(lData).Select
For lCount = 3 To lCol1
Range(Cells(1, 1), Cells(lRow1, lCol1)).Select
Selection.AutoFilter
ActiveSheet.Range(Cells(1, 1), Cells(lRow1, lCol1)).AutoFilter Field:=lCount, Criteria1:="<>", Operator:=xlAnd
Range(Cells(1, 1), Cells(lRow1, lCount)).Select
Selection.SpecialCells(xlCellTypeVisible).Select
Selection.Copy
Sheets.Add After:=ActiveSheet
lFilter = ActiveSheet.Name
ActiveSheet.Paste
Range("A1").Select
Selection.End(xlDown).Select
lRow3 = ActiveCell.Row
Sheets("Summary").Select
Application.CutCopyMode = False
Cells(2, lCount).Select
ActiveCell.Formula = "=VLOOKUP(A2," & lFilter & "!$A$2:" & Cells(lRow3, lCount).Address & "," & lCount & ",0)"
Range(Cells(2, lCount), Cells(2, lCount)).Copy
Range(Cells(2, lCount), Cells(lRow3, lCount)).Select
ActiveSheet.Paste
Range(Cells(2, lCount), Cells(lRow3, lCount)).Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Sheets(lFilter).Select
Application.DisplayAlerts = False
ActiveWindow.SelectedSheets.Delete
Application.DisplayAlerts = True
Sheets(lData).Select
Next
Selection.AutoFilter
Range("A1").Select
Sheets("Summary").Select
Range("A1").Select
End Sub
I am new to VBA, but had a situation where doing this manually would be extremely tedious, so I got to learning.
I needed a script that can find certain text values on a column and then copy a certain number of rows with all the row values into another worksheet. Full row values on the first row, and first 5 rows on the next rows. The text value that is searched is for example "DOL-1" or "VFD".
After lots of research and trial and error, I have managed to stitch together this script that does the job, but it is obviously badly written and not optimized. I have tried searching for similar questions and tried their answers, but I couldn't get anything to do what this script does.
I was wondering if there are some better and/or faster methods to achieve the same thing as this script does?
Sub Add_Rows()
Dim wbC As Workbook
Dim wbP As Workbook
Dim wsC As Worksheet
Dim wsP As Worksheet
Dim cell As Range
Dim r As Integer
Dim dataTable As Range
r = 8
'rownumber
Set wbP = Application.Workbooks.Open("C:\Projects\Feed_list.xlsx")
Set wsP = wbP.Worksheets("Feed_list")
' set paste destination (these variables aren't really even used because I couldn't get them to work)
Set wbC = Application.Workbooks.Open("C:\Projects\Generated_list.xlsm")
Set wsC = wbC.Worksheets("GEN")
' set copy location (these variables aren't really even used because I couldn't get them to work)
Windows("Generated_list.xlsm").Activate
Application.ScreenUpdating = False
For Each cell In Range("AB2:AB5000")
If cell.Value = "DOL-1" Then
Debug.Print cell.Address
Windows("Generated_list.xlsm").Activate
Range(cell, cell.Offset(, -25)).Copy
Windows("Feed_list.xlsx").Activate
Sheets("Feed_list").Select
'Debug.Print r
Rows(r).Select
Selection.EntireRow.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
r = r + 1
Rows(r).Select
Selection.EntireRow.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
r = r + 1
Rows(r).Select
Selection.EntireRow.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
r = r + 1
Rows(r).Select
Selection.EntireRow.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
r = r + 1
Windows("Generated_list.xlsm").Activate
Range(cell.Offset(, -21), cell.Offset(, -25)).Copy
Windows("Feed_list.xlsx").Activate
Sheets("Feed_list").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Windows("Generated_list.xlsm").Activate
Range(cell.Offset(, -21), cell.Offset(, -25)).Copy
Windows("Feed_list.xlsx").Activate
Sheets("Feed_list").Select
Selection.Offset(-1).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Windows("Generated_list.xlsm").Activate
Range(cell.Offset(, -21), cell.Offset(, -25)).Copy
Windows("Feed_list.xlsx").Activate
Sheets("Feed_list").Select
'Rows(r).Select
Selection.Offset(-1).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End If
If cell.Value = "VFD" Then
Debug.Print cell.Address
Windows("Generated_list.xlsm").Activate
Range(cell, cell.Offset(, -25)).Copy
Windows("Feed_list.xlsx").Activate
Sheets("Feed_list").Select
'Debug.Print r
Rows(r).Select
Selection.EntireRow.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
r = r + 1
Rows(r).Select
Selection.EntireRow.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
r = r + 1
Windows("Generated_list.xlsm").Activate
Range(cell.Offset(, -21), cell.Offset(, -25)).Copy
Windows("Feed_list.xlsx").Activate
Sheets("Feed_list").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Windows("Generated_list.xlsm").Activate
Range(cell.Offset(, -21), cell.Offset(, -25)).Copy
Windows("Feed_list.xlsx").Activate
Sheets("Feed_list").Select
Selection.Offset(-1).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End If
'these if functions are repeated about 20 times with different text values and number of rows copied
Next
Application.ScreenUpdating = True
Windows("Feed_list.xlsx").Activate
Sheets("Feed_list").Select
End Sub
I made small example pictures. The Generated_list looks like this. (Notice column AB)
The Feed_list looks like this at first.
And after running the script it should look like this.
Sub Main()
Call Add_Rows(8)
End Sub
Sub Add_Rows(whereToAdd As Long)
Dim wb_Feed As Workbook, wb_Gen As Workbook
Dim ws_Feed As Worksheet, ws_Gen As Worksheet
Dim lastRow As Long, lastCol As Long, i As Long, idxType As Long
Set wb_Feed = Workbooks.Open("C:\Projects\Feed_list.xlsx")
Set wb_Gen = Workbooks.Open("C:\Projects\Generated_list.xlsm")
Set ws_Feed = wb_Feed.Worksheets("Feed_List")
Set ws_Gen = wb_Gen.Worksheets("Generated_List")
' Find the last row and last column of the data in Generated List
' Assume that the first column does not contain any blank data in middle
lastRow = ws_Gen.Cells(ws_Gen.Rows.Count, "A").End(xlUp).Row
lastCol = ws_Gen.Cells(1, ws_Gen.Columns.Count).End(xlToLeft).Column ' First row is header
' Column AB is the last column
idxType = lastCol
With ws_Gen
For i = 2 To lastRow
If .Cells(i, idxType).Value = "VFD" Then
' Insert a row to Feed List
ws_Feed.Range("A" & whereToAdd).EntireRow.Insert
' Copy entire row
.Range(.Cells(i, 1), .Cells(i, lastCol)).Copy
' Paste
ws_Feed.Range("A" & whereToAdd).PasteSpecial xlPasteAll
Application.CutCopyMode = False
' Since VFD, insert extra 1 line according to your screenshot
whereToAdd = whereToAdd + 1
ws_Feed.Range("A" & whereToAdd).EntireRow.Insert
' Copy first 5 columns
.Range(.Cells(i, 1), .Cells(i, 5)).Copy
' Paste
ws_Feed.Range("A" & whereToAdd).PasteSpecial xlPasteAll
Application.CutCopyMode = False
' Update where to add next
whereToAdd = whereToAdd + 1
ElseIf .Cells(i, idxType).Value = "DOL-1" Then
' Insert a row to Feed List
ws_Feed.Range("A" & whereToAdd).EntireRow.Insert
' Copy entire row
.Range(.Cells(i, 1), .Cells(i, lastCol)).Copy
' Paste
ws_Feed.Range("A" & whereToAdd).PasteSpecial xlPasteAll
Application.CutCopyMode = False
' Since DOL-1 insert extra 3 lines according to your screenshot
whereToAdd = whereToAdd + 1
ws_Feed.Range("A" & whereToAdd).EntireRow.Insert
ws_Feed.Range("A" & whereToAdd).EntireRow.Insert
ws_Feed.Range("A" & whereToAdd).EntireRow.Insert
' Copy first 5 columns
.Range(.Cells(i, 1), .Cells(i, 5)).Copy
ws_Feed.Range("A" & whereToAdd).PasteSpecial xlPasteAll
ws_Feed.Range("A" & whereToAdd + 1).PasteSpecial xlPasteAll
ws_Feed.Range("A" & whereToAdd + 2).PasteSpecial xlPasteAll
Application.CutCopyMode = False
' Update where to add next
whereToAdd = whereToAdd + 3
End If
Next i
End With
' You should close the workbook after you finish your job
End Sub
I have 4 sheets of data with thousands of rows in each sheet. There is one column within each sheet that I would like to consolidate into a 5th sheet. In this column, I'd like to make sure that every name from the previous four sheets is included in one comprehensive list with no repeats.
See a simple example below, but imagine 20,000 rows on each sheet with complex names. Can anyone think of a method of doing this, that does not require tweaking everytime the inputs change? I've been trying to use PivotChart Wizard with no luck.
Sheet 1 Sheet 2 Sheet 3 Sheet 4 Ideal Sheet 5
Dog Cat Fish Giraffe Dog
Hamster Dog Lhama Cat Cat
Giraffe Elephant Dog Fish Fish
Giraffe
Elephant
Hamster
Lhama
Here is the code I came up with to solve the problem in case anyone is interested. "Zone & Fam" just specifies the column I'm interested in.
Sub GetUniqueZoneFam()
Application.ScreenUpdating = False
Dim Lastrow As Long
Worksheets("Calculation Indv").Range("A:A").ClearContents
Worksheets("fcst fg").Activate
Range("Fcst_Fg[Zone & Fam]").Copy
Worksheets("Calculation Indv").Activate
Range("A2").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Lastrow = Cells(Rows.Count, "A").End(xlUp).Row
Worksheets("fcst ps").Activate
Range("Fcst_PS[Zone & Fam]").Copy
Worksheets("Calculation Indv").Activate
Range("A" & Lastrow + 1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Lastrow = Cells(Rows.Count, "A").End(xlUp).Row
Worksheets("sales fg").Activate
Range("Sales_FG[Zone & Fam]").Copy
Worksheets("Calculation Indv").Activate
Range("A" & Lastrow + 1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Lastrow = Cells(Rows.Count, "A").End(xlUp).Row
Worksheets("sales ps").Activate
Range("Sales_PS[Zone & Fam]").Copy
Worksheets("Calculation Indv").Activate
Range("A" & Lastrow + 1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Lastrow = Cells(Rows.Count, "A").End(xlUp).Row
Application.CutCopyMode = False
Range("A:A").RemoveDuplicates Columns:=1, Header:=xlNo
Range("A1").Select
Worksheets("Calculation Indv").Range("A1").Value = "Zone & Fam"
Worksheets("Calculation Indv").Range("A1").Font.Bold = True
Application.ScreenUpdating = True
MsgBox ("Done!")
End Sub
In vba this would look something like the following (Totally not tested, written outside of VBE, probably riddled with mistakes, definitely will need tweaking to fit your sheet names and columns where your data lives):
Dim wsName as String
Dim lastRow as Long
Dim writeRow as Long
'set the row on which we are going to start writing data to "Sheet 5"
writeRow = 1
'Loop though your sheets to copy from
For Each wsName In Array("Sheet 1", "Sheet 2", "Sheet 3", "Sheet 4")
'determine the last used row in the worksheet we are copying from
lastRow = Sheets(wsName).Range("A1").End(xlDown).Row
'grab the data
Sheets(wsName).Range("A1:A" & lastRow).Copy Destination:=Sheets("Sheet 5").Range("A" & writeRow)
'increment the writeRow
writeRow = writeRow + lastRow
Next wsName
'Now that all the data is copied, dedup it
Sheets("Sheet 5").Range("A1:A" & writeRow).RemoveDuplicates Columns:=Array(1), Header:=xlNo
Sub GetUniqueZoneFam()
Application.ScreenUpdating = False
Dim Lastrow As Long
Worksheets("Calculation Indv").Range("A:A").ClearContents
Worksheets("fcst fg").Activate
Range("Fcst_Fg[Zone & Fam]").Copy
Worksheets("Calculation Indv").Activate
Range("A2").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Lastrow = Cells(Rows.Count, "A").End(xlUp).Row
Worksheets("fcst ps").Activate
Range("Fcst_PS[Zone & Fam]").Copy
Worksheets("Calculation Indv").Activate
Range("A" & Lastrow + 1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Lastrow = Cells(Rows.Count, "A").End(xlUp).Row
Worksheets("sales fg").Activate
Range("Sales_FG[Zone & Fam]").Copy
Worksheets("Calculation Indv").Activate
Range("A" & Lastrow + 1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Lastrow = Cells(Rows.Count, "A").End(xlUp).Row
Worksheets("sales ps").Activate
Range("Sales_PS[Zone & Fam]").Copy
Worksheets("Calculation Indv").Activate
Range("A" & Lastrow + 1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Lastrow = Cells(Rows.Count, "A").End(xlUp).Row
Application.CutCopyMode = False
Range("A:A").RemoveDuplicates Columns:=1, Header:=xlNo
Range("A1").Select
Worksheets("Calculation Indv").Range("A1").Value = "Zone & Fam"
Worksheets("Calculation Indv").Range("A1").Font.Bold = True
Application.ScreenUpdating = True
MsgBox ("Done!")
End Sub
This is what I have:
I am trying to get excel to copy only the cells that i have selected and pasted on the next blank line in another spreadsheet.
But in the code below, it fixed the range of cell being copied. How should i change my code so that it can be a dynamic range?
Sub CopyPaste()
Range("A6:E6").Select
Selection.Copy
Sheets("Sheet2").Select
lMaxRows = Cells(Rows.Count, "A").End(xlUp).Row
Range("A" & lMaxRows + 1).Select
Selection.PasteSpecial Paste:=xlValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=False
lMaxRows = Cells(Rows.Count, "A").End(xlUp).Row
Range("A" & lMaxRows + 1).Select
End Sub
Remove the statement
Range("A6:E6").Select
This statement selects the fixed range.
Try this
Sub CopyPaste()
Dim sht As Worksheet
Dim rngTarget As Range
Dim lMaxRows As Long
Selection.Copy
Set sht = Sheets("Sheet2")
lMaxRows = sht.Cells(Rows.Count, "A").End(xlUp).Row
Set rngTarget = sht.Range("A" & lMaxRows + 1)
rngTarget.PasteSpecial Paste:=xlValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
lMaxRows = sht.Cells(Rows.Count, "A").End(xlUp).Row
sht.Activate
sht.Range("A" & lMaxRows + 1).Select
End Sub
I have rewritten the code to specify exactly which cells and ranges are used. If not, it will apply selections on the sheet that is open (active) at that moment.
In my experience, using .Select is error-prone so I try to avoid it as much as possible.
I have the following Do with a nested If Not statement:
Do
Set i = SrchRng.Find("#609532", LookIn:=xlValues)
If Not i Is Nothing Then i.EntireRow.Copy
BBsheet.Activate
nextRow = Cells(Rows.Count, 1).End(xlUp).Row + 1
Cells(nextRow, 1).Select
Selection.PasteSpecial Paste:=xlValues, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
srcBook.Activate
i.EntireRow.Delete
Loop While Not i Is Nothing
This functions properly but it is failing to exit the loop when it should. When I step through it, it grabs the If Not i and skips over the copy command, but still steps through the lines below and fails on the Selection.PasteSpecial. I can not seem to get it to skip over those and move on to the next Do. The following works, but I need to copy before the delete:
Do
Set i = SrchRng.Find("#609532", LookIn:=xlValues)
If Not i Is Nothing Then i.EntireRow.Delete
Loop While Not i Is Nothing
How do I get the loop to register that "#609532" no longer exists and move on to the next loop?
You need to use If .. Then .. End If statement instead If ... Then ..:
Do
Set i = SrchRng.Find("#609532", LookIn:=xlValues)
If Not i Is Nothing Then
i.EntireRow.Copy
BBsheet.Activate
nextRow = Cells(Rows.Count, 1).End(xlUp).Row + 1
Cells(nextRow, 1).Select
Selection.PasteSpecial Paste:=xlValues, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
srcBook.Activate
i.EntireRow.Delete
End If
Loop While Not i Is Nothing
and it's better to avoid Select and Activate statements:
Do
Set i = SrchRng.Find("#609532", LookIn:=xlValues)
If Not i Is Nothing Then
i.EntireRow.Copy
With BBsheet
nextRow = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
.Cells(nextRow, 1).PasteSpecial Paste:=xlValues
End With
i.EntireRow.Delete
End If
Loop While Not i Is Nothing