Copy and Paste under specific Header - excel

I have 6 different headers under the WIPTX worksheet that will be pulling information from the TestData tab which is essentially data that will be uploaded from a SharePoint site. I want to be able to copy and paste rows that have specific values like the type of status or by name
under each header in the WIPTX worksheet. Headers are in columns A-C, E-G, I-K, M-O, Q-S, and U-W. Headers are of different status's that are in the TestData worksheet. Status include Assigned, Accepted, In Progress, On Hold, Completed, and Cancelled.
Will this be possible?
Code that I have so far works but it does not paste under specific header columns.
I have tried researching and looing at other sources but I am still not able to find the right code that is specific to what I am looking for.
Sub Update1()
Dim LastRow1 As Long, LastRow2 As Long, i As Long
With ThisWorkbook.Worksheets("TestData")
LastRow1 = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = 1 To LastRow1
If .Range("A" & i).Value = "Thomas Xiong" Then
LastRow2 = ThisWorkbook.Worksheets("All Projects with NetBuilds").Cells(ThisWorkbook.Worksheets("All Projects with NetBuilds").Rows.Count, "A").End(xlUp).Row
.Rows(i).Copy ThisWorkbook.Worksheets("All Projects with NetBuilds").Rows(LastRow2 + 1)
End If
Next i
End With
End Sub
Is this possible?

I think this should help you:
Option Explicit
Sub Update1()
Dim wsData As Worksheet, wsProjects As Worksheet, LastRow As Long, Col As Integer, CopyRange As Range, C As Range
With ThisWorkbook
Set wsData = .Sheets("TestData") 'refering the worksheet with all the data
Set wsProjects = .Sheets("All Projects with NetBuilds") 'refering the worksheet with the headers
End With
For Each C In wsData.Range("A2", wsData.Cells(1, 1).End(xlDown)) 'Lets assume the criteria is on the column A
With wsData
Select Case C.Value
Case "Assigned"
With wsData
Set CopyRange = .Range(.Cells(C.Row, 3), .Cells(C.Row, 5)) 'Here I'm assuming you want to copy data from Columns B To D
End With
Case "Accepted"
With wsData
Set CopyRange = .Range(.Cells(C.Row, 7), .Cells(C.Row, 9)) 'Here I'm assuming you want to copy data from Columns G To I
End With
'... all your headers
End Select
End With
With wsProjects
Col = .Cells.Find(C).Column 'Find the header column
LastRow = .Cells(.Rows.Count, Col).End(xlUp).Row + 1 'find the last row on that header
CopyRange.Copy .Cells(LastRow, Col) 'paste the range (this method will copy everything from the source)
End With
Next C
'In case you are always copying the same range of cells skip the select case, delete the CopyRange variable and just copy paste on the last block
End Sub

Related

Use VBA to copy entire row from one excel worksheet to another if match is not found in Column A

I have been running into some issues trying to use VBA to compare 2 tables in different worksheets, and then copy any rows in the "Master" sheet that are not found in the "New" sheet. Both tables are formatted as tables. The match is based on an "ID" column in Column A of both tables. If an ID is in the "Master" sheet, but not in the "New" sheet, than that entire row should be copy and pasted to the end of the table in the "New" sheet.
I updated some code found in another forum, which is almost working. However, it only seems to paste over the ID data into Column A, and not the entire corresponding row of data which is needed.
Sub compare()
Dim i As Long
Dim lrs As Long
Dim lrd As Long
With Worksheets("Master")
lrs = .Cells(.Rows.Count, 1).End(xlUp).Row
For i = 2 To lrs 'assumes header in row 1
If Application.IfError(Application.Match(.Cells(i, 1), Worksheets("New").Columns(1), 0), 0) = 0 Then
lrd = Worksheets("New").Cells(Worksheets("test").Rows.Count, 1).End(xlUp).Row
Worksheets("New").Cells(lrd + 1, 1).Value = .Cells(i, 1).Value
End If
Next i
End With
End Sub
I think the issue has to do with the "Cells" reference, instead of a range, but I do not know how to make that line dynamic.
Slightly different approach, but you need to use something like Resize() to capture the whole row, and not just the cell in Col A.
Sub compare()
Const NUM_COLS As Long = 10 'for example
Dim wb As Workbook, wsSrc As Worksheet, wsDest As Worksheet
Dim c As Range, cDest As Range
Set wb = ThisWorkbook 'or ActiveWorkbook for example
Set wsSrc = wb.Worksheets("Master")
Set wsDest = wb.Worksheets("New")
Set cDest = wsDest.Cells(Rows.Count, 1).End(xlUp).Offset(1) 'next empty row
For Each c In wsSrc.Range("A2:A" & wsSrc.Cells(Rows.Count, 1).End(xlUp).Row).Cells
If IsError(Application.Match(c.Value, wsDest.Columns(1), 0)) Then
cDest.Resize(1, NUM_COLS).Value = c.Resize(1, NUM_COLS).Value
Set cDest = cDest.Offset(1) 'next row
End If
Next c
End Sub

