Excel VBA - Copying data based on two parameters into another worksheet - excel

I'm trying to copy data from one sheet that contains raw data (over 30 columns and 300000 rows) into other sheets that split them into organized form.
In the DATA sheet I have repetitive ID's in column A, case numbers in column B which are unique and dates of cases in column J (multiple case numbers have the same date).
My goal is to copy case numbers into worksheets that are named with ID's from col A. In the target sheet I have single dates in col A (ex. from 3/01/2021 in A1 to 3/31/2021 in A31). The case numbers need to be transposed so they appear in columns next to each other but they have the same date.
I cannot use the ID's names in the code because it varies every month so I suppose that the code needs to work as some sort of comparison tool.

This should be close: it will add the sheets if they don't already exist.
Sub Copy_to_ID_sheet()
Dim impdate As Date, startDate As Date, daysToFillDown As Long
Dim finalrow As Long
Dim i As Long, numSheets As Long
Dim shipment As String, m
Dim ID As String, wsDane As Worksheet, dict As Object, ws As Worksheet
startDate = DateSerial(2021, 3, 1) 'adjust as needed
daysToFillDown = 31 '...and here
Set wsDane = ThisWorkbook.Sheets("Dane")
numSheets = ThisWorkbook.Worksheets.Count
Set dict = CreateObject("scripting.dictionary")
For i = 2 To wsDane.Cells(Rows.Count, "A").End(xlUp).Row
impdate = wsDane.Cells(i, 10).Value
shipment = wsDane.Cells(i, 2).Value
ID = Sheets("Dane").Cells(i, 1).Value
'already seen this ID and have a matching sheet?
If Not dict.exists(ID) Then
Set ws = Nothing
On Error Resume Next
Set ws = ThisWorkbook.Sheets(ID) 'does the sheet already exist?
On Error GoTo 0
If ws Is Nothing Then
'no existing sheet, so add a new one
Set ws = ThisWorkbook.Worksheets.Add( _
after:=ThisWorkbook.Worksheets(numSheets))
numSheets = numSheets + 1
ws.Name = ID
'add dates to the new sheet
With ws.Range("A1")
.NumberFormat = "mm/dd/yyyy" 'or whatever
.Value = startDate
.AutoFill Destination:=.Resize(daysToFillDown, 1)
End With
End If
Set dict(ID) = ws 'save in dictionary
Else
Set ws = dict(ID) 'get the existing sheet
End If
'match the date to the destination sheet
m = Application.Match(CLng(impdate), ws.Range("A1:A40"), 0)
If Not IsError(m) Then
'got a date match - add the shipment to the next available slot
ws.Cells(m, Columns.Count).End(xlToLeft).Offset(0, 1).Value = shipment
End If
Next i
End Sub

Related

How do I open another workbook with multiple sheets and find matches?

