VBA: how to avoid copying table headers from multiple sheets? - vba

Trying to combine multiple excel sheets is there a way to modify the below so that it does not copy table headers from the other sheets into a sheet called "Combined"?
Sub Combine()
'UpdatebyExtendoffice
Dim J As Integer
On Error Resume Next
Sheets(1).Select
Worksheets.Add
Sheets(1).Name = "Combined"
Sheets(2).Activate
Range("A1").EntireRow.Select
Selection.Copy Destination:=Sheets(1).Range("A1")
For J = 2 To Sheets.Count
Sheets(J).Activate
Range("A1").Select
Selection.CurrentRegion.Select
Selection.Offset(1, 0).Resize(Selection.Rows.Count - 1).Select
Selection.Copy Destination:=Sheets(1).Range("A65536").End(xlUp)(2)
Next
End Sub

Quick rewrite and introducing some variables to hold the new sheet and copy range which should help for debugging.
This also incorporates the "skip two header rows" requirement:
Sub Combine()
Dim J As Integer
'Set the newly added sheet to a variable so we can reference.
Dim CombineSheet as Worksheet
Set CombineSheet = Worksheets.Add
CombineSheet.Name = "Combined"
'Assume you are copying the header here. It's a
' little risky hoping that Sheets(2) is going
' to be the one you want.
'Furthermore, getting rid of select/activate
' stuff. Instead directly say which sheet and
' range you want to copy and its destination.
Sheets(2).Range("A1").EntireRow.Copy Destination:=CombineSheet.Range("A1")
'Introducing a new variable to hold the range that will be copied
Dim copyRange as Range
For J = 2 To Sheets.Count
'Cutting out the activates and selects here
Set copyRange = Sheets(J).Range("A1").CurrentRegion
'Offset it and resize skipping 2 header rows and resizing the whole
' range to be 2 rows smaller (the 2 rows we just skipped)
copyRange = copyRange.Offset(2).Resize(copyRange.Rows.Count - 2)
'Copy/Paste
copyRange.Copy Destination:=CombineSheet.Range("A65536").End(xlUp)
Next
End Sub
The biggest change here, besides the removal of the .Select and .Activate is just offsetting by 2 rows and then resizing that range by -2 rows to accommodate that offset.

Try the next updated code, please:
Sub CombineSheets()
Dim J As Long, sh As Worksheet
Worksheets.Add Before:=Sheets(1)
Sheets(1).Name = "Combined"
Sheets(2).Range("A1").EntireRow.Copy Destination:=Sheets(1).Range("A1")
For Each sh In ActiveWorkbook.Sheets
If sh.Name <> Sheets(1).Name Then
sh.Range("A1").CurrentRegion.Offset(2).Resize(sh.Range("A" & sh.rows.Count).End(xlUp).row - 1).Copy _
Destination:=Sheets(1).Range("A" & sh.rows.Count).End(xlUp)(2)
End If
Next
End Sub
Selecting, activating only consume Excel resources and make the code slower...

Related

Applying an Excel formula with macro

Thank you for taking the time to read my query.
I have a problem with applying a formula to one of my Excel sheets. I'm currently using a macro to combine few sheets into one. It's quite rough but it does the job.
Sub Combine()
Application.DisplayAlerts = False
Sheets("Combined").Delete
Application.DisplayAlerts = True
Dim J As Integer
On Error Resume Next
Sheets(1).Select
Worksheets.Add
Sheets(1).Name = "Combined"
Sheets(2).Activate
Range("A1").EntireRow.Select
Selection.Copy Destination:=Sheets(1).Range("A1")
For J = 3 To 6
Sheets(J).Activate
Range("A1").Select
Selection.CurrentRegion.Select
Selection.Offset(1, 0).Resize(Selection.Rows.Count - 1).Select
Selection.Copy Destination:=Sheets(1).Range("A65536").End(xlUp)(2)
Sheets("Combined").Visible = False
Next
End Sub
This is giving me a specific page from which I need to draw the info. I will tie it to button for easy access in the future. I'm currently struggling with applying a formula that draws info from the aforementioned 'Combined' sheet. The formula that I'm using is lost upon deleting the sheet in the beginning of the code.
=IF(ISNUMBER(SEARCH("_",Combined!A2)),LEFT(Combined!A2,(FIND("_",Combined!A2,1)-1)))
So I tried applying it to a macro. But as you can see there is an underscore in there, that VBA has a very specific interpretation of it. Is there a workaround?
Sub Place_formula()
'trying to place the formulae once again
Range("F2").Formula =
"=IF(ISNUMBER(SEARCH("_",Combined!A2)),LEFT(Combined!A2,
(FIND("_",Combined!A2,1)-1)))"
End Sub
If I manage to do this I will easily find a way to replicate it to where it is needed.
You must double up the quotes in VBA
Range("F2").Formula = "=IF(ISNUMBER(SEARCH(""_"",Combined!A2)),LEFT(Combined!A2,(FIND(""_"",Combined!A2,1)-1)))"
Also suggest amending your main code to avoid the selecting, and using some worksheet variables to make it easier to refer to relevant sheets.
Sub Combine()
Application.DisplayAlerts = False
workSheets("Combined").Delete
Application.DisplayAlerts = True
Dim ws1 As Worksheet, ws2 As Worksheet
Dim J As Long
Set ws1 = Sheets(1)
Set ws2 = Worksheets.Add(before:=ws1)
ws2.Name = "Combined"
ws1.Range("A1").EntireRow.Copy Destination:=ws2.Range("A1")
For J = 3 To 6
With workSheets(J).Range("A1").CurrentRegion
.Offset(1, 0).Resize(.Rows.Count - 1).Copy Destination:=ws2.Range("A" & Rows.Count).End(xlUp)(2)
End With
Next
ws2.visible = False
End Sub

