copy rows from 1 source worksheet to worksheets that match the worksheet name - vba

I have a master worksheet that contains data with many columns.
Next I have also created multiple worksheets from a list.
Now, I would like to copy the rows from the master worksheet to the respective worksheets if the value in the column matches against all the worksheet name, else copy to an 'NA' sheet.
Previously I could only think of hardcoding, but it is not feasible because the number of worksheets may increase to 50+, so I need some help on how I can achieve this..
'find rows of master sheet
With sh
LstR = .Cells(.Rows.Count, "C").End(xlUp).Row 'find last row of column C
Set rng = .Range("C3:C" & LstR) 'set range to loop
End With
'start the loop
'loop through, then loop through each C cell in template. if cell.value == worksheet name, copy to respective worksheet... elseif... else copy to NA
For Each c In rng.Cells
If c = "WEST" Then
c.EntireRow.Copy wsl1.Cells(wsl1.Rows.Count, "A").End(xlUp).Offset(1) 'copy row to first empty row in WEST
ElseIf c = "PKM" Then
c.EntireRow.Copy wsl2.Cells(wsl2.Rows.Count, "A").End(xlUp).Offset(1)
Else
c.EntireRow.Copy wsl7.Cells(wsl7.Rows.Count, "A").End(xlUp).Offset(1)
End If
Next c
Thanks to #user9770531, I was able to do what I want for the macro.
However, now I would like to make the macro more flexible.
For example, I have this additional table in another worksheet with
ColA_id and ColB_group
Instead of just matching checking worksheet name against the values in column C, I would like to do this:
if the master file column C matches "ColA_id", copy the data to respective "ColB_group" worksheets. Assuming ColB_group have been used to create the worksheet names.

Use code bellow - all subs in the same (standard) module
It searches Master.ColumnC for each sheet name (except Master and NA)
Uses AutoFilter for each sheet name, and copies all rows at once
All rows not assigned to a specific sheet will be copied to NA
It assumes sheet NA is already created, with Headers
Option Explicit
Const NA_WS As String = "NA" 'Create sheet "NA" if it doesn't exist
Public Sub DistributeData()
Const MASTER_WS As String = "Master"
Const MASTER_COL As String = "C" 'AutoFilter column in Master sheet
Dim wb As Workbook
Set wb = Application.ThisWorkbook
Dim ws As Worksheet, lr As Long, lc As Long, ur As Range, fCol As Range, done As Range
With wb.Worksheets(MASTER_WS)
lr = .Cells(.Rows.Count, MASTER_COL).End(xlUp).Row
lc = .Cells(1, .Columns.Count).End(xlToLeft).Column
Set ur = .Range(.Cells(3, 1), .Cells(lr, lc))
Set fCol = .Range(.Cells(2, MASTER_COL), .Cells(lr, MASTER_COL))
Set done = .Range(.Cells(1, MASTER_COL), .Cells(2, MASTER_COL))
End With
Application.ScreenUpdating = False
For Each ws In wb.Worksheets
If ws.Name <> MASTER_WS And ws.Name <> NA_WS Then
fCol.AutoFilter Field:=1, Criteria1:=ws.Name
If fCol.SpecialCells(xlCellTypeVisible).Cells.Count > 1 Then
UpdateWs ws, ur
Set done = Union(done, fCol.SpecialCells(xlCellTypeVisible))
End If
End If
Next
If wb.Worksheets(MASTER_WS).AutoFilterMode Then
fCol.AutoFilter
UpdateNA done, ur
End If
Application.ScreenUpdating = True
End Sub
Private Sub UpdateWs(ByRef ws As Worksheet, ByRef fromRng As Range)
fromRng.Copy
With ws.Cells(ws.Rows.Count, "A").End(xlUp).Offset(1, 0)
.PasteSpecial xlPasteAll
End With
ws.Activate
ws.Cells(1).Select
End Sub
Private Sub UpdateNA(ByRef done As Range, ByRef ur As Range)
done.EntireRow.Hidden = True
If ur.SpecialCells(xlCellTypeVisible).Cells.Count > 1 Then
UpdateWs ThisWorkbook.Worksheets(NA_WS), ur.SpecialCells(xlCellTypeVisible)
End If
done.EntireRow.Hidden = False
Application.CutCopyMode = False
ur.Parent.Activate
End Sub

Related

Match, Copy, and Add Values between Sheets