The goal is to use a reference Excel workbook as a database to find matching BoxID and then copy cells D to G in the same row. Finally pasting to another workbook that consists of a single worksheet.
I figured Xlookup would be easiest. In Excel it works but it doesn't in VBA.
Three main questions
How do I open another workbook and then reference all sheets or a specific range through all sheets in a dynamically named workbook to my current activeworkbook?
(e.g. sheets will be named freezer 23, freezer 43, fridge 190 in database.)
The rows of the sheets is variable but the columns stay the same.
Is there a way to do the above but if nothing is found to leave the cell blank?
Is there a way I could simplify this code?
On the left is the database which is going to be the external reference/where the data is coming from and on the right is the output sheet. Where I will be using Xlookup to search for the matching value. column "A" is where the search value will be and output to the next 4 cells.
Sub FreezerPulls()
Dim lastrow, j As Long
lastrow = Cells(Rows.Count, 1).End(xlUp).Row
Dim a As Integer
Dim list As Workbook
Dim frzdatabase As
Dim BoxIDlist, info, BoxIDdatabase, database, databasepath As String
databasepath = ("C:\Users\mikeo\Desktop\DataBaseStandard.xlsm")
Workbooks.Open ("C:\Users\mikeo\Desktop\DataBaseStandard.xlsm")
database = "DataBaseStandard.xlsm"
Set list = ThisWorkbook
list.Activate
Set BoxIDlist = Worksheets("Sheet1").Range("A" & Row.Count).End(xlUp).Row 'emphasized textthis doesn't work
Set BoxIDdatabase = Range("A2:A1500")
Set info = Range("D2:G1500")
a = Application.Worksheets.Count
End Sub
You could do something like this, using Match(). See comments in code
Sub FreezerPulls()
Const DB_PATH As String = "C:\Users\mikeo\Desktop\DataBaseStandard.xlsm"
Dim wbData As Workbook, ws As Worksheet, rw As Range, id, m
Set wbData = Workbooks.Open(DB_PATH, ReadOnly:=True) 'get a reference to the data workbook
'loop each row in the lookup table
For Each rw In ThisWorkbook.Sheets("Sheet1").Range("A17:F40").Rows
id = rw.Cells(1).Value 'Box ID to find
If Len(id) > 0 Then 'any value to look up?
For Each ws In wbData.Worksheets 'loop all worksheets in data workbook
m = Application.Match(id, ws.Columns("A"), 0) 'any match on this sheet ColA?
If Not IsError(m) Then 'no error = match was made on row m
rw.Cells(3).Value = ws.Name 'add freezer name
rw.Cells(4).Resize(1, 3).Value = _
ws.Cells(m, 5).Resize(1, 3).Value 'copy segment, rackID, position
Exit For 'done searching (assumes box id's are unique)
End If
Next ws
End If
Next rw
wbData.Close False
End Sub

Loop through filtered list of cells to check if value appears in another column then copy/paste

Need some help with my macro. What I need is to loop through a filterable list of IDs in Sheet2 and match them to where the ID is contained in Column 16 on Sheet 1. Then copy over the whole matched row in Sheet1 over to a Sheet3.
Here's what Sheet2 looks like, generally (filtering by things like Status, etc.):
ID
Summary
Created On
Status
1234567
Text
Date
Done
2345678
Text
Date
In Progress
And Sheet1 (*note the ID -> ID2 match):
ID
Summary
Created On
Status
ID2
#######
Text
Date
Done
1234567, #######, #######
#######
Text
Date
In Progress
#######, 2345678
I used this thread here (Code needed to loop through column range, check if value exists and then copy cells) for a process of pairing in the same workbook that does not need to be filtered, and it seems to work just fine. However, my code in this instance is not pairing the amount of rows correctly nor is it pairing with the correct IDs either. I think something may be off with the pairing process with filtering in the mix?
My code so far:
Public Sub PairingBackTEST()
Dim WS As Worksheet
Set WS = Sheets("Sheet1")
'Clears Sheet 3
Sheets("Sheet3").Activate
Sheets("Sheet3").Cells.Clear
' Get the number of used rows for each sheet
Dim RESULTBlocked As Integer, Blockers As Integer
RESULTBlocked = WS.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Cells.Count
Debug.Print RESULTBlocked
Blockers = Worksheets(1).Cells(1048576, 1).End(xlUp).Row
Debug.Print Blockers
RESULTBlockers = Worksheets(4).Cells(1048576, 1).End(xlUp).Row
'Set date/time format for Created On and Due Date columns
Sheets("Sheet3").Activate
Sheets("Sheet3").Columns("H:H").Select
Selection.NumberFormat = "[$-en-US]m/d/yy h:mm AM/PM;#"
Sheets("Sheet3").Columns("I:I").Select
Selection.NumberFormat
'Pairing
With Worksheets(1)
'Loop through Sheet2
For i = 1 To Blockers
'Loop through Sheet1
For j = 1 To RESULTBlocked
If InStr(1, .Cells(i, 16), WS.Cells(j, 1), vbBinaryCompare) > 0 Then
' If a match is found:
RESULTBlockers = RESULTBlockers + 1
For k = 1 To 17 'How ever many columns there are
Sheets("Sheet3").Cells(RESULTBlockers, k) = .Cells(i, k)
Next
Exit For
Else
End If
Next j
Next i
End With
'Prepare headers on RESULT Blocked
Sheets("Sheet1").Rows(1).Copy
Sheets("Sheet3").Range("A1").PasteSpecial
I'd maybe try an approach like this:
Public Sub PairingBackTEST()
Dim wb As Workbook
Dim wsList As Worksheet, wsCheck As Worksheet, wsResults As Worksheet
Dim lrList As Long, lrCheck As Long, c As Range, cDest As Range, id, m
'use workbook/worksheet variables for clarity, and to avoid repetition...
Set wb = ThisWorkbook
Set wsList = wb.Worksheets("Sheet2")
Set wsCheck = wb.Worksheets("Sheet1")
Set wsResults = wb.Worksheets("Sheet3")
'no need for activate/select here
With wsResults
.Cells.Clear
.Columns("H:H").NumberFormat = "[$-en-US]m/d/yy h:mm AM/PM;#"
'.Columns("I:I").NumberFormat = ??? this is missing in your posted code
wsCheck.Rows(1).Copy .Range("A1") 'copy headers
End With
Set cDest = wsResults.Range("A2") 'first destination row on result sheet
For Each c In wsList.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Cells
id = c.Value
'you can use match in place of looping as long as there's only one row to find
m = Application.Match("*" & id & "*", wsCheck.Columns(16), 0)
If Not IsError(m) Then
If m > 1 Then 'avoid matching on header...
cDest.Resize(1, 17).Value = wsCheck.Cells(m, 1).Resize(1, 17).Value
Set cDest = cDest.Offset(1, 0) 'next row on results sheet
End If
End If
Next c
End Sub