Copying the matched row in another sheet

I have two Sheets, sheet1 and sheet 2.
I am looking into column T of sheet1 and pasting the complete row if T contains 1 in sheet 2.
The code, works good, but it paste the result in sheet2 in the same row in sheet1.
This results in blanks, between the rows. Can anyone suggest, what i should Change with my code, so that i get them in sequence without any blank rows.
Also, how can I copy the Header in row 1 from sheet 1 to sheet2?
Sub Test()
For Each Cell In Sheets(1).Range("T:T")
If Cell.Value = "1" Then
matchRow = Cell.Row
Rows(matchRow & ":" & matchRow).Select
Selection.Copy
Sheets(2).Select
ActiveSheet.Rows(matchRow).Select
ActiveSheet.Paste
Sheets(1).Select
End If
Next
End Sub
There's no need to use Select and Selection to copy paste, it will only slows down your code's run-time.
Option Explicit
Sub Test()
Dim Cell As Range
Dim NextRow as Long
Application.ScreenUpdating = False
For Each Cell In Sheets(1).Range("T1:T" & Sheets(1).Cells(Sheets(1).Rows.Count, "T").End(xlUp).Row)
If Cell.Value = "1" Then
NextRow = Sheets(2).Cells(Sheets(2).Rows.Count, "T").End(xlUp).Row
Rows(Cell.Row).Copy Destination:=Sheets(2).Range("A" & NextRow + 1)
End If
Next
Application.ScreenUpdating = True
End Sub
Not For Points
Apologies, but I couldn't stop myself from posting an answer. It pains me when I see someone wanting to use an inferior way of doing something :(
I am not in favor of looping. It is very slow as compared to Autofilter.
If you STILL want to use looping then you can make it faster by not copying the rows in the loop but in the end in ONE GO...
Also if you do not like living dangerously then always fully qualify your object else you may end up copying the wrong row.
Option Explicit
Sub Sample()
Dim wsI As Worksheet, wsO As Worksheet
Dim lRow As Long, i As Long, r As Long
Dim copyRng As Range
Set wsI = Sheet1: Set wsO = Sheet2
wsO.Cells.Clear
'~~> first available row in sheet2
r = 2
With wsI
lRow = .Range("T" & .Rows.Count).End(xlUp).Row
'~~> Copy Headers
.Rows(1).Copy wsO.Rows(1)
For i = 1 To lRow
If .Range("T" & i).Value = 1 Then
If copyRng Is Nothing Then
Set copyRng = .Rows(i)
Else
Set copyRng = Union(copyRng, .Rows(i))
End If
End If
Next i
End With
If Not copyRng Is Nothing Then copyRng.Copy wsO.Rows(r)
End Sub
Screenshot

Excel Macro working different worksheet