Looking to match values of column 1&2 of the same row on sheet2 to values of column 1&2 of the same row on sheet1. Then, copy entire row of sheet1 match onto next blank row of sheet3 + copy value of column 3+4 of same row sheet2 onto end of pasted row on sheet3.
IF Sheet2 Row First&Last (column1&2) Name match Sheet1 Row First&Last (column1&2)
THEN
Copy Sheet1 Row, paste to Sheet3 # next blank Row. Copy Sheet2 Row column 3+4 # end of previously pasted Row on Sheet3
Here is what I have so far, this doesn’t do anything right now but I have pieced it together from a few working macros to try and accomplish what I’m after. I haven’t been able to find examples of “Copy Sheet2 Row column 3+4 # end of previously pasted Row on Sheet3” so I just have a description on the line where I think the code should go.
Sub Match_Copy_AddValues()
Dim s1 As Worksheet, s2 As Worksheet, s3 As Worksheet
Application.ScreenUpdating = False
Application.EnableEvents = False
Set s1 = ActiveSheet 'List with dump data'
Set s2 = Sheets("Sheet 2") 'List of names to match, and additional information to be added'
Set s3 = Sheets("Sheet 3") 'Worksheet to copy rows of matched names'
Dim r As Long 'Current Row being matched?'
On Error GoTo fìn
Set ws2 = Sheets("Sheet 2")
With Sheets("Sheet 1")
r = Application.Max(.Cells(Rows.Count, 1).End(xlUp).Row, .Cells(Rows.Count, 2).End(xlUp).Row) 'Defines # of rows to apply If/Then to?'
For r = Application.Sum(v) To 2 Step -1 'Each time If/Then is ran, reduce # of rows to apply If/Then to?'
If CBool(Application.CountIfs(ws2.Columns(1), .Cells(r, 1).Value, ws2.Columns(2), .Cells(r, 2).Value)) Then _
.Rows(r).EntireRow.Copy s3.Cells(K, 1) 'Compares value in (r)row column 1 and 2, sheet2, to sheet1(activesheet), if equal THEN copies entire (r)row onto sheet3 # next empty row'
'take (r)row of match and copy value of column 3 and 4 sheet2 onto the end of previously pasted row on sheet3'
Next r
End With
fìn:
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
The code below doesn't do everything just the way your attempt suggests but I wrote it in very plain language so that you will surely be able to teak it back into your track where it has transgressed to where it shouldn't go.
Sub MatchNameAndInfo()
' 02 Aug 2017
Dim WsInput As Worksheet
Dim WsInfo As Worksheet
Dim WsOutput As Worksheet
Dim Rl As Long ' Last row of WsInput
Dim R As Long ' WsInput/WsInfo row counter
Dim Tmp1 As String, Tmp2 As String ' Clm 1 and Clm2 Input values
Dim Cmp1 As String, Cmp2 As String ' Clm 1 and Clm2 Info values
Set WsInput = Worksheets("Krang (Input)")
Set WsInfo = Worksheets("Krang (Info)")
Set WsOutput = Worksheets("Krang (Output)")
Application.ScreenUpdating = False
With WsInput
Rl = Application.Max(.Cells(.Rows.Count, 1).End(xlUp).Row, _
.Cells(.Rows.Count, 2).End(xlUp).Row)
If Rl < 2 Then Exit Sub
For R = 2 To Rl ' define each input row in turn
Tmp1 = Trim(.Cells(R, 1).Value)
Tmp2 = Trim(.Cells(R, 2).Value)
Cmp1 = Trim(WsInfo.Cells(R, 1).Value)
Cmp2 = Trim(WsInfo.Cells(R, 2).Value)
If StrComp(Tmp1 & Tmp2, Cmp1 & Cmp2, vbTextCompare) = 0 Then
TransferData R, WsInfo, WsOutput
End If
Next R
End With
Application.ScreenUpdating = True
End Sub
Private Function TransferData(R As Long, _
WsInfo As Worksheet, _
WsOut As Worksheet)
' 02 Aug 2017
Dim Rng As Range
Dim Rt As Long ' target row
With WsInfo
Set Rng = .Range(.Cells(R, 1), .Cells(R, 4))
End With
With WsOut
Rt = Application.Max(.Cells(.Rows.Count, 1).End(xlUp).Row + 1, 2)
Rng.Copy Destination:=.Cells(Rt, 1)
End With
End Function

Dynamically copy a worksheet multiple times and rename using VBA in Excel