How to copy and paste unique data according to date, when the dates are repeated?

I am trying to copy data from one sheet to another according to matching dates and so far I can do this but the problem is that the most recent data for a corresponding date over writes all other data for the same date.
E.G.
I want to copy data from sheet 2 column 1 (based on the date in column 2)
I want to paste this data into sheet 1 column 2 (Based on the date in column 1)
As can be seen, only the last number from sheet 2 column 1 which corresponds to the respective date is pasted into ALL corresponding dates in sheet 1 column 2.
Instead, if there are two dates, I want two different numbers( from sheet 2 column 1 ) to be pasted into sheet 1 column 2.
My original code is as follows:
Sub Macroturnip()
'
' Macroturnip Macro
'
Dim Row As Double 'row is the row variable for the destination spreadsheet
Dim i As Date
Dim x As Long 'x is the row variable for the source spreadsheet
For Row = 1 To 825
i = Sheets("1").Cells(Row, 1)
If i <> DateSerial(1900, 1, 0) Then
'DateSerial(1900, 1, 0) --> this is the default for no data in the field, i.e. i want to skip these
For x = 2 To 450
If Sheets("2").Cells(x, 2) = Sheets("1").Cells(Row, 1) Then
Sheets("2").Select
Cells(x, 1).Select
Selection.Copy
Sheets("1").Select
Cells(Row, 2).Select
ActiveSheet.Paste
End If
Next x
End If
Next Row
End Sub
Is good practice to avoid using variable names that are already representing something in code, i.e.: Row.
Row number should a be a integer/long type
You should declare and assign your worksheets to variables
Most code in VBA can be written without using .Select, though sometimes you might need it, this is not one of those times... and you should avoid at all cost using it in a nested loop. For ex:
Sheets("2").Select
Cells(x, 1).Select
Selection.Copy
Can be easily rewritten as such:
Sheets("2").Cells(x, 1).Copy
This might need some better logic, but based on your screenshots, it works:
Sub Macroturnip()
'
' Macroturnip Macro
'
Dim wsDst As Worksheet: Set wsDst = ActiveWorkbook.Sheets("1")
Dim lRowDst As Long: lRowDst = wsDst.Cells(wsDst.Rows.Count, 1).End(xlUp).Row
Dim wsSrc As Worksheet: Set wsSrc = ActiveWorkbook.Sheets("2")
Dim lRowSrc As Long: lRowSrc = wsSrc.Cells(wsSrc.Rows.Count, 1).End(xlUp).Row
Dim rngFind As Range
Dim Rs As Long, Rd As Long 'row is the row variable for the destination spreadsheet
For Rd = 2 To lRowDst
If wsDst.Cells(Rd, 1) <> "" Then
'DateSerial(1900, 1, 0) --> this is the default for no data in the field, i.e. i want to skip these
For Rs = 2 To lRowSrc
If wsDst.Cells(Rd, 1) = wsSrc.Cells(Rs, 2) Then
Set rngFind = wsDst.Range("B2:B" & Rd).Find(wsSrc.Cells(Rs, 1), Lookat:=xlWhole)
If rngFind Is Nothing Then
wsDst.Cells(Rd, 2) = wsSrc.Cells(Rs, 1).Value
Exit For 'No need to keep checking, move on
End If
Set rngFind = Nothing
End If
Next Rs
End If
Next Rd
End Sub
PS: I've assumed that by Sheets("2") you actually referred to a sheet named 2, and not Sheet2 or Sheets(2) which though look similar, are not the same thing.