How to copy rows based on multiple email addresses?

I have a huge list of data and column 3 contains email addresses.
I'm trying to copy rows based on a mailing list. As long as the row contains one of the email addresses in the mailing list it should be copied to a new sheet.
I have code to copy data based on one email at a time.
I have a userform set up for several email addresses, but this is not efficient.
Here is my code that uses one email address at a time.
Private Sub CommandButton1_Click()
a = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To a
If Worksheets("Sheet1").Cells(i, 3).Value = "<#gmail.com>" Then
Worksheets("Sheet1").Rows(i).Copy
Worksheets("Sheet2").Activate
b = Worksheets("Sheet2").Cells(Rows.Count, 1).End(xlUp).Row
Worksheets("Sheet2").Cells(b + 1, 1).Select
ActiveSheet.Paste
Worksheets("Sheet2").Activate
End If
Next
Application.CutCopyMode = False
End Sub
How to copy rows based on multiple emails addresses?
I would suggest using the Advanced Filter The destination range will get written in a single step. If you can minimize the number of times your code reads/writes to/from a worksheet, the faster it will run.
Sheet 1
Read the comments in the code as they will be important for modifying it to your real data.
In particular, if your column 3 list does not have the same format as what you have shown in your code, you will need to modify the Criteria range to account for that. The Advanced Filter can also accept wild-cards in the criteria, so this might be another possible approach if your column 3 contains actual email addresses.
Option Explicit
Sub copyWithEmail()
Dim wsSrc As Worksheet, wsDest As Worksheet
Dim rSrc As Range, rDest As Range, rCrit As Range
Dim arrCrit As Variant
Dim I As Long
Set wsSrc = Worksheets("sheet1")
Set wsDest = Worksheets("sheet2")
With wsDest
.Cells.Clear 'optional
Set rCrit = .Cells(1, 250) 'someplace off the screen view
Set rDest = .Cells(1, 1)
End With
'assumes original data starts in A1
'assumes first row is a header row
Set rSrc = wsSrc.Cells(1, 1).CurrentRegion
'can get list of desired emails from user form; range someplace in the workbook; or hard-coded as we have here
arrCrit = Array("gmail.com", "abc.com")
For I = 0 To UBound(arrCrit)
'creating formula that mimics what you show in your code above.
arrCrit(I) = "=" & """=<#" & arrCrit(I) & ">"""
Next I
'create criteria range
'header is same header as in Source Data column 3
Set rCrit = rCrit.Resize(2 + UBound(arrCrit))
rCrit(1) = rSrc(1, 3)
rCrit.Offset(1).Resize(rCrit.Rows.Count - 1) = WorksheetFunction.Transpose(arrCrit)
'Activate wsDest since we will be copying here
wsDest.Activate
rSrc.AdvancedFilter Action:=xlFilterCopy, _
CriteriaRange:=rCrit, CopyToRange:=rDest, Unique:=False
rDest.CurrentRegion.EntireColumn.AutoFit
rCrit.Clear 'get rid of this range
End Sub
Sheet 2
May be something like having Sheet3 of mialList and then
Private Sub CommandButton1_Click()
Dim Sh1 As Worksheet, Sh2 As Worksheet, Sh3 As Worksheet, fnd As Range, cl As Range
Set Sh1 = Worksheets("Sheet1")
Set Sh2 = Worksheets("Sheet2")
Set Sh3 = Worksheets("Sheet3")
Dim mailList As Range
x = Sh3.Range("A" & Sh3.Rows.Count).End(xlUp).Row
Set mailList = Sh3.Range("A2:A" & x)
'Assuming headers in row 1
For Each cl In mailList
b = Sh2.Range("A" & Sh2.Rows.Count).End(xlUp).Row + 1
Set fnd = Sh1.Columns(3).Find(cl)
If Not fnd Is Nothing Then
Sh2.Rows(b).Value = Sh1.Rows(fnd.Row).Value
End If
Next
End Sub