I am trying to dynamically generate a custom number of worksheets based on a template that we use regularly in excel using VBA.
I have created an "Overview" page where we can input a range which will be used to name the new worksheets but then would like to use a hidden "Master" worksheet to generate the content of these new worksheets.
My code below currently generates the correct number of pages based on the range AND copies our master template page but does not combine the two and leaves them in separate pages.
Sub test()
Dim MyNames As Range, MyNewSheet As Range
Set masterSheet = ThisWorkbook.Worksheets("Master")
Set MyNames = Range("A1:A6").CurrentRegion ' load range into variable
For Each MyNewSheet In MyNames.Cells ' loop through cell range
masterSheet.Copy ThisWorkbook.Sheets(Sheets.Count) 'copy master template sheet
Sheets.Add.Name = MyNewSheet.Value
Next MyNewSheet
MyNames.Worksheet.Select ' move selection to original sheet
End Sub
As you can see, the code generates both the named (blank) worksheets AND copies my master worksheet which defaults to naming as "Master()".
So we just need to replace this line:
Sheets.Add.Name = MyNewSheet.Value
with this line:
ActiveSheet.Name = MyNewSheet.Value
Loop through the list and copy the sheet if the sheet does not already exist.
Sub CopyMaster()
Dim ws As Worksheet, sh As Worksheet
Dim Rws As Long, rng As Range, c As Range
Set sh = Sheets("Overview")
Set ws = Sheets("Master")
With sh
Rws = .Cells(Rows.Count, "A").End(xlUp).Row
Set rng = .Range(.Cells(1, 1), .Cells(Rws, 1))
End With
For Each c In rng.Cells
If WorksheetExists(c.Value) Then
MsgBox "Sheet " & c & " exists"
Else:
ws.Copy After:=Worksheets(Worksheets.Count)
Worksheets(Worksheets.Count).Name = c.Value
End If
Next c
End Sub
Function WorksheetExists(WSName As String) As Boolean
On Error Resume Next
WorksheetExists = Worksheets(WSName).Name = WSName
On Error GoTo 0
End Function

Compare cells in two different worksheets in a workbook and return a value to a next column

I have two excel sheets and I need to do a cell comparison.
Need a Macro solution.
Sheet 1 have column A-N and Sheet 2 have column A-S
I need to first check whether each column B values (B1:B2000) in sheet 1 available in Column F in Sheet 2.
If available then select the value in column A in shee2 and paste that in the Column O in sheet 1.
Sorry for the detail question without putting any effort.
Can't find anyway to enter to this question...
Give this a go,
Sub Button1_Click()
Dim ws As Worksheet, sh As Worksheet
Dim wsRws As Long, wsRng As Range, w As Range
Dim shRws As Long, shRng As Range, s As Range
Set ws = Sheets("Sheet1")
Set sh = Sheets("Sheet2")
With ws
wsRws = .Cells(Rows.Count, "B").End(xlUp).Row
Set wsRng = .Range(.Cells(1, "B"), .Cells(wsRws, "B"))
End With
With sh
shRws = .Cells(Rows.Count, "F").End(xlUp).Row
Set shRng = .Range(.Cells(1, "F"), .Cells(shRws, "F"))
End With
For Each w In wsRng
For Each s In shRng
If w = s Then w.Offset(0, -1) = s.Offset(0, -5)
Next s
Next w
End Sub

Copy cell content and paste it to another sheet multiple times

I am trying to copy value from two specific cells to specific cells in another sheet.
Problem is that I have many cells in first sheet and some of them are empty. Also paste is always 99 times, just range changes. Is there a loop to make everything more easy?
Here is my attempt
Sub copytry()
Worksheets("sheetI").Range("I17:J17").Copy _
Destination:=Worksheets("sheetII").Range("F1352:F1451")
Worksheets("sheetI").Range("I18:J18").Copy _
Destination:=Worksheets("sheetII").Range("F1452:F151")
End Sub
Practice using this,
Sub copytry()
Dim ws As Worksheet
Dim sh As Worksheet, lstrw As Long
Dim Rws As Long, Rng As Range, c As Range
Set ws = Worksheets("sheetI")
Set sh = Worksheets("sheetII")
With ws
Rws = .Cells(Rows.Count, "I").End(xlUp).Row
Set Rng = .Range(.Cells(17, "I"), .Cells(Rws, "I"))
For Each c In Rng.Cells
If c = "" Then c = "." 'Added to Code
lstrw = sh.Cells(Rows.Count, "A").End(xlUp).Row + 1
c.Range("A1:B1").Copy Destination:=sh.Range(sh.Cells(lstrw, 1), sh.Cells(lstrw + 99, 1))
Next c
End With
End Sub