Excel Formula to reference Master Sheet

I currently have a master excel sheet that has the names of about 20 different sales people, and a new row is created, with the salesmen name in column A, whenever they make a sale. But, I now want this data to be available to the salesmen, but I want only them to only be able to view their info, not everyones. So, I am going to create 20 different individual files, one for each salesman.
Is there a formula that I can use for these 20 different spreadsheets to update for that specific salesmen every time I update the master sheet?
You could create workbooks from a Column (Looping from row 1 to x) based on unique values.
So for each unique salesmen in Column A you create a new workbook. Then you only need to use your current Master file, and do whatever you want in that file. When you want to send a sheet to a sales person, you execute the code and Excel will copy all rows that belongs to the specific sales man and create 20 individual sheets for you which you can send.
Process:
I have a file in a folder, which I have all my main data.
The main data looks like this, and the new workbooks will be named after Column A. It will only create workbook for unique names.
After running the macro it has create the following 5 new workbooks.
This is how Workbook "Anne - 10-27-18,14.24.47.xlsx" looks like:
This is how Workbook "Belle- 10-27-18,14.24.47.xlsx" looks like:
I used the following code and only modified to make it dynamic of the unique list column. All credit to J. Fox at SO
VBA Code:
Option Explicit
Sub ExportByName()
'Source and Credit: https://stackoverflow.com/questions/46368771/how-to-create-a-new-workbook-for-each-unique-value-in-a-column
Dim unique(1000) As String 'How many unique values we can store
Dim wb(1000) As Workbook
Dim ws As Worksheet
Dim x As Long, y As Long, ct As Long, uCol As Long, ColName As Long
Dim StaticDate As Date
On Error GoTo ErrHandler
Application.ScreenUpdating = True
Application.Calculation = xlCalculationManual
'Your main worksheet
Set ws = ActiveWorkbook.Sheets("Sheet1")
'Column Where Unique Names are
ColName = 1
uCol = 12 'End column of data in MainFile
ct = 0
'get a unique list of users
For x = 2 To ws.Cells(ws.Rows.Count, ColName).End(xlUp).Row
If CountIfArray(ActiveSheet.Cells(x, ColName), unique()) = 0 Then
unique(ct) = ActiveSheet.Cells(x, ColName).Text
ct = ct + 1
End If
Next x
StaticDate = Now() 'This create the same timestamp for all the new workbooks
'loop through the unique list
For x = 0 To ws.Cells(ws.Rows.Count, ColName).End(xlUp).Row - 1
If unique(x) <> "" Then
'add workbook
Set wb(x) = Workbooks.Add
'copy header row
ws.Range(ws.Cells(1, 1), ws.Cells(1, uCol)).Copy wb(x).Sheets(1).Cells(1, 1)
'loop to find matching items in ws and copy over
For y = 2 To ws.Cells(ws.Rows.Count, ColName).End(xlUp).Row
If ws.Cells(y, ColName) = unique(x) Then
'copy full formula over
'ws.Range(ws.Cells(y, 1), ws.Cells(y, uCol)).Copy wb(x).Sheets(1).Cells(WorksheetFunction.CountA(wb(x).Sheets(1).Columns(uCol)) + 1, 1)
'to copy and paste values
ws.Range(ws.Cells(y, 1), ws.Cells(y, uCol)).Copy
wb(x).Sheets(1).Cells(WorksheetFunction.CountA(wb(x).Sheets(1).Columns(uCol)) + 1, 1).PasteSpecial (xlPasteValues)
End If
Next y
'autofit
wb(x).Sheets(1).Columns.AutoFit
'save when done
wb(x).SaveAs ThisWorkbook.Path & "\" & unique(x) & " - " & Format(StaticDate, "mm-dd-yy, hh.mm.ss") & ".xlsx"
wb(x).Close SaveChanges:=True
Else
'once reaching blank parts of the array, quit loop
Exit For
End If
Next x
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
ErrHandler:
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Public Function CountIfArray(lookup_value As String, lookup_array As Variant)
CountIfArray = Application.Count(Application.Match(lookup_value, lookup_array, 0))
End Function

