copying specific columns from one Excel sheet to another - excel

I have a worksheet in Excel which needs only specific data copied to another worksheet.
The destination sheet does have more columns than are actually needed, so I had to create a macro which copies only the specified data from the source sheet to the destination sheet.
The thing is, that it does not copy any column and says that it is either an object or application problem.
Here's the code:
Option Explicit
Function GetHeadersDict() As Scripting.Dictionary
Dim result As Scripting.Dictionary
Set result = New Scripting.Dictionary
With result
.Add "ATA", False
.Add "PART NO", False
.Add "SERIAL NO", False
.Add "DESCRIPTION", False
.Add "POSITION", False
.Add "DUE DATE", False
.Add "TSN", False
.Add "CSN", False
.Add "REMARKS", False
End With
Set GetHeadersDict = result
End Function
Function FindHeaderRange(ByVal ws As Worksheet, ByVal header As String) As Range
Set FindHeaderRange = ws.Cells.Find(header, , , xlWhole)
End Function
Sub clearDataSheet2()
Sheets("Data").Range("A1").CurrentRegion.Offset(1).ClearContents
End Sub
Sub copyColumnData()
On Error GoTo ErrorMessage
Dim ws1 As Worksheet, ws2 As Worksheet
Set ws1 = ThisWorkbook.Sheets("Hoja2")
Set ws2 = ThisWorkbook.Sheets("Data")
clearDataSheet2
Dim numRowsToCopy As Long
numRowsToCopy = ws1.Cells(RowIndex:=Rows.Count, ColumnIndex:=1).End(xlUp).Row - 1
MsgBox "The number of rows to copy is " & numRowsToCopy
Dim destRowOffset As Long
destRowOffset = ws2.Cells(RowIndex:=Rows.Count, ColumnIndex:=1).End(xlUp).Row
MsgBox "The next Blank row is " & destRowOffset
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim dictKey As Variant
Dim header As String
Dim numColumnsToCopy As Long
Dim source As Range
Dim dest As Range
Dim headersDict As Scripting.Dictionary
Set headersDict = GetHeadersDict()
For Each dictKey In headersDict
header = dictKey
If headersDict.Item(header) = False Then
Set source = FindHeaderRange(ws1, header)
If Not (source Is Nothing) Then
Set dest = FindHeaderRange(ws2, header)
If Not (dest Is Nothing) Then
headersDict.Item(header) = True
For numColumnsToCopy = 1 To headersDict.Count
MsgBox numColumnsToCopy
If source.Offset(ColumnOffset:=numColumnsToCopy).Value = dest.Offset(ColumnOffset:=numColumnsToCopy).Value Then
headersDict.Item(source.Offset(ColumnOffset:=numColumnsToCopy).Value) = True
Else
Exit For
End If
Next numColumnsToCopy
source.Offset(RowOffset:=1).Resize(RowSIze:=numRowsToCopy, ColumnSize:=numColumnsToCopy).Copy _
dest.Offset(RowOffset:=destRowOffset)
End If
End If
End If
Next dictKey
Dim msg As String
For Each dictKey In headersDict
header = dictKey
If headersDict.Item(header) = False Then
msg = msg & vbNewLine & header
End If
Next dictKey
ExitSub:
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
If msg <> "" Then
MsgBox "The following headers were not copied: " & vbNewLine & msg
End If
Exit Sub
ErrorMessage:
MsgBox "An error has occured: " & Err.Description
Resume ExitSub
End Sub

I had the same issue of yours and I fixed by setting the right column index
Dim numRowsToCopy As Long
numRowsToCopy = ws1.Cells(RowIndex:=Rows.Count, ColumnIndex:=**1**).End(xlUp).Row - 1
MsgBox "The number of rows to copy is " & numRowsToCopy
Dim destRowOffset As Long
destRowOffset = ws2.Cells(RowIndex:=Rows.Count, ColumnIndex:=**1**).End(xlUp).Row
MsgBox "The next Blank row is " & destRowOffset

Related

Add multiple attachments to an e-mail from excel table - VBA

