Cut specified number of rows in selected range VBA - excel

I have problem,
I have e.g 180 rows in sheet, I want to choose randomly e.g 18 rows in range from A2 to the end of sheet except first because there will be title of columns, and paste it to new sheet,

The following will achieve what you are wanting, it will generate 18 random numbers between 2 and your last row with data, in your case row 180 and then copy that row into the next free row in Sheet2:
Sub foo()
Dim wsOriginal As Worksheet: Set wsOriginal = ThisWorkbook.Worksheets("Sheet1")
Dim wsDestination As Worksheet: Set wsDestination = ThisWorkbook.Worksheets("Sheet2")
'declare and set the worksheets you are working with, amend as required
Dim i As Long, LastRowOrig As Long, LastRowDest As Long
LastRowOrig = wsOriginal.Cells(wsOriginal.Rows.Count, "A").End(xlUp).Row
'get the last row with data on Column A on your Sheet with data
For i = 1 To 18 'loop 18 times
RandNumber = Int((LastRowOrig - 2 + 1) * Rnd + 2)
'generate a random number between 2 and 180 (Last Row)
LastRowDest = wsDestination.Cells(wsDestination.Rows.Count, "A").End(xlUp).Row + 1
'get the last row with data on Destination sheet and offset by one (i.e. next free row)
wsOriginal.Rows(RandNumber).Copy 'copy the row
wsDestination.Rows(LastRowDest).PasteSpecial xlPasteAll 'paste the row
Next i
End Sub
UPDATE:
To reflect your comment and add a new workbook with the random rows in it, use the following code:
Sub foo()
Dim wsOriginal As Worksheet: Set wsOriginal = ThisWorkbook.Worksheets("Sheet1")
Dim wsDestination As Worksheet
Dim i As Long, LastRowOrig As Long, LastRowDest As Long
Set NewWorkbook = Workbooks.Add 'create a new workbook
With NewWorkbook
.Title = "Random Rows" 'You can modify this value.
.SaveAs Filename:="C:\Users\doneby\Desktop\RandomGeneratedRows.xlsx"
'amend the line above to the path you and name of the file you want to create
End With
Set wsDestination = NewWorkbook.Worksheets("Sheet1") 'specify the Sheet of the new workbook
'declare and set the worksheets you are working with, amend as required
LastRowOrig = wsOriginal.Cells(wsOriginal.Rows.Count, "A").End(xlUp).Row
'get the last row with data on Column A on your Sheet with data
For i = 1 To 18 'loop 18 times
RandNumber = Int((LastRowOrig - 2 + 1) * Rnd + 2)
'generate a random number between 2 and 180 (Last Row)
LastRowDest = wsDestination.Cells(wsDestination.Rows.Count, "A").End(xlUp).Row + 1
'get the last row with data on Destination sheet and offset by one (i.e. next free row)
wsOriginal.Rows(RandNumber).Copy 'copy the row
wsDestination.Rows(LastRowDest).PasteSpecial xlPasteAll 'paste the row
Next i
NewWorkbook.Close SaveChanges:=True
'close and save the new workbook
End Sub

Related

VBA code that uses checkbox to copy and paste entire row with data to a new sheet