Merging two spreadsheets after a button click

I have 2 spreadsheets:
main.xlsxm
drs.xlsx
I am trying to merge the two spreadsheets - this event will be launched after a button click on the main.xlsx spreadsheet (so the VBA code will reside on main.xlsx).
But I'm having difficulty writing my code, I originally tried using a variation of the following Excel formula but it was incredibly slow.
=IFERROR(INDEX([1.xlsx]Sheet1!$A:$A,SMALL(IF([1.xlsx]Sheet1!$B:$B=$A2,ROW([1.xlsx]Sheet1!$B:$B),99^99),COLUMN(A$1))),"")
I am trying to accomplish the following in VBA:
If column value E in drs.xlsx equals column value A in main.xlsx:
Then on the matching row in main.xlsx
Copy column value B in drs.xls to column value J in main.xlsx
If a second match is found (provided it is not the same as the first match):
Where column value E in drs.xlsx equals column value A in main.xlsx
Copy column value B in drs.xls to column value K in main.xlsx
If a third match is found (provided it is not the same as the first and second match):
Where column value E in drs.xlsx equals column value A in main.xlsx
Copy column value B in drs.xls to column value L in main.xlsx
If it happens for a fourth time then ignore…
How would I articulate this as VBA code?
This is my code so far (which prepares the spreadsheet ready):
Sub DRS_Update()
Dim wb As Workbook
Set wb = Workbooks.Open("C:\drs.xlsx")
With wb.Worksheets("Sheet1")
.AutoFilterMode = False
With .Range("A1:D1")
.AutoFilter Field:=1, Criteria1:="TW", Operator:=xlOr, Criteria2:="W"
.AutoFilter Field:=3, Criteria1:="Windows 7", Operator:=xlOr, Criteria2:="Windows XP"
.AutoFilter Field:=4, Criteria1:="Workstation-Windows"
End With
End With
End Sub
Try following code. I've commented it in details, but if you have some questions, feel free to ask in comments:)
Sub test()
Dim wb As Workbook
Dim sh1 As Worksheet
Dim sh2 As Worksheet
Dim user As Range
Dim lastrowDRS As Long, lastrowMAIN As Long
Dim rng As Range, res As Range
Dim k As Byte
Dim fAddr As String
Application.ScreenUpdating = False
'specify sheet name for main workbook
Set sh1 = ThisWorkbook.Worksheets("Sheet1")
'if drs is already opened
'Set wb = Workbooks("drs.xlsx")
'if drs not already opened
Set wb = Workbooks.Open("C:\drs.xlsx")
'specify sheet name for drs workbook
Set sh2 = wb.Worksheets("Sheet1")
With sh1
'find last row on column A in main wb
lastrowMAIN = .Cells(.Rows.Count, "A").End(xlUp).Row
'clear prev data in columns J:L
.Range("J1:L" & lastrowMAIN).ClearContents
End With
With sh2
.AutoFilterMode = False
'find last row on column A in drs wb
lastrowDRS = .Cells(.Rows.Count, "A").End(xlUp).Row
'apply filter
With .Range("A1:D1")
.AutoFilter Field:=1, Criteria1:="TW", Operator:=xlOr, Criteria2:="W"
.AutoFilter Field:=3, Criteria1:="Windows 7", Operator:=xlOr, Criteria2:="Windows XP"
.AutoFilter Field:=4, Criteria1:="Workstation-Windows"
End With
On Error Resume Next
'get only visible rows in column E
Set rng = .Range("E1:E" & lastrowDRS).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
'loop throught each user in main wb
For Each user In sh1.Range("A1:A" & lastrowMAIN)
'counter for finding entries
k = 0
'find first match
Set res = rng.Find(what:=user.Value, MatchCase:=False)
If Not res Is Nothing Then
'remember address of first match
fAddr = res.Address
Do
'user.Offset(, 9 + k) gives you column J for k=0, K for k=1, L for k=2
user.Offset(, 9 + k).Value = res.Offset(, -3).Value
'increment k
k = k + 1
'find next match
Set res = rng.FindNext(res)
'if nothing found exit stop searcing entries for current user
If res Is Nothing Then Exit Do
'if we already found 3 mathes, then stop search for current user
Loop While fAddr <> res.Address And k < 3
End If
Next user
End With
'close drs wb without saving changes
wb.Close saveChanges:=False
Set wb = Nothing
Application.ScreenUpdating = True
End Sub