How to copy and paste only filtered cells in excel using vba

I've been trying to copy and paste a range of filtered cells in a specific space in my excel sheet (take a look in the images) using vba , but when I try to do that, the
error 1004
occurs. I've searched in a lot of forums and try to solve my problem in different ways but it isn't working and the error 1004 still occurs.
Sub arrumando_dados_pro_xml()
Dim n As Integer
Dim i As Integer
Dim m As Integer
Dim j As Integer
n = Cells(1000, 1).End(xlUp).Row
j = Cells(n - 1, 1).End(xlUp).Row
m = Cells(1, 50).End(xlLeft).Row
Range(Worksheets("Planilha1").Cells(2, 1), Worksheets("Planilha1").Cells(j, m)).SpecialCells(xlCellTypeVisible).Copy
'''Range("A2:P37").SpecialCells(xlCellTypeVisible).Select
''''Selection.SpecialCells(xlCellTypeVisible).Select
'''Selection.SpecialCells(xlCellTypeVisible).Copy
''''Call Plan1.AutoFilter.Range.Copy
Range(Worksheets("Planilha2").Cells(1, 1), Worksheets("Planilha2").Cells(1, m)).Paste
Range(Worksheets("Planilha2").Cells(1, 1), Worksheets("Planilha2").Cells(1, m)).Copy
Range(Worksheets("Planilha1").Cells(n, 1), Worksheets("Planilha2").Cells(n, m)).Copy
''' Range(Cells(n, 1), Cells(n, m)).Select
''' ActiveSheet.Paste
End Sub
Since your code was a little confusing, I simplified it. Here is a basic code example, with comments, to copy visible cells in a range and paste. It can be modified as needed.
'Declare your variables
Dim ws1 As Worksheet, ws2 As Worksheet, As Range, lRow As Long, lCol As Long
'Assign your variables, you should always identify the workbook and worksheet
'ThisWorkbook refers to the workbook where your code resides
Set ws1 = ThisWorkbook.Sheets("Planilha1")
Set ws2 = ThisWorkbook.Sheets("Planilha2")
'Using your worksheet variable find the last used row and last used column
lRow = ws1.Cells(ws1.Rows.Count, 1).End(xlUp).Row
lCol = ws1.Cells(1, ws1.Columns.Count).End(xlToLeft).Column
'Define your range by resizing using lRow and lCol.
Set rng = ws1.Cells(2, 1).Resize(lRow - 1, lCol)
'Copy the visible cells in the range(normally used after filtering or with hidden rows/columns)
rng.SpecialCells(xlCellTypeVisible).Copy
'paste the copied range starting on row 1, after the last column with data, by using .Offset(, 1)
ws2.Cells(1, 1).PasteSpecial xlPasteValues
If you have any questions, please ask and I will help.
Edited I modified your code, had to make changes, see comments
'Added worksheet variables
Dim ws1 As Worksheet, ws2 As Worksheet, n As Long, m As Long 'removed j As Long
Set ws1 = ThisWorkbook.Sheets("Planilha1")
Set ws2 = ThisWorkbook.Sheets("Planilha2")
n = ws1.Cells(1000, 1).End(xlUp).Row
'Removed [j = ws1.Cells(n - 1, 1).End(xlUp).Row] if there are no blank cells after "n" the new last used row then j = 1
m = ws1.Cells(1, 50).End(xlToLeft).Column 'you can't use .End(xlLeft).Row to get the last column
'changed j to n, if j = 1 then only the top two rows will be copied
ws1.Range(ws1.Cells(2, 1), ws1.Cells(n, m)).SpecialCells(xlCellTypeVisible).Copy
'when pasting, just use one cell
ws2.Cells(1, 1).PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False 'Exits the CutCopyMode, removes "Marching Ants"

Adding a column stating the worksheet source of the data