I have a workbook that contains several sheets with different types of inventory and one summary sheet.
I am trying to use checkboxes, that if checked as "True", will copy that row of data and paste into the summary sheet starting on a specific row. Each inventory sheet has several rows of differing data and I'd like users to be able to check multiple boxes they need on each sheet and this data to be copied to the summary sheet.
I found this code below that is working for the most part except it skips over some lines of data that are marked as "true". It also adds an unnecessary extra row between the lines once it copies the data over to the new sheet. What can I change so that all of the data marked "true" can be copied over and eliminate the extra rows?
Code I found is from this video: https://www.youtube.com/watch?v=TJoRUwrEe0g
Sub CopyRowBasedOnCellValue()
Dim xRg As Range
Dim xCell As Range
Dim A As Long
Dim B As Long
Dim C As Long
A = Worksheets("Exterior Items").UsedRange.Rows.Count
B = Worksheets("Customer Sheet").UsedRange.Rows.Count
If B = 1 Then
If Application.WorksheetFunction.CountA(Worksheets("Customer Sheet").UsedRange) = 0 Then B = 0
End If
Set xRg = Worksheets("Exterior Items").Range("B1:B" & A)
On Error Resume Next
Application.ScreenUpdating = False
For B = 1 To xRg.Count
If CStr(xRg(B).Value) = "True" Then
xRg(B).EntireRow.Copy Destination:=Worksheets("Customer Sheet").Range("A" & B + 9)
B = B + 1
End If
Next
Application.ScreenUpdating = True
End Sub
Try this:
Sub Copy_table_where_B_is_TRUE_row_by_row()
'declarations
Dim shtSource As Worksheet
Dim shtDestination As Worksheet
'reference source and destination sheets
Set shtSource = Worksheets("Exterior Items")
Set shtDestination = Worksheets("Customer Sheet")
'find limits of tables present on source and destination sheets
LastRowSource = shtSource.Cells(shtSource.Rows.Count, "A").End(xlUp).Row
LastRowDestination = shtDestination.Cells(shtDestination.Rows.Count, "A").End(xlUp).Row
'set output row index
OutputRow = LastRowDestination + 1
'using the source table..
For Each rw In shtSource.Range("1:" & LastRowSource).Rows
'if 2nd cell in row is TRUE
If rw.Cells(2).Value = "True" Then
'copy to destination sheet
rw.Copy shtDestination.Cells(OutputRow, 1)
'increment output row index
OutputRow = OutputRow + 1
End If
Next
End Sub
An entirely different method, that doesn't require any loops or counters would be to use a filter:
Sub Copy_filtered_table_where_B_is_TRUE()
'declarations
Dim shtSource As Worksheet
Dim shtDestination As Worksheet
'reference source and destination sheets
Set shtSource = Worksheets("Exterior Items")
Set shtDestination = Worksheets("Customer Sheet")
'find limits of tables present on source and destination sheets
'(these can be manually set if source table is fixed and destination location is fixed)
LastRowSource = shtSource.Cells(shtSource.Rows.Count, "A").End(xlUp).Row
LastRowDestination = shtDestination.Cells(shtDestination.Rows.Count, "A").End(xlUp).Row
'using the source table..
With shtSource.Range("1:" & LastRowSource)
'apply a filter
.AutoFilter
'set filter to column 2 = True
.AutoFilter Field:=2, Criteria1:="True"
'copy cells visible after application of filter, to next available row on destination sheet
.SpecialCells(xlCellTypeVisible).Copy shtDestination.Cells(LastRowDestination + 1, 1)
'remove filter
shtSource.AutoFilterMode = False
End With
End Sub

VBA Copy whole row to different sheet based on a cell value, to next available row