I have a VBA macro to send e-mails to different recipients, but now I want to add attachments. The problem is the attachments paths are in an excel table and it varies according to the customer. I.e. customer A has 3 lines in the table, each with a different attachment, cust B has 5 lines, and so on.
Anyone knows how to vlookup it and get all possible files paths? Here follows my current code without attachments:
Sub Controle_de_orçamentos()
response = MsgBox("Deseja enviar as cobranças?", vbYesNo)
If response = vbNo Then
MsgBox ("Então tchau")
Exit Sub
End If
Dim OutApp As Object
Dim OutMail As Object
Dim rng As Range
Dim Ash As Worksheet
Dim Cws As Worksheet
Dim Rcount As Long
Dim Rnum As Long
Dim FilterRange As Range
Dim FieldNum As Integer
Dim mailAddress As String
On Error GoTo cleanup
Set OutApp = CreateObject("Outlook.Application")
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
'Set filter sheet, you can also use Sheets("MySheet")
Set Ash = ActiveSheet
'Set filter range and filter column (Column with names)
Set FilterRange = Ash.Range("A1:H" & Ash.Rows.Count)
FieldNum = 1 'Filter column = A because the filter range start in A
'Add a worksheet for the unique list and copy the unique list in A1
Set Cws = Worksheets.Add
FilterRange.Columns(FieldNum).AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=Cws.Range("A1"), _
CriteriaRange:="", Unique:=True
'Count of the unique values + the header cell
Rcount = Application.WorksheetFunction.CountA(Cws.Columns(1))
'If there are unique values start the loop
If Rcount >= 2 Then
For Rnum = 2 To Rcount
'Filter the FilterRange on the FieldNum column
FilterRange.AutoFilter Field:=FieldNum, _
Criteria1:=Cws.Cells(Rnum, 1).Value
'Look for the mail address in the MailInfo worksheet
mailAddress = ""
On Error Resume Next
mailAddress = Application.WorksheetFunction. _
VLookup(Cws.Cells(Rnum, 1).Value, _
Worksheets("Mailinfo").Range("A1:B" & _
Worksheets("Mailinfo").Rows.Count), 2, False)
On Error GoTo 0
If mailAddress <> "" Then
With Ash.AutoFilter.Range
On Error Resume Next
Set rng = .SpecialCells(xlCellTypeVisible)
On Error GoTo 0
End With
Set OutMail = OutApp.CreateItem(0)
On Error Resume Next
With OutMail
.To = mailAddress
.Subject = "Orçamentos aguardando aprovação - Indi Empilhadeiras"
.HTMLBody = "Prezados(as), boa tarde!<br>" & _
"Poderiam, por gentileza, informar se os orçamentos abaixo estão aprovados?" & RangetoHTML(rng) & _
"<br>Obrigado!<br>" & _
"Denis Scalco<br>" & _
"(15) 98145-0856"
.Display 'Or use Send
.Send
End With
On Error GoTo 0
Set OutMail = Nothing
End If
'Close AutoFilter
Ash.AutoFilterMode = False
Next Rnum
End If
cleanup:
Set OutApp = Nothing
Application.DisplayAlerts = False
Cws.Delete
Application.DisplayAlerts = True
With Application
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
To filter the files for a specific customer you may want to use standard or advanced filtering:
https://support.microsoft.com/en-gb/office/filter-by-using-advanced-criteria-4c9222fe-8529-4cd7-a898-3f16abdff32b
read file names of attachments from range: see below code proposal
add attachments
How to add an attachment to an email using VBA in Excel
Option Explicit
Sub test()
Dim myA(20) As String
Dim myCt As Integer
Dim NrFiles As Integer
Call ReadAttachments(myA, Range("H1:H10"), False, NrFiles)
For myCt = 1 To NrFiles
Debug.Print myCt, myA(myCt)
Next myCt
End Sub
Sub ReadAttachments(ByRef myAttachments() As String, myRange As Range, _
hasHeader As Boolean, FileCt As Integer)
Dim myCell As Range
Dim iCt As Integer
For Each myCell In myRange
If iCt <> 0 Then
If myCell.Value <> "" Then
myAttachments(iCt) = myCell.Value
FileCt = FileCt + 1
End If
End If
iCt = iCt + 1
Next myCell
End Sub

Creating a new worksheet for each row, but duplicates should be in same worksheet