Sub CopyPaste()
'
' CopyPaste Macro
'
' Keyboard Shortcut: Ctrl+Shift+P
'
Range("A2:C5").Select
Selection.Copy
Sheets("A").Select
Range("A2").Select
ActiveSheet.Paste
Sheets("Sheet1").Select
Range("A6:C11").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("B").Select
Range("A2").Select
ActiveSheet.Paste
Sheets("Sheet1").Select
Range("A12:C17").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("C").Select
Range("A2").Select
ActiveSheet.Paste
Sheets("Sheet1").Select
Range("A18:C21").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("D").Select
Range("A2").Select
ActiveSheet.Paste
End Sub
I have trying making a Macro to do a basic task but I can't seem to figure it out, can anyone help please! I'm trying to create a macro that will copy data from one worksheet and place into another worksheet based on specific letter.
For example all "A" item will paste automatically into new worksheet name "A". This I can do with no problem. But, when I want to use the same macro with another row with different no of column is where I have my problem.
I already use recorded macro and then if the row from copy worksheet have been reduced, it will paste wrongly in new worksheet.
Is there any way to solve it?
thanks in advance.
P/S--> the new worksheet will have header in it. so it would be nice if they can paste start from A2 row. Can refer image below for example.
See Example / and see comment on the code
Option Explicit
Public Sub Example()
'Declare your Variables
Dim Sht As Worksheet
Dim rng As Range
Dim List As Collection
Dim varValue As Variant
Dim i As Long
With ThisWorkbook
'Set your Sheet name
Set Sht = ActiveWorkbook.Sheets("Sheet1")
'set your auto-filter, A1
With Sht.Range("A1")
.AutoFilter
End With
'Set your agent Column range # (1) that you want to filter it
Set rng = Range(Sht.AutoFilter.Range.Columns(1).Address)
'Create a new Collection Object
Set List = New Collection
'Fill Collection with Unique Values
On Error Resume Next
For i = 2 To rng.Rows.Count
List.Add rng.Cells(i, 1), CStr(rng.Cells(i, 1))
Next i
'Start looping in through the collection Values
For Each varValue In List
'Filter the Autofilter to macth the current Value
rng.AutoFilter Field:=1, Criteria1:=varValue
'Copy the AutoFiltered Range to new Workbook
Sht.AutoFilter.Range.Copy
Worksheets.Add.Paste
ActiveSheet.Name = Left(varValue, 30)
Next ' Loop back
'Go back to main Sheet and removed filters
Sht.AutoFilter.ShowAllData
Sht.Activate
End With
End Sub
Make sure to have header on your data, see below

Copy filtered data to another sheet using VBA

I have two sheets. One has the complete data and the other is based on the filter applied on the first sheet.
Name of the data sheet : Data
Name of the filtered Sheet : Hoky
I am just taking a small portion of data for simplicity. MY objective is to copy the data from Data Sheet, based on the filter. I have a macro which somehow works but its hard-coded and is a recorded macro.
My problems are:
The number of rows is different everytime. (manual effort)
Columns are not in order.
Sub TESTTHIS()
'
' TESTTHIS Macro
'
'FILTER
Range("F2").Select
Selection.AutoFilter
ActiveSheet.Range("$B$2:$F$12").AutoFilter Field:=5, Criteria1:="hockey"
'Data Selection and Copy
Range("C3").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Sheets("Hockey").Select
Range("E3").Select
ActiveSheet.Paste
Sheets("Data").Select
Range("D3").Select
Range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Hockey").Select
Range("D3").Select
ActiveSheet.Paste
Sheets("Data").Select
Range("E3").Select
Range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Hockey").Select
Range("C3").Select
ActiveSheet.Paste
End Sub
Best way of doing it
Below code is to copy the visible data in DBExtract sheet, and paste it into duplicateRecords sheet, with only filtered values. Range selected by me is the maximum range that can be occupied by my data. You can change it as per your need.
Sub selectVisibleRange()
Dim DbExtract, DuplicateRecords As Worksheet
Set DbExtract = ThisWorkbook.Sheets("Export Worksheet")
Set DuplicateRecords = ThisWorkbook.Sheets("DuplicateRecords")
DbExtract.Range("A1:BF9999").SpecialCells(xlCellTypeVisible).Copy
DuplicateRecords.Cells(1, 1).PasteSpecial
End Sub
I suggest you do it a different way.
In the following code I set as a Range the column with the sports name F and loop through each cell of it, check if it is "hockey" and if yes I insert the values in the other sheet one by one, by using Offset.
I do not think it is very complicated and even if you are just learning VBA, you should probably be able to understand every step. Please let me know if you need some clarification
Sub TestThat()
'Declare the variables
Dim DataSh As Worksheet
Dim HokySh As Worksheet
Dim SportsRange As Range
Dim rCell As Range
Dim i As Long
'Set the variables
Set DataSh = ThisWorkbook.Sheets("Data")
Set HokySh = ThisWorkbook.Sheets("Hoky")
Set SportsRange = DataSh.Range(DataSh.Cells(3, 6), DataSh.Cells(Rows.Count, 6).End(xlUp))
'I went from the cell row3/column6 (or F3) and go down until the last non empty cell
i = 2
For Each rCell In SportsRange 'loop through each cell in the range
If rCell = "hockey" Then 'check if the cell is equal to "hockey"
i = i + 1 'Row number (+1 everytime I found another "hockey")
HokySh.Cells(i, 2) = i - 2 'S No.
HokySh.Cells(i, 3) = rCell.Offset(0, -1) 'School
HokySh.Cells(i, 4) = rCell.Offset(0, -2) 'Background
HokySh.Cells(i, 5) = rCell.Offset(0, -3) 'Age
End If
Next rCell
End Sub
When i need to copy data from filtered table i use range.SpecialCells(xlCellTypeVisible).copy. Where the range is range of all data (without a filter).
Example:
Sub copy()
'source worksheet
dim ws as Worksheet
set ws = Application.Worksheets("Data")' set you source worksheet here
dim data_end_row_number as Integer
data_end_row_number = ws.Range("B3").End(XlDown).Row.Number
'enable filter
ws.Range("B2:F2").AutoFilter Field:=2, Criteria1:="hockey", VisibleDropDown:=True
ws.Range("B3:F" & data_end_row_number).SpecialCells(xlCellTypeVisible).Copy
Application.Worksheets("Hoky").Range("B3").Paste
'You have to add headers to Hoky worksheet
end sub
it needs to be .Row.count not Row.Number?
That's what I used and it works fine
Sub TransfersToCleared()
Dim ws As Worksheet
Dim LastRow As Long
Set ws = Application.Worksheets("Export (2)") 'Data Source
LastRow = Range("A" & Rows.Count).End(xlUp).Row
ws.Range("A2:AB" & LastRow).SpecialCells(xlCellTypeVisible).Copy