The program's main function is to copy all the data in the worksheets opened and put it in a worksheet named "consolidated." Everything's working well, however, I want to add a column called "Data Source" wherein it can state where the data came from (e.g. Sheet1, Sheet2). But the thing is, it outputs the wrong sheet name.
I have tried different codes and I have attached what currently works below. I will highlight the part where I assume the problem comes from. I would really appreciate some help as I'm not a coder myself (just learned this a week ago).
For Each wksSrc In ThisWorkbook.Worksheets
'Skip Destination worksheet
If wksSrc.Name <> wksDst.Name And wksSrc.Name <> "Tool" Then
With wksSrc
'Identify the last row and column on this sheet
'so we know when to stop looping through the data
lngLastSrcRowNum = LastOccupiedRowNum(wksSrc)
lngLastSrcColNum = LastOccupiedColNum(wksSrc)
'Identify the last row of the Destination sheet
'so we know where to (eventually) paste the data
lngLastDstRowNum = LastOccupiedRowNum(wksDst)
'Loop through the headers on this sheet, looking up
'the appropriate Destination column from the Final
'Headers dictionary and creating ranges on the fly
For lngIdx = 1 To lngLastSrcColNum
strColHeader = Trim(CStr(.Cells(1, lngIdx)))
'Set the Destination target range using the
'looked up value from the Final Headers dictionary
Set rngDst = wksDst.Cells(lngLastDstRowNum + 1, _
dicFinalHeaders(strColHeader))
'Set the source target range using the current
'column number and the last-occupied row
Set rngSrc = .Range(.Cells(2, lngIdx), _
.Cells(lngLastSrcRowNum, lngIdx))
'Copy the data from this sheet to the destination
rngSrc.Copy Destination:=rngDst
Next lngIdx
Dim TargetColumn As Long
Dim FinalRow As Long
Dim rngAddress As Range
Dim i As Long
With wksDst
FinalRow = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rngAddress = .Range("A:Z").Find("Data Source")
If Not rngAddress Is Nothing Then
TargetColumn = rngAddress.Column
''''THIS IS THE PART WHERE I ASSUME THE PROBLEM COMES FROM'''''
For i = 1 To FinalRow
.Cells(i, TargetColumn).Value = wksSrc.Name
Next i
End If
End With
End With
End If
Next wksSrc
End Sub
I already added the "Data Source" column but the wksSrc.Name part in the code always outputs only the last worksheet name when it should be different/dynamic depending on the worksheets where I got the data from.
This might help. When I make the i value to 1, it outputs the correct sheet name, however, it replaces the column header with the sheet name and the loop is only done once. When I make the i value to 2, it outputs the wrong sheet name but it starts to output in the correct first blank row of the Data Source column.
As mentioned in the comments. You are looping through the ENTIRE source name column each time. As such, at the end of your process you will be left with the last worksheet looped through. So in order to overcome this you need a StartRow as well as a FinalRow to only loop through data from that sheet. See below code (not tested) but I think you will get the idea of how to implement and it may work off the bat.
For Each wksSrc In ThisWorkbook.Worksheets
'Skip Destination worksheet
If wksSrc.Name <> wksDst.Name And wksSrc.Name <> "Tool" Then
With wksSrc
'Identify the last row and column on this sheet
'so we know when to stop looping through the data
lngLastSrcRowNum = LastOccupiedRowNum(wksSrc)
lngLastSrcColNum = LastOccupiedColNum(wksSrc)
'Identify the last row of the Destination sheet
'so we know where to (eventually) paste the data
lngLastDstRowNum = LastOccupiedRowNum(wksDst)
'Loop through the headers on this sheet, looking up
'the appropriate Destination column from the Final
'Headers dictionary and creating ranges on the fly
For lngIdx = 1 To lngLastSrcColNum
strColHeader = Trim(CStr(.Cells(1, lngIdx)))
'Set the Destination target range using the
'looked up value from the Final Headers dictionary
Set rngDst = wksDst.Cells(lngLastDstRowNum + 1, _
dicFinalHeaders(strColHeader))
'Set the source target range using the current
'column number and the last-occupied row
Set rngSrc = .Range(.Cells(2, lngIdx), _
.Cells(lngLastSrcRowNum, lngIdx))
'Copy the data from this sheet to the destination
rngSrc.Copy Destination:=rngDst
Next lngIdx
Dim TargetColumn As Long
Dim FinalRow As Long, StartRow As Long
Dim rngAddress As Range
Dim i As Long
With wksDst
Set rngAddress = .Range("A:Z").Find("Data Source")
If Not rngAddress Is Nothing Then
TargetColumn = rngAddress.Column
'set the start for this sheet
StartRow = lngLastDstRowNum + 1
'set the final row for this worksheet
FinalRow = .Cells(.Rows.Count, "A").End(xlUp).Row
.Range(.Cells(StartRow, TargetColumn), .Cells(FinalRow, TargetColumn)).Value = wksSrc.Name
End If
End With
End With
End If
Next wksSrc
As can be seen your range adjustment on the wksDst should take into account the sheets data.