I would like to create a new worksheet for every customer in my excel file. The customer number is given in column c, but it is only the first 7 letters that shows the customer number. Therefore I would like if the code named each new worksheet it creates, after the customer number, so that it can check if a customer already has a worksheet, and if it does, the next row in the first worksheet that contains the same customer number should be put into that new worksheet, below what has already been copied into there.
Function SheetExists(SheetName As String, Optional InWorkbook As Workbook) As Boolean
If InWorkbook Is Nothing Then Set InWorkbook = ActiveWorkbook
On Error Resume Next
SheetExists = Not InWorkbook.Sheets(SheetName) Is Nothing
On Error GoTo 0
End Function
Sub RowToSheet()
Dim xRow As Long
Dim I As Long
Dim ws As Worksheet
Application.ScreenUpdating = False
ActiveSheet.Name = "Sheet 1"
With ActiveSheet
xRow = .Range("A" & Rows.Count).End(xlUp).Row
For I = 2 To xRow
If Not SheetExists(Left(Cells(I, 3), 7)) Then Worksheets.Add(, Sheets(Sheets.Count)).Name = Left(Cells(I, 3), 7)
.Rows(I).Copy Sheets(Left(Cells(I, 3), 7)).Cells(Sheets(Left(Cells(I, 3), 7)).Cells(Rows.Count, 1).End(xlUp).Row + 1, 1)
Sheets(1).Rows(1).Copy Destination:=Sheets(Left(Cells(I, 3), 7)).Rows(1)
Next I
End With
Test if the sheet exists before adding a new one. Here's a simple function for checking if a sheet with that name exists:
Function SheetExists(SheetName As String, Optional InWorkbook As Workbook) As Boolean
If InWorkbook Is Nothing Then Set InWorkbook = ActiveWorkbook
On Error Resume Next
SheetExists = Not InWorkbook.Sheets(SheetName) Is Nothing
On Error GoTo 0
End Function
You would add it to your code like:
Sub RowToSheet()
Dim xRow As Long
Dim I As Long
Dim ws As Worksheet
Application.ScreenUpdating = False
ActiveSheet.Name = "Sheet 1"
With ActiveSheet
xRow = .Range("A" & Rows.Count).End(xlUp).Row
For I = 2 To xRow
If Not SheetExists("Row " & I) Then Worksheets.Add(, Sheets(Sheets.Count)).Name = "Row " & I
.Rows(I).Copy Sheets("Row " & I).Range("A2")
Sheets(1).Rows(1).Copy Destination:=Sheets(I).Rows(1)
Next I
End With
End Sub
This way the sheet is only created if it did not already exist. The .Copy will overwrite the values on Range("A2") so you will want to change that to dynamically search for the next empty row like:
.Rows(I).Copy Sheets("Row " & I).Cells(Sheets("Row " & I).Cells(Rows.Count, 1).End(xlUp).Row + 1, 1)
And your line Sheets(1).Rows(1).Copy Destination:=Sheets(I).Rows(1) is just guessing that the new sheet will be in the same position as the loop index. I suggest correcting that to be:
Sheets(1).Rows(1).Copy Destination:=Sheets("Row " & I).Rows(1)
Use a dictionary to hold the unique customer numbers. Loop through them applying a filter to column C and copy the filtered records to a new sheet/workbook.
Option Explicit
Sub RowToSheet()
Dim wb As Workbook
Dim ws As Worksheet, wsNew As Worksheet
Dim LastRow As Long, i As Long, n As Integer
Dim dict As Object, key, rng As Range
Set dict = CreateObject("Scripting.Dictionary")
Set wb = ThisWorkbook
Set ws = wb.Sheets("Sheet 1")
LastRow = ws.Cells(Rows.Count, "C").End(xlUp).Row
Set rng = ws.Range("A1:P" & LastRow)
' build list of unique values from col C
For i = 2 To LastRow
key = Trim(Left(ws.Cells(i, "C"), 7))
If Len(key) > 0 Then dict(key) = 1
Next
' delete any existing sheets
Application.DisplayAlerts = False
For Each wsNew In wb.Sheets
If wsNew.Name <> "Sheet 1" Then
wsNew.Delete
End If
Next
Application.DisplayAlerts = True
n = wb.Sheets.Count
' create new sheets/workbooks for each unique value
Application.ScreenUpdating = False
For Each key In dict.keys
Set wsNew = wb.Sheets.Add(after:=wb.Sheets(n))
wsNew.Name = Right(key, 5) ' number with C:
n = n + 1
' filter on col C and copy to new sheet
rng.AutoFilter 3, Criteria1:=CStr(key) & "*"
rng.Copy wsNew.Range("A1")
rng.AutoFilter 3
' copy to new workbook
wsNew.Copy
ActiveWorkbook.SaveAs wb.Path & "\" & wsNew.Name
ActiveWorkbook.Close False
Next
Application.ScreenUpdating = False
'ws.AutoFilterMode = False
MsgBox dict.Count & " workbooks created", vbInformation
End Sub
You need Ron de Bruin's new sheet for all unique values!
Sub Copy_To_Worksheets()
'Note: This macro use the function LastRow
Dim My_Range As Range
Dim FieldNum As Long
Dim CalcMode As Long
Dim ViewMode As Long
Dim ws2 As Worksheet
Dim Lrow As Long
Dim cell As Range
Dim CCount As Long
Dim WSNew As Worksheet
Dim ErrNum As Long
'Set filter range on ActiveSheet: A1 is the top left cell of your filter range
'and the header of the first column, D is the last column in the filter range.
'You can also add the sheet name to the code like this :
'Worksheets("Sheet1").Range("A1:D" & LastRow(Worksheets("Sheet1")))
'No need that the sheet is active then when you run the macro when you use this.
Set My_Range = Range("A1:D" & LastRow(ActiveSheet))
My_Range.Parent.Select
If ActiveWorkbook.ProtectStructure = True Or _
My_Range.Parent.ProtectContents = True Then
MsgBox "Sorry, not working when the workbook or worksheet is protected", _
vbOKOnly, "Copy to new worksheet"
Exit Sub
End If
'This example filters on the first column in the range(change the field if needed)
'In this case the range starts in A so Field:=1 is column A, 2 = column B, ......
FieldNum = 1
'Turn off AutoFilter
My_Range.Parent.AutoFilterMode = False
'Change ScreenUpdating, Calculation, EnableEvents, ....
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
ActiveSheet.DisplayPageBreaks = False
'Add a worksheet to copy the a unique list and add the CriteriaRange
Set ws2 = Worksheets.Add
With ws2
'first we copy the Unique data from the filter field to ws2
My_Range.Columns(FieldNum).AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=.Range("A1"), Unique:=True
'loop through the unique list in ws2 and filter/copy to a new sheet
Lrow = .Cells(Rows.Count, "A").End(xlUp).Row
For Each cell In .Range("A2:A" & Lrow)
'Filter the range
My_Range.AutoFilter Field:=FieldNum, Criteria1:="=" & _
Replace(Replace(Replace(cell.Value, "~", "~~"), "*", "~*"), "?", "~?")
'Check if there are no more then 8192 areas(limit of areas)
CCount = 0
On Error Resume Next
CCount = My_Range.Columns(1).SpecialCells(xlCellTypeVisible) _
.Areas(1).Cells.Count
On Error GoTo 0
If CCount = 0 Then
MsgBox "There are more than 8192 areas for the value : " & cell.Value _
& vbNewLine & "It is not possible to copy the visible data." _
& vbNewLine & "Tip: Sort your data before you use this macro.", _
vbOKOnly, "Split in worksheets"
Else
'Add a new worksheet
Set WSNew = Worksheets.Add(After:=Sheets(Sheets.Count))
On Error Resume Next
WSNew.Name = cell.Value
If Err.Number > 0 Then
ErrNum = ErrNum + 1
WSNew.Name = "Error_" & Format(ErrNum, "0000")
Err.Clear
End If
On Error GoTo 0
'Copy the visible data to the new worksheet
My_Range.SpecialCells(xlCellTypeVisible).Copy
With WSNew.Range("A1")
' Paste:=8 will copy the columnwidth in Excel 2000 and higher
' Remove this line if you use Excel 97
.PasteSpecial Paste:=8
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
.Select
End With
End If
'Show all data in the range
My_Range.AutoFilter Field:=FieldNum
Next cell
'Delete the ws2 sheet
On Error Resume Next
Application.DisplayAlerts = False
.Delete
Application.DisplayAlerts = True
On Error GoTo 0
End With
'Turn off AutoFilter
My_Range.Parent.AutoFilterMode = False
If ErrNum > 0 Then
MsgBox "Rename every WorkSheet name that start with ""Error_"" manually" _
& vbNewLine & "There are characters in the name that are not allowed" _
& vbNewLine & "in a sheet name or the worksheet already exist."
End If
'Restore ScreenUpdating, Calculation, EnableEvents, ....
My_Range.Parent.Select
ActiveWindow.View = ViewMode
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
End Sub
Function LastRow(sh As Worksheet)
On Error Resume Next
LastRow = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
Before:
After:
Source:
https://www.rondebruin.nl/win/s3/win006_4.htm