I'm a beginner using VBA, I'm trying to copy the whole row of source data 'Search' (see image), into a secondary tab called 'order' if there is any data in column M of the source data (will be numeric - which is why I've tried >0). Both sheets are in the same workbook.
The trick is, I want to paste it onto the next available row in the order tab - without copying over any previously copied rows.
This is my code so far but it isn't copying over the data. Any help would be much appreciated.
Sub CopySomeCells()
Dim SourceSheet As Worksheet
Dim DestinationSheet As Worksheet
Dim SourceRow As Long
Dim DestinationRow As Long
Set SourceSheet = ActiveWorkbook.Sheets("Search")
Set DestinationSheet = ActiveWorkbook.Sheets("Order")
DestinationRow = 2
For SourceRow = 2 To SourceSheet.UsedRange.Rows.Count
If SourceSheet.Range("M" & SourceRow).Value > 0 Then
SourceSheet.Range(SourceSheet.Cells(SourceRow, 1), SourceSheet.Cells(SourceRow, 29)).Copy _
DestinationSheet.Cells(DestinationRow, 2)
DestinationRow = DestinationRow + 1
End If
Next SourceRow
Application.CutCopyMode = False
Set SourceSheet = Nothing
Set DestinationSheet = Nothing
End Sub

How to copy specific ranges into a new worksheet in VBA?

I'm trying to create a macro that will compile specific columns from all worksheets in a workbook into a single new worksheet.
What I have so far creates the new sheet, and returns the correct headers for each column, but copies across all columns from the existing sheets rather than just the columns I have specified.
As can be seen with the column headings, I would like to only copy the values in columns A:I, K:M, R and W:Y from sheets 2 onwards, into columns B:O in the "MASTER" worksheet.
Does anyone have any suggestions as to how I can get this working?
Sub Combine2()
Dim J As Integer, wsNew As Worksheet
Dim rngCopy As Range, rngPaste As Range
Dim Location As String
On Error Resume Next
Set wsNew = Sheets("MASTER")
On Error GoTo 0
'if sheet does not already exist, create it
If wsNew Is Nothing Then
Set wsNew = Worksheets.Add(Before:=Sheets(1)) ' add a sheet in first place
wsNew.Name = "MASTER"
End If
'copy headings and paste to new sheet starting in B1
With Sheets(2)
.Range("A1:I1").Copy wsNew.Range("B1")
.Range("R1").Copy wsNew.Range("K1")
.Range("K1:M1").Copy wsNew.Range("L1")
.Range("W1:Y1").Copy wsNew.Range("O1")
End With
' work through sheets
For J = 2 To Sheets.Count ' from sheet 2 to last sheet
'save sheet name/location to string
Location = Sheets(J).Name
'set range to be copied
With Sheets(J).Range("A1").CurrentRegion
Set rngCopy = .Offset(1, 0).Resize(.Rows.Count - 1)
End With
'set range to paste to, beginning with column B
Set rngPaste = wsNew.Cells(Rows.Count, 2).End(xlUp).Offset(1, 0)
'copy range and paste to column *B* of combined sheet
rngCopy.Copy rngPaste
'enter the location name in column A for all copied entries
Range(rngPaste, rngPaste.End(xlDown)).Offset(0, -1) = Location
Next J
With Sheets(1)
Range("A1").Value = "Extract Date"
Range("A1").Font.Bold = True
Columns("A:T").AutoFit
End With
' wsNew.Visible = xlSheetHidden
End Sub
Copy/paste each range in turn in the same way as you have for the headings. (untested)
Dim ar(4), k as Integer
ar(1) = array("A1:I1","B")
ar(2) = array("R1","K")
ar(3) = array("K1:M1","L")
ar(4) = array("W1:Y1","O")
'copy headings and paste to new sheet
With Sheets(2)
For k = 1 to Ubound(ar)
.Range(ar(k)(0)).Copy wsNew.Range(ar(k)(1) & "1")
Next
End With
' work through sheets
Dim lr As Long
For J = 2 To Sheets.Count ' from sheet 2 to last sheet
'save sheet name/location to string
Location = Sheets(J).Name
'set range to be copied
With Sheets(J)
lr = .Cells(Rows.Count, 1).End(xlUp).Row
For k = 1 to Ubound(ar)
Set rngCopy = .Range(ar(k)(0)).Offset(1).Resize(lr-1)
'set range to paste to, beginning with column B
Set rngPaste = wsNew.Cells(Rows.Count, ar(k)(1)).End(xlUp).Offset(1, 0)
'copy range and paste to combined sheet
rngCopy.Copy rngPaste
If k = 1 Then
'enter the location name in column A for all copied entries
Range(rngPaste, rngPaste.End(xlDown)).Offset(0, -1) = Location
End If
Next
End With
Next J
Note this block is missing a dot on the ranges to use the With
With Sheets(1)
Range("A1").Value = "Extract Date"
Range("A1").Font.Bold = True
Columns("A:T").AutoFit
End With

Cut rows to new sheet based on values in column

I have this list of products, and i want to:
Create new sheets based on the values on column C, if there's already a sheet with the same name as the cell value don't create a new sheet. (like "Abstract" in my example that already been created for row 2 and doesn't need to created again for row 3)
Cut the entire row to the matching sheet.
Make sure the first row is copied to all sheets.
This is a before picture
After Pic #1: new sheets created, nothing left on first sheet except the 1st row
After Pic #2: the sheet contains 2 products because there were 2 "Abstract" in column C
After Pic #3: the sheet contain 1 product because there was 1 "Plain" in column C
After Pic #4: the sheet contain 1 product because there was 1 "Shiny" in column C
This will get the job done.
I Named the first sheet to "Worksheet".
The code is dynamic, so you need to input 2 values by yourself:
Which range/names that should create the new worksheets:
Set myrange = ThisWorkbook.Sheets("Worksheet").Range("C2:C5") 'Set range that should create the new worksheet list
and how many columns you want to copy to the new sheets (it makes it more dynamic than take the whole row)
lastcol = Cells(1, "C").Column 'Set how many column that should be copied to new worksheet
VBA Code:
Sub AddNewSheetFromRange2()
Dim c As Range
Dim ws As Worksheet
Dim myrange As Range
Dim lastcol As Integer
Dim lrow As Integer
Dim lrow_newsheet As Integer
Dim i As Integer
Set myrange = ThisWorkbook.Sheets("Worksheet").Range("C2:C5") 'Set range that should create the new worksheet list
lastcol = Cells(1, "C").Column 'Set how many column that should be copied to new worksheet
lrow = Cells(Rows.Count, 3).End(xlUp).Row 'find last row for range that should create the new worksheet list
i = 1 'Set first index loop to 1
For Each c In myrange.Cells
i = i + 1 'Create index for each loop, used to know which row that should be copied
'Debug.Print c 'Print which Sheet Name that will be examine
Set ws = Nothing
On Error Resume Next
Set ws = Worksheets(c.Value)
On Error GoTo 0
If ws Is Nothing Then
With ThisWorkbook
Set ws = .Sheets.Add(After:=.Sheets(.Sheets.Count)) 'Add new sheet after (not before)
ws.Name = c.Value 'Rename the new sheet
End With
Dim WorksheetSheet As Worksheet 'Declare variable for Main worksheet
Set WorksheetSheet = ActiveWorkbook.Worksheets("Worksheet") 'Name the Main sheet
Dim NewSheet As Worksheet 'Declare variable for new worksheet
Set NewSheet = ActiveWorkbook.Worksheets(ws.Name) 'Make all new worksheets dynamic by taking name from range
'Copy Headers from Main sheet to New Worksheet
Worksheets("Worksheet").Activate
ThisWorkbook.Worksheets("Worksheet").Range(Cells(1, 1), Cells(1, 3)).Copy
Worksheets(ws.Name).Activate
ThisWorkbook.Worksheets(ws.Name).Range(Cells(1, 1), Cells(1, 3)).PasteSpecial
'Copy row from Main sheet to New Worksheet
Worksheets("Worksheet").Activate
ThisWorkbook.Worksheets("Worksheet").Range(Cells(i, 1), Cells(i, lastcol)).Copy
Worksheets(ws.Name).Activate
lrow_newsheet = Cells(Rows.Count, 3).End(xlUp).Row + 1
ThisWorkbook.Worksheets(ws.Name).Range(Cells(lrow_newsheet, 1), Cells(lrow_newsheet, lastcol)).PasteSpecial
'Clear row in Main sheet
Worksheets("Worksheet").Activate
ThisWorkbook.Worksheets("Worksheet").Range(Cells(i, 1), Cells(i, lastcol)).Clear
Else
'If worksheet already exists, then
'Copy row from Main sheet to existing worksheet with exactly the same name
Worksheets("Worksheet").Activate
ThisWorkbook.Worksheets("Worksheet").Range(Cells(i, 1), Cells(i, lastcol)).Copy
Worksheets(ws.Name).Activate
lrow_newsheet = Cells(Rows.Count, 3).End(xlUp).Row + 1
ThisWorkbook.Worksheets(ws.Name).Range(Cells(lrow_newsheet, 1), Cells(lrow_newsheet, lastcol)).PasteSpecial
'Clear row in Main sheet
Worksheets("Worksheet").Activate
ThisWorkbook.Worksheets("Worksheet").Range(Cells(i, 1), Cells(i, lastcol)).Clear
End If
Next c
End Sub
Visualizing the code in excel you will have to start with this:
and the final output will be this (the four rows into individual worksheets, if the name already exists, it will add to the already existing worksheet)

Deleting Entire Rows from Source After Pasting Into New Sheet

Everything in this code works well until the piece where I need to delete the rows in column "I" of the source tab ("Status Report"). I have to run this macro several times to clear out all of the rows I want to delete because it appears to only delete one row at a time.
How can I get this macro to delete all of the rows I want and only run this code once?
Sub CopyYes()
Dim c As Range
Dim j As Integer
Dim Source As Worksheet
Dim Target As Worksheet
' Change worksheet designations as needed
Set Source = ActiveWorkbook.Worksheets("Status Report")
Set Target = ActiveWorkbook.Worksheets("Sheet1")
j = 1 ' Start copying to row 1 in target sheet
For Each c In Source.Range("I1:I1000") ' Do 1000 rows
If c = 1 Then
Source.Rows(c.Row).Copy Target.Rows(j)
j = j + 1
Source.Rows(c.Row).EntireRow.Delete
End If
Next c
End Sub
Thanks for your help!
How is this? It, as suggested by #yass, starts at the last row and works backwards.
Sub CopyYes()
Dim c As Range
Dim j As Integer
Dim Source As Worksheet
Dim Target As Worksheet
Dim lastRow As Long
' Change worksheet designations as needed
Set Source = ActiveWorkbook.Worksheets("Status Report")
Set Target = ActiveWorkbook.Worksheets("Sheet1")
blankRow = Target.Cells(Target.Rows.Count, 1).End(xlUp).Row ' Start copying to row 1 in target sheet
lastRow = 1000
' lastRow = Source.Cells(Source.Rows.Count, 9).End(xlUp).Row ' Uncomment this line if you want to do ALL rows in column I
With Source
For i = lastRow To 1 Step -1
If .Cells(i, 9).Value = 1 Then
If blankRow = 1 Then
.Rows(i).Copy Target.Rows(blankRow)
Else
.Rows(i).Copy Target.Rows(blankRow + 1)
End If
blankRow = Target.Cells(Target.Rows.Count, 1).End(xlUp).Row
.Rows(i).EntireRow.Delete
Next i
End With
End Sub
Note: The main difference is the For loop. AFAIK you can't do a For each x in Range loop backwards.

Resources