Additional condition to copy only new values

The following code works fine for me to identify rows of data that have a certain value in Column BH in sheet(SOC 5) and copy the corresponding values in row column A from each respective row, to a new sheet.
However, I need to amend the code to copy to my destination sheet ONLY THE Newly Identified values. Meaning, the destination sheet already had some of the values I am looking for. After refreshing my underlying data, I need the code to pull in only, the newest values which meet the criteria.
Sub Cond5Copy()
'The data is in sheet Data
Sheets("Data").Select
RowCount = Cells(Cells.Rows.Count, "a").End(xlUp).Row
For i = 1 To RowCount
'the qualifying value is in column BH
Range("BH" & i).Select
check_value = ActiveCell
If check_value = "5" Then
Cells(Application.ActiveCell.Row, 1).Copy
'The destination set is in sheet SOC 5
Sheets("SOC 5").Select
RowCount = Cells(Cells.Rows.Count, "a").End(xlUp).Row
Range("a" & RowCount + 1).Select
ActiveSheet.Paste
Sheets("Data").Select
End If
Next
End Sub
You can try of moving all data that meets:
Dim s as Worksheet, d as Worksheet, LRs as Long, LRd as Long
Set s = Sheets("Data") 's for Source
Set d = Sheets("SOC 5") 'd for Destination
LRs = s.Cells( s.Rows.Count, "A").End(xlUp).Row 'last row of source
For i = 1 to LRs
If s.Cells( i, "BH") = 5 Then
LRd = d.Cells( d.Rows.Count, "A").End(xlUp).Row 'last row of destination
s.Rows(i).Copy d.Rows(LRd + 1)
End If
Next i
You can use this to verify newest data:
Dim s as Worksheet, d as Worksheet, LRs as Long, LRd as Long
Set s = Sheets("Data") 's for Source
Set d = Sheets("SOC 5") 'd for Destination
LRs = s.Cells( s.Rows.Count, "A").End(xlUp).Row 'last row of source
LRd = d.Cells( d.Rows.Count, "A").End(xlUp).Row 'last row of destination
For i = 1 to LRd
If d.Cells( i, "B") = Application.Index( s.Range( s.Cells(1, "B"), s.Cells(LRs, "B")), Application.Match(d.Cells( i, "A"), s.Range( s.Cells(1, "A"), s.Cells(LRs, "A")),0)) Then
s.Rows(Application.Match(d.Cells( i, "A"), s.Range( s.Cells(1, "A"), s.Cells(LRs, "A")),0)).Copy d.Rows(i)
End If
Next i
Used abritrary look-up in A for matching (match) and an output of B (index).
So it sounds like you want a unique list of values. Have you considered using a dictionary object? Dictionary objects in Excel VBA have a method to allow you to check if a value already exists in the dictionary. This allows you the ability to easily populate the dictionary with only unique values by checking that a value you're considering adding to the dictionary doesn't already exist in the dictionary.
If this sounds promising to you, then I encourage you to visit the following resource to learn more about how to use dictionaries in VBA:
https://excelmacromastery.com/vba-dictionary/#A_Quick_Guide_to_the_VBA_Dictionary
You'll want to be using the following exists method:
dict.Exists(Key)
To check if a value is already in the dictionary.
Please let me know if this answer isn't clear enough, because I can elaborate if necessary.
Sub Cond5CopyNew()
Dim wsSource As Worksheet
Dim wsDest As Worksheet
Dim rowCount As Long
Set wsSource = Worksheets("Data")
Set wsDest = Worksheets("SOC 5")
Application.ScreenUpdating = False
With wsSource
rowCount = .Cells(.Cells.Rows.Count, "a").End(xlUp).Row
For i = 1 To rowCount
If .Cells(i, "BH").Value = 5 Then
'Second check, make sure it's not already copied
If WorksheetFunction.CountIf(wsDest.Range("A:A"), .Cells(i, "A").Value) = 0 Then
'Copy the row over to next blank row
.Cells(i, "A").Copy wsDest.Cells(.Rows.Count, "A").End(xlUp).Offset(1)
End If
End If
Next i
End With
Application.ScreenUpdating = True
End Sub

Resources