VBA - Copy Variable Number of Rows from a Workbook to Another

Our office has recently updated to excel 2013 and a code which worked in the 2010 version is not working. I've searched on several threads here on SO and have yet to find a solution that works for this particular case.
The code identifies and copies a range of cells from an open workbook and logs them into a second workbook, one range of cells at a time. The reason it's set up to copy only 1 row at a time is because the number of rows to be copied varies from time to time. Since the change to 2013, the Selection.PasteSpecial functions have been triggering the debug prompt.
In practice, the worksheet is being used as a routing form. Once it's filled out, we run the code and save all the relevant information in a separate workbook. Since it's a routing form, the number of people on it varies, and we need a row for each person in order to track their 'status'.
The code:
Sub Submit()
'Transfer code
Dim i As Long, r As Range, coltoSearch As String
coltoSearch = "I"
'Change i = # to transfer rows of data. Needs to be the first row which copies over.
'This is to identify how many rows are to be copied over. If statement ends the for loop once an "empty" cell is reached
For i = 50 To Range(coltoSearch & Rows.Count).End(xlUp).Row
Set r = Range(coltoSearch & i)
If Len(r.Value) = 0 Then
Exit For
End If
'Copies the next row on the loop
Range(Cells(i, 1), Cells(i, 18)).Copy
'open the workbook where row will be copied to
Workbooks.Open FileName:= _
"Workbook2"
'definition for the first empty row in Workbook 2, or the row under the last occupied cell in the Log
erow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
'selects the first cell in the empty row
ActiveSheet.Cells(erow, 1).Select
' Pastes the copied row from Workbook 1 into Workbook 2. First line is highlighted when debugging
Selection.PasteSpecial Paste:=xlPasteValuesAndNumberFormats
ActiveWorkbook.Save
ActiveWorkbook.Close
Application.CutCopyMode = False
'moves to the next row
Next i
Any thoughts? I'm open to all options. Thanks for your time.
The Working alternative to select is
ActiveSheet.Cells(erow, 1).PasteSpecial Paste:=xlPasteValuesAndNumberFormats
but just for be sure that everything is going fine you have to set the range where i you want to paste everything
dim rngToFill as range
Set rngToFill = ActiveSheet.Cells(erow, 1)
maybe instead of using ActiveSheet you have to define that sheet after opening the wb with
dim wb as Workbook, ws as worksheet
set wb = Workbooks.Open FileName:="Workbook2"
set ws = wb.Sheets(nameofthesheet) 'or number of the sheet
then
set rngToFill = ws.Cells(erow, 1)
then you can paste in that range using .PasteSpecial method, but before doing that, try to be sure that there is no merged cell and that the worksheet we're you are going to paste values is not protected.
rngToFill.PasteSpecial xlPasteValuesAndNumberFormats
Your code:
dim wb as Workbook, ws as worksheet
set wb = Workbooks.Open(FileName:="Workbook2")
set ws = wb.Sheets(nameofthesheet) 'or number of the sheet
erow = ws.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
if erow = 0 then erow = 1
set rngToFill = ws.Cells(erow, 1)
rngToFill.PasteSpecial xlPasteValuesAndNumberFormats
The B plan is to use a for loop iterating throug the cell you want to copy... but it's painfull slowly!
Dim wb As Workbook, newWs As Worksheet, oldWs As Worksheet
Dim z As Integer
Set oldWs = ActiveSheet
Set wb = Workbooks.Open("Workbook2")
Set newWs = wb.Sheets(1)
erow = ws.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
If erow = 0 Then erow = 1
For z = 1 To 18
newWs.Cells(erow, z) = oldWs.Cells(i, z).Value
Next z
ActiveWorkbook.Save
ActiveWorkbook.Close
Application.CutCopyMode = False
'moves to the next row
Next i