How to Search Specific Column In Each Worksheet of Excel

I have an excel document with over 50 worksheets all with a similar naming convention.
As this will be so unfriendly for users to navigate to, I wrote a VBA macro which creates a worksheet called summary with the list of all the worksheets hyperlinked in a tabular form with Sheet A B and C as the Column and Sheet 1 and 2 as rows.
Now I am trying to go through each row of a specific column in Sheet 1 and Sheet 2 and look for any reference to SheetB, SheetC and SheetD and for each reference found and I want to mark that creating a matrix.
I am not sure how to achieve this. Any assistance will be much appreciated.
I have managed to search Sheet 1 and 2 for any reference to SheetB as shown below but I am not sure how to update the corresponding cell in my summary sheet.
Function findWord(word As String, wSheet As String) As Boolean
Dim LastRow As Long
Dim i As Long
LastRow = Worksheets(wSheet).Cells(Rows.Count, "D").End(xlUp).Row
For i = LastRow To 1 Step -1
If Worksheets(wSheet).Range("D" & i).Value = word Then
findWord = True
Exit Function
End If
Next i
End Function
For Each wsSheet In wbBook.Worksheets
If (wsSheet.Name <> wsActive.Name) And (Left(wsSheet.Name, 4) <> "fact") Then
For i = 2 To lastColumn
MsgBox wsSheet.Name
If findWord(columnNames(counter2), wsSheet.Name) Then
'Update summary sheet
End If
counter = counter2 + 1
Next i
End If
Next wsSheet
If the result in "Summary sheet" you are looking for is similar to this :
Then you can use something like this (read the comments inside the code for explanations)
Sub MarkReferencesToSheets()
Dim wsSummary As Worksheet 'sheet with summary table matrix
Dim wsSheetRow As Worksheet 'sheets in which we will search references to other sheets
Dim strSheetColumnName As String 'name of the reference we are looking for
Dim intSheetRow As Integer 'for loop purposes
Dim intSheetColumn As Integer 'for loop purposes
Set wsSummary = Sheets("Summary")
For intSheetRow = 2 To 3 'change to suit; headers for rows in summary sheet
Set wsSheetRow = Worksheets(wsSummary.Cells(intSheetRow, 1).Value)
For intSheetColumn = 2 To 4 'change to suit; headers for columns in summary sheet
strSheetColumnName = wsSummary.Cells(1, intSheetColumn) 'name of sheet we are looking for
If Not wsSheetRow.Columns(4).Find(strSheetColumnName) Is Nothing Then 'look only in column "D", or 4
wsSummary.Cells(intSheetRow, intSheetColumn) = "X" ' if we found it, mark it
Else
'if you want something else in the cell when reference is not found, put it here
End If
Next intSheetColumn
Next intSheetRow
End Sub

Resources