Merge Two Columns of Data into a Single Variable

I have a spreadsheet with two columns of data, both columns have a header. I would like to establish a variable for each row of data I can then use to generate new worksheet names and insert into formulas. My variable would be a one to one ratio with the data, meaning A2-B2, A3-B3, etc. I have tried the following code:
'''Sub CreateSheet2()
Dim rngBP As Range
Dim rngCon As Range
Dim cellBP As Range
Dim cellCon As Range
On Error GoTo Errorhandling
Set rngBP = Application.InputBox(prompt:="Bid Package Select Cell Range:", Title:="Create Sheets", Default:=Selection.Address, Type:=8)
Set rngCon = Application.InputBox(prompt:="Contractor Select Cell Range:", Title:="Create Sheets", Default:=Selection.Address, Type:=8)
For Each cellBP In rngBP
If cellBP <> "" And cellCon <> "" Then
Sheets.Add(after:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count)).Name = cellBP & "-" & cellCon
End If
Next cellBP
Errorhandling:
MsgBox prompt:="Error Detected" & vbNewLine & "Error" & Err.Number & ": " & Err.Description
End Sub'''
However, this code generates a variable with all of the possible combinations (A2-B2, A2-B3, A3-B3, etc.). Ideally, this code would also skip empty cells and not create a variable for that entire row. Here is a screenshot of my sample dataset.Sample Dataset. Thank you for the assistance.
Add Worksheets with Names Created from Two Columns
I see the double Application.InputBoxes as a disaster waiting to happen so I abandoned the idea.
The code will search for the specified headers in the first row and their columns will define the column ranges (from the 2nd to the last row).
Copy the code into a standard module, e.g. Module1.
Adjust the four constants.
You only run the first procedure which will call the second when needed.
The third procedure is showing an example of proper error handling. Study it closely.
The Code
Option Explicit
Sub CreateSheet2()
'On Error GoTo ErrorHandling
Const wsName As String = "Sheet1"
Const bTitle As String = "Bid Package"
Const cTitle As String = "Contractor"
Const FirstRow As Long = 2
Dim wb As Workbook
Set wb = ThisWorkbook ' The workbook containing this code.
Dim ws As Worksheet
Set ws = wb.Worksheets(wsName)
Dim bCol As Variant
bCol = Application.Match(bTitle, ws.Rows(1), 0)
Dim cCol As Variant
cCol = Application.Match(cTitle, ws.Rows(1), 0)
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, bCol).End(xlUp).Row
Dim ColumnOffset As Long
ColumnOffset = cCol - bCol
Dim SheetNames As Variant
SheetNames = getSheetNames(wb)
Dim rng As Range
Set rng = ws.Cells(FirstRow, bCol).Resize(LastRow - FirstRow + 1)
Dim cel As Range
Dim SheetName As String
For Each cel In rng.Cells
If cel.Value <> "" And cel.Offset(, ColumnOffset).Value <> "" Then
SheetName = cel.Value & "-" & cel.Offset(, ColumnOffset).Value
If IsError(Application.Match(SheetName, SheetNames, 0)) Then
On Error Resume Next
wb.Worksheets.Add(After:=wb.Sheets(wb.Sheets.Count)).Name _
= SheetName
If Err Then ' might happen if there are duplicates in columns.
Application.DisplayAlerts = False
ActiveSheet.Delete
Application.DisplayAlerts = True
End If
On Error GoTo ErrorHandling
End If
End If
Next cel
ProcExit:
Exit Sub
ErrorHandling:
MsgBox Prompt:="Error Detected" & vbNewLine & "Error '" & Err.Number _
& "': " & Err.Description, _
Buttons:=vbCritical, _
Title:="Fail"
Resume ProcExit
End Sub
Function getSheetNames(Book As Workbook) _
As Variant
If Book Is Nothing Then
GoTo ProcExit
End If
Dim Data As Variant
ReDim Data(1 To Book.Sheets.Count)
Dim sh As Object
Dim n As Long
For Each sh In Book.Sheets
n = n + 1
Data(n) = sh.Name
Next sh
getSheetNames = Data
ProcExit:
End Function
Proper Error Handling
Sub ProperErrorHandling()
On Error GoTo ErrorHandling
' The code
ProcExit:
Exit Sub ' You don't want to show the message if no error and
' you must not 'Resume' with no error!
ErrorHandling:
MsgBox Prompt:="Error Detected" & vbNewLine & "Error '" & Err.Number _
& "': " & Err.Description, _
Buttons:=vbCritical, _
Title:="Fail"
' Sets the error number to 0, but still keeps the error handler active.
' Therefore be aware that if you put code between 'ProcExit' and 'Exit Sub'
' and an error occurs, it will result in an endless loop.
Resume ProcExit ' 'Resume', not 'GoTo'!
End Sub
Please try this code.
Sub CreateSheet2()
Const BidPack As String = "A" ' specify a column
Const Contractor As String = "B" ' change to suit (to the right of BidPack)
Const FirstDataRow As Long = 2 ' change to suit
Dim Wb As Workbook
Dim Ws As Worksheet
Dim BidRng As Range
Dim ConRng As Range
Dim Tmp As Variant ' misc use
Dim WsName As String
Dim R As Long ' loop counter: rows
Set Wb = ActiveWorkbook ' change to suit
WsName = "Sheet1" ' change to suit
Application.ScreenUpdating = False
Tmp = Columns(Contractor).Column
With Wb.Worksheets(WsName)
Set ConRng = .Range(.Cells(FirstDataRow, Tmp), _
.Cells(.Rows.Count, Tmp).End(xlUp))
' ConRng and BidRng are of identical size,
' not exceeding the number of rows available in ConRng.
Set BidRng = ConRng.Offset(, Columns(BidPack).Column - Tmp)
For R = 1 To BidRng.Cells.Count
If (Not IsEmpty(BidRng.Cells(R))) And (Not IsEmpty(ConRng.Cells(R))) Then
WsName = Format(BidRng.Cells(R).Value, "00-") & ConRng.Cells(R).Value
On Error Resume Next
Set Tmp = Wb.Sheets(WsName)
If Err Then
Wb.Sheets.Add(After:=Wb.Sheets(Wb.Sheets.Count)).Name = WsName
Else
MsgBox "A worksheet by the name of """ & WsName & _
""" already exists.", vbInformation, _
"Duplicate instruction"
End If
End If
Next R
End With
Application.ScreenUpdating = False
End Sub
I think it's best
loop through rngBP range not empty values, only
using a Dictionary object to ensure you're not duplicating sheet names
Option Explicit
Sub CreateSheets()
Dim rngBP As Range
Dim cellBP As Range
On Error GoTo Errorhandling
Set rngBP = Application.InputBox(prompt:="Bid Package Select Cell Range:", Title:="Create Sheets", Default:=Selection.Address, Type:=8)
Dim shNamesDict As Object
Set shNamesDict = CreateObject("Scripting.Dictionary")
With ActiveWorkbook
Dim shName As String
For Each cellBP In rngBP.SpecialCells(xlCellTypeConstants)
If Not IsEmpty(cellBP.Offset(, 1).Value2) Then
shName = cellBP.Value2 & "-" & cellBP.Offset(, 1).Value2
If Not shNamesDict.exists(shName) Then
shNamesDict.Add shName, 0
.Sheets.Add(after:=.Worksheets(.Worksheets.Count)).Name = shName
End If
End If
Next
End With
Errorhandling:
If Err.Number <> 0 Then MsgBox prompt:="Error Detected" & vbNewLine & "Error" & Err.Number & ": " & Err.Description
End Sub

Where do I add this function

I have a macro in my Excel Workbook that I run reports on.
I want to add in the pastespecial Function below but don't know where to place it in the script further down. It keeps giving me errors. I've tried almost every line.
I also want to add an extract phrase function added in as well. There is some text I want removed from one column at the beginning of every cell eg: alpha/beta/kappa
Help please. Thank you.
++++++++++++++++++++++++++++++++
Copy and Value Paste to Different Sheet
This example will Copy & Paste Values for single cells on different worksheets
1
2
Sheets("Sheet1").Range("A1").Copy
Sheets("Sheet2").Range("B1").PasteSpecial Paste:=xlPasteValues
++++++++++++++++++++++++++++++++++++++
My code below where I want to insert the above pastespecial function:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Option Explicit
Function GetHeadersDict() As Scripting.Dictionary
' We must activate the Microsoft Scripting Runtime from Tools --References
Dim result As Scripting.Dictionary
Set result = New Scripting.Dictionary
With result
.Add "Track #", False
.Add "Date", False
.Add "Status", False
.Add "Shoes", False
.Add "Description", False
End With
Set GetHeadersDict = result
End Function
Function FindHeaderRange(ByVal ws As Worksheet, ByVal header As String) As Range
Set FindHeaderRange = ws.Cells.Find(header, , , xlWhole)
End Function
Sub clearDataNotFormulasSheet2()
Sheets("Results").Range("A2:k96").ClearContents
End Sub
Sub copyColumnData()
On Error GoTo ErrorMessage
Dim ws1 As Worksheet, ws2 As Worksheet
Set ws1 = ThisWorkbook.Sheets("Report")
Set ws2 = ThisWorkbook.Sheets("Results")
clearDataSheet2
Dim numRowsToCopy As Long
numRowsToCopy = ws1.Cells(RowIndex:=Rows.Count, ColumnIndex:=1).End(xlUp).Row - 1
'MsgBox "The no of rows to copy is " & numRowsToCopy
Dim destRowOffset As Long
destRowOffset = ws2.Cells(RowIndex:=Rows.Count, ColumnIndex:=1).End(xlUp).Row
'MsgBox "The next Blank row is " & destRowOffset
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim dictKey As Variant
Dim header As String
Dim numColumnsToCopy As Long
Dim Report As Range
Dim dest As Range
Dim headersDict As Scripting.Dictionary
Set headersDict = GetHeadersDict()
For Each dictKey In headersDict
header = dictKey
If headersDict.Item(header) = False Then
Set Report = FindHeaderRange(ws1, header)
If Not (Report Is Nothing) Then
Set dest = FindHeaderRange(ws2, header)
If Not (dest Is Nothing) Then
headersDict.Item(header) = True
' Look at successive headers to see if they match
' If so, copy these columns altogether to make the macro faster
For numColumnsToCopy = 1 To headersDict.Count
'MsgBox numColumnsToCopy
If Report.Offset(ColumnOffset:=numColumnsToCopy).Value = dest.Offset(ColumnOffset:=numColumnsToCopy).Value Then
headersDict.Item(Report.Offset(ColumnOffset:=numColumnsToCopy).Value) = True
Else
Exit For
End If
Next numColumnsToCopy
Report.Offset(RowOffset:=1).Resize(RowSize:=numRowsToCopy, ColumnSize:=numColumnsToCopy).Copy _
dest.Offset(RowOffset:=destRowOffset)
End If
End If
End If
Next dictKey
Dim msg As String
For Each dictKey In headersDict
header = dictKey
If headersDict.Item(header) = False Then
msg = msg & vbNewLine & header
End If
Next dictKey
ExitSub:
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
If msg <> "" Then
MsgBox "The following headers were not copied:" & vbNewLine & msg
End If
Exit Sub
ErrorMessage:
MsgBox "An error has occurred: " & Err.Description
Resume ExitSub
End Sub
Private Sub CommandButton1_Click()
End Sub
I had the same issue of yours just replace Report.Offset(RowOffset:=1).Resize(RowSize:=numRowsToCopy, ColumnSize:=numColumnsToCopy).Copy _ dest.Offset(RowOffset:=destRowOffset)
with
Report.Offset(RowOffset:=1).Resize(RowSize:=numRowsToCopy,ColumnSize:=numColumnsToCopy).Copy
dest.Offset(RowOffset:=destRowOffset).PasteSpecial Paste:=xlPasteValues

VBA copy a range based on values from 2 separate sheets

I do not know what I am doing wrong. The code will run but it does not copy the data as expected, all the values seem to be overwriting to row 1 on the target sheet (tsht) instead of copying data down the target sheet. The goal here is to take data and iterate it for every county listed on the group ID tab (captured by SubCell.Value). Where plan codes and term dates match, the macro should copy each matching row from dsht for the indicated number of counties on gsht to the tsht. Can anyone see my error or why this code is keeping data all in the top row of the tsht?
Sub GroupID_Breakout()
Dim dsht As Worksheet 'data sheet target
Dim gsht As Worksheet
Dim tsht As Worksheet
Dim dlrow As Long
Dim glrow As Long
Dim tlrow As Long
Dim SubCell As Range
Dim rngCell As Range
Dim Result() As String
Dim countycount As Long
Set dsht = ThisWorkbook.Worksheets("Data_No Formulas")
Set gsht = ThisWorkbook.Worksheets("GroupID")
'kill clunky processes
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
Application.Calculation = xlCalculationManual
'delete compare tab if it exists
Application.DisplayAlerts = False
On Error Resume Next
ThisWorkbook.Sheets("Data_Final").Delete
On Error GoTo 0
Application.DisplayAlerts = True
'On Error GoTo Errhandler
Sheets.Add(After:=Sheets("Data_No Formulas")).Name = "Data_Final" 'create new tab
Set tsht = ThisWorkbook.Worksheets("Data_Final")
With dsht.Range("A2:CN2")
tsht.Range("A1").Resize(.Rows.Count, .Columns.Count).Value = .Value
End With
glrow = gsht.Cells(Rows.Count, 1).End(xlUp).Row
dlrow = dsht.Cells(Rows.Count, 1).End(xlUp).Row
For Each SubCell In gsht.Range("I2:I" & glrow)
countycount = SubCell.Value
Result() = Split(SubCell.Offset(0, -2).Value, ",")
For Each rngCell In dsht.Range("A3:A" & dlrow)
a = 0
If SubCell.Offset(0, -4).Value = rngCell.Value And SubCell.Offset(0, -8).Value = rngCell.Offset(0, 5).Value Then
For i = 1 To countycount
tlrow = tsht.Cells(Rows.Count, 1).End(xlUp).Row
With dsht.Range(rngCell, rngCell.Offset(0, 91))
tsht.Range("A" & tlrow).Resize(.Rows.Count, .Columns.Count).Value = .Value
End With
tsht.Range("L" & tlrow).Value = Result(a)
i = i + 1
Next
a = a + 1
End If
Next rngCell
Next SubCell
'bring back clunky processes
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
Application.Calculation = xlCalculationAutomatic
MsgBox ("Macro Complete!")
Exit Sub
Errhandler:
'bring back clunky processes
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
Application.Calculation = xlCalculationAutomatic
Select Case Err.Number
'different error handling here
Case Else
MsgBox "Error " & Err.Number & ": " & Err.Description, vbCritical, "Summary"
End Select
End Sub
This has been resolved with the below code, I wanted to post the resolution in case anyone finds a way to make this code work for them. Sorry I couldn't get this to copy over as clean as my 1st block.
Solution:
Sub GroupID_Breakout()
Dim dsht As Worksheet 'data sheet target
Dim gsht As Worksheet
Dim tsht As Worksheet
Dim dlrow As Long
Dim glrow As Long
Dim tlrow As Long
Dim SubCell As Range
Dim rngCell As Range
Dim Result() As String
Dim countycount As Long
Set dsht = ThisWorkbook.Worksheets("Data_No Formulas")
Set gsht = ThisWorkbook.Worksheets("GroupID")
'kill clunky processes
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
Application.Calculation = xlCalculationManual
'delete compare tab if it exists
Application.DisplayAlerts = False
On Error Resume Next
ThisWorkbook.Sheets("Data_Final").Delete
On Error GoTo 0
Application.DisplayAlerts = True
'On Error GoTo Errhandler
Sheets.Add(After:=Sheets("Data_No Formulas")).Name = "Data_Final" 'create new tab
Set tsht = ThisWorkbook.Worksheets("Data_Final")
'pull header from dsht to tsht
With dsht.Range("A2:CN2")
tsht.Range("A1").Resize(.Rows.Count, .Columns.Count).Value = .Value
End With
glrow = gsht.Cells(Rows.Count, 1).End(xlUp).Row
dlrow = dsht.Cells(Rows.Count, 1).End(xlUp).Row
For Each SubCell In gsht.Range("I2:I" & glrow)
countycount = SubCell.Value
Result() = Split(SubCell.Offset(0, -2).Value, ",") 'separates a list of counties by comma to reference as "Result(0)"
For Each rngCell In dsht.Range("A3:A" & dlrow)
a = 0
i = 1
For i = 1 To countycount
If SubCell.Offset(0, -4).Value = rngCell.Value And SubCell.Offset(0, -8).Value = rngCell.Offset(0, 5).Value Then 'match dates and plan codes
'move row where match is found between dsht and gsht variables
With dsht.Range(rngCell, rngCell.Offset(0, 91))
tlrow = tsht.Cells(Rows.Count, 1).End(xlUp).Row
tsht.Range("A" & (tlrow + 1)).Resize(.Rows.Count, .Columns.Count).Value = .Value
End With
'place county names captured by split above with each iteration
tsht.Range("L" & (tlrow + 1)).Value = Result(a)
End If
a = a + 1
Next i
Next rngCell
Next SubCell
'bring back clunky processes
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
Application.Calculation = xlCalculationAutomatic
MsgBox ("Macro Complete!")
Exit Sub
Errhandler:
'bring back clunky processes
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
Application.Calculation = xlCalculationAutomatic
Select Case Err.Number
'different error handling here
Case Else
MsgBox "Error " & Err.Number & ": " & Err.Description, vbCritical, "Summary"
End Select
End Sub
tsht.Range("A" & tlrow).Resize(.Rows.Count, .Columns.Count).Value =
should be
tsht.Range("A" & (tlrow+1)).Resize(.Rows.Count, .Columns.Count).Value =

Resources