Obtain a list of information Pertaining to a Specific Month - excel

I have trouble running this script to obtain Summary information for a specific month. I am explaining below the details of my workbook.
Tab 1 called "Schedule"
Tab 2 called "Results"
Tab 3 called "Sheet3"
I would like to obtain info from column C (Summary) in tab1 for the month of July. I am entering the month in tab2 and would like to run the macro and obtain all the results pertaining to the month of July.
Sub schedule()
Dim sch As Workbook
Dim schTot As Worksheet
Dim schRes As Worksheet
Dim i As Long
Dim j As Long
Let sch = Thisworkbook
Let schRes = sch.Worksheets("Results")
Let schTot = sch.Worksheets("Schedule")
For i = 1 To schTot.Range("A1").End(xlDown)
For j = 3 To schRes.Range("B3").End(xlDown)
If schTot.Cells(i, 1).Value = schRes.Cells(1, 2).Value Then
If schRes.Cells(j, 1).Value = "" Then
schTot.Rows(i).Copy
schRes.Cells(j, 1).Paste
Application.CutCopyMode = False
'Exit For
End If
End If
Next j
Next i
End Sub

Try this:
Option Explicit
Sub schedule()
Dim sch As Workbook
Dim schTot As Worksheet
Dim schRes As Worksheet
Dim i As Long
Dim j As Long
Dim strMonth As String
With ThisWorkbook
Set schRes = .Worksheets("Results")
Set schTot = .Worksheets("Schedule")
End With
schRes.Range("A3:C" & schRes.Cells(3, 1).End(xlDown).Row).ClearContents
strMonth = schRes.Cells(1, 2).Value
i = 2
j = 3
With schTot
Do Until .Cells(i, 1).Value = ""
If .Cells(i, 1).Value = strMonth Then
schRes.Range("A" & j & ":C" & j).Value = .Range("A" & i & ":C" & i).Value
j = j + 1
End If
i = i + 1
Loop
End With
End Sub

For your code, you just need to change following things to get it run:
-use "Set" instead of "Let"
Set sch = Thisworkbook
Set schRes = sch.Worksheets("Results")
Set schTot = sch.Worksheets("Schedule")
-return row's number in for loop condition
For i = 1 To schTot.Range("A1").End(xlDown).Row
For j = 3 To schRes.Range("B3").End(xlDown).Row
Then your code will be ok to run, but if your B3 cell in Results worksheet don't have value or following cells(i.e. B4,B5,B6...) doesn't have vale, your code will run infinitely and crush eventually.
Also, you copy a entire row in loop every single time which contain unnecessary cells. This will horribly slow down your code.
To speed up the code, I recommend to use auto filter to solve the problem:
Sub sechedule()
Dim sch As Workbook: Set sch = ThisWorkbook
Dim schTot As Worksheet: Set scTot = sch.Worksheets("Schedule")
Dim schRes As Worksheet: Set schRes = sch.Worksheets("Results")
Dim month As String
month = Range("B1").Value 'The month you inputted in Results worksheet
'I suppose you want to paste the result to Results worksheet starting from Cell A3, so the contents will be cleared first each time if somethings are in the result area:
If Range("A3").Value = "" Then Range("A3:C" & Range("A" & Rows.Count).End(xlUp).Row).ClearContents
With schTot
.Activate
.Range("A:C").AutoFilter Field:=1, Criterial:=month 'Choose data for specific month with auto filter
.Range("A2:C" & Range("A" & Rows.Count).End(xlUp).Row).SpecialCells(xlCellTypeVisible).Copy Destination:=schRes.Range("A3") '<--You can change the paste destination here
.ShowAllData
.Range("A:C").AutoFilter 'Cancel auto filter
End With
schRes.Activate
End Sub

Related

Split an excel file based on column values

I have an excel data file with 2 sheet named "Data" and "GL Data"
Both these sheets contain a column called "Leader" which has 4 different names - say D1, D2, D3 and D4
I have 4 other workbooks named - Data_D1, Data_D2, Data_D3 and Data_D4 each with 2 sheet named "Data" and "GL Data".
I need to put each Leader's data in their sheet. That is :
1- Apply a filter on Leader column in sheet "data" and select D1
2- copy the filtered rows to "data" sheet of workbook Data_D1
3- Apply a filter on Leader column in sheet "GL data" and select D1
4- copy the filtered rows to "GL data" sheet of workbook Data_D1
5- Repeat the above steps for D2, D3 and D4
I am wondering if there's a better way of doing this quickly. I searched online but couldn't find anything. Any help would be useful. Thank you.
EDIT: Wrote some VBA code (see answer below). Facing some problem with its working.
I wrote the following code but I can't seem to figure out why the second time the second loop runs, the filtered values are not copied. Do I need to reset the filter or something ? The first loop seems to be working.
Sub foo()
Dim yr As String
Dim lastPd As String
Dim thisPd As String
Dim x As Workbook
Dim y As Workbook
Dim vals As Variant
Dim lr As Long
Dim strNames(1 To 4) As String
Dim fileNames(1 To 4) As String
Dim path As String
Dim sourceFileName As String
Dim i As Integer
Dim j As Integer
yr = "2022"
sourceFileName = "sourcefilename.xlsx"
path = "path to the file"
'populate the arrays
strNames(1) = "D1"
strNames(2) = "D2"
strNames(3) = "D3"
strNames(4) = "D4"
fileNames(1) = "Data_D1.xlsx"
fileNames(2) = "Data_D2.xlsx"
fileNames(3) = "Data_D3.xlsx"
fileNames(4) = "Data_D4.xlsx"
For i = 1 To 4
Set x = Workbooks.Open(path & sourceFileName)
x.Activate
Sheets("DATA").Activate
lr = Cells(Rows.Count, 1).End(xlUp).Row
Set y = Workbooks.Open(path & fileNames(i))
x.Sheets("DATA").Range("A1:N" & lr).AutoFilter Field:=14, Criteria1:=strNames(i)
x.Sheets("DATA").Range("A1:L" & lr).SpecialCells(xlCellTypeVisible).Copy
y.Sheets("DATA").Cells(1, 1).PasteSpecial
Next i
For j = 1 To 4
Set x = Workbooks.Open(path & sourceFileName)
x.Activate
Sheets("GL Data").Activate
lr = Cells(Rows.Count, 1).End(xlUp).Row
Set y = Workbooks.Open(path & fileNames(j))
x.Sheets("GL Data").Range("A1:P" & lr).AutoFilter Field:=15, Criteria1:=strNames(j)
x.Sheets("GL Data").Range("A1:L" & lr).SpecialCells(xlCellTypeVisible).Copy
y.Sheets("GL Data").Cells(1, 1).PasteSpecial
Next j
End Sub
I have some remarks about your VBA code :
1- The sourcefilename.xlsx file must be opened one. So, the opening
of the file has to be outside the two Next loop (i and j).
2- The filter (Autofilter) must be disabled (turned to False) before each
change of criterion.
3- The copy/paste operation can be done in same
line, like this source.Copy destination
4- Try to add one row (first)
on DATA & GL Data sheets of sourcefilename.xlsx. Because, when you
filter the first line is considered as header, so it's not filtered.
5- In the header of the VBA module (the first line). you have to put
the syntax: Option Base 1 so that the first element has the index
= 1 (and not 0).
I made some changes to your code. It does run perfectly :)
Sub foo()
Dim yr As String
Dim lastPd As String
Dim thisPd As String
Dim x As Workbook
Dim y As Workbook
Dim vals As Variant
Dim lr As Long
Dim strNames(1 To 4) As String
Dim fileNames(1 To 4) As String
Dim path As String
Dim sourceFileName As String
Dim i As Integer
Dim j As Integer
yr = "2022"
sourceFileName = "sourcefilename.xlsx"
path = "path to the file"
'populate the arrays
strNames(1) = "D1"
strNames(2) = "D2"
strNames(3) = "D3"
strNames(4) = "D4"
fileNames(1) = "Data_D1.xlsx"
fileNames(2) = "Data_D2.xlsx"
fileNames(3) = "Data_D3.xlsx"
fileNames(4) = "Data_D4.xlsx"
'Open the Main workbook
Workbooks.Open Filename:=Path & sourceFileName
Set x = ActiveWorkbook
For i = 1 To 4
x.Sheets("DATA").Activate
x.Sheets("DATA").AutoFilterMode = False
lr = Cells(Rows.Count, 1).End(xlUp).Row
Set Y = Workbooks.Open(Path & fileNames(i))
x.Sheets("DATA").Range("A1:N" & lr).AutoFilter Field:=14, Criteria1:=strNames(i)
x.Sheets("DATA").Range("A2:L" & lr).SpecialCells(xlCellTypeVisible).Copy Y.Sheets("DATA").Cells(1, 1)
Range("A1").Select
Next i
x.Sheets("DATA").AutoFilterMode = False
For j = 1 To 4
x.Activate
x.Sheets("GL Data").Activate
x.Sheets("GL Data").AutoFilterMode = False
lr = Cells(Rows.Count, 1).End(xlUp).Row
Set Y = Workbooks(fileNames(j))
x.Sheets("GL Data").Range("A1:P" & lr).AutoFilter Field:=15, Criteria1:=strNames(j)
x.Sheets("GL Data").Range("A2:L" & lr).SpecialCells(xlCellTypeVisible).Copy Y.Sheets("GL Data").Cells(1, 1)
Range("A1").Select
Next j
x.Sheets("GL Data").AutoFilterMode = False
End Sub

Loop input values in another sheet through cell reference then Copy formula value and paste it to another sheet using vba

[
I am working on two sheets
Sheets("UPDATER") = where input data is placed (more than 700 rows) and where data needs to be copied
Sheets("Historical_vol) = where i have kept the formulas (C9:N9) and input the records from updater sheet in cell A9 of historical_vol sheet.
The aim is to get the values of each of Underlyings pasted in sheets("updater").columns("AB") but the values get calculated from sheets("Historical_vol").column(C9:F9) then paste these values in sheet("updater")on each row starts from cell AD4.
Sub historical_vol()
Dim i As Long
Dim a As Worksheet
Dim b As Worksheet
lr = Worksheets("UPDATER").Cells(Rows.count, "AB").End(xlUp).Row
Set a = Worksheets("UPDATER")
Set b = Worksheets("Historical_vol")
For i = 4 To lr
b.Range("A9").value = a.Range("AB4" & i).value
'b.Range("C9":F9").Calculate
Application.Wait (Now + TimeValue("00:00:02"))
b.Range("C9:F9").Copy
NextRow = Cells(Rows.count, "AD").End(xlUp).Row + 1
Cells(NextRow, "AD").Select
ActiveSheet.Paste
Next i
End Sub
At first I notice the line b.Range("A9").value = a.Range("AB4" & i).value should be b.Range("A9").value = a.Range("AB" & i).value
As I see you are using Application.Wait, I assume it is for the calculation. So, I suggest using xlCalculationManual calculation and resetting it to auto once done as below.
Sub historical_vol()
Application.ScreenUpdating = True
'This will help to watch the status bar update
Application.Calculation = xlCalculationManual
Dim wb As Workbook, uPd As Worksheet, hV As Worksheet
Dim lr As Long, cl As Range
Set wb = ThisWorkbook
Set uPd = wb.Sheets("UPDATER")
Set hV = wb.Sheets("Historical_vol")
lr = uPd.Cells(Rows.Count, "AB").End(xlUp).Row
i = 0
For Each cl In uPd.Range("AB4:AB" & lr)
hV.Range("A9").Value = cl.Value
hV.Calculate
cl.Offset(0, 2).Resize(1, 4).Value = hV.Range("C9:F9").Value
i = i + 1
Application.StatusBar = i '& " / " & lr - 3
'View on status bar number of records completed out of total records (lr-3)
Next
Application.Calculation = xlCalculationAutomatic
End Sub

Search words in two columns and copy to another sheet

In my problem:
First, I need to find "Unit Name" in Column B.
If it found "Unit Name" it should look for "First Name:" in Column D and copy 5 cell right. ("Obama" in I10)
Paste the name "Obama" to Unit Name sheet. (Paste "Obama" to Sheet "1" A1)
I am new in coding therefore i don't know too much about it. I tried with some codes but it is not efficient.
Here is an image to show my problem.
Sub Test()
Dim i As Integer
Dim m As Integer
Dim n As Integer
Dim z As Integer
For i = 1000 To 1 Step -1
If Range("B" & i).Value = "Unit Name" Then
m = 2
m = i + 1
n = i - 18
If Range("D" & n).Value = "First Name:" Then
m = Range("B" & m).Value + 1
Range("H" & n).Copy
Sheets(m).Range("B7").PasteSpecial xlPasteValues
End If
End If
Next i
End Sub
You don't need all those integer variables, you can use a few Range variables instead:
Sub find_name()
Dim mainWS As Worksheet, altWS As Worksheet
Dim unitCel As Range, fNameCell As Range
Set mainWS = Worksheets("Sheet2") 'CHANGE AS NEEDED
Set altWS = Worksheets("Sheet1")
With mainWS
Set unitCel = .Range("B:B").Find(What:="Unit Name")
If Not unitCel Is Nothing Then
Set fNameCell = .Range("D:D").Find(What:="First Name:").Offset(0, 5)
altWS.Range("A1").Value = fNameCell.Value
End If
End With
End Sub
May need to tweak this, depending on where your data is. I am assuming "Obama" could be any text, that is three columns right of column D, where "First Name:" is found.
Sub Shift_Over5()
Dim i As Long
'Sheet name should be a string
Dim SheetName As String
Dim FirstName As Range
Dim UnitName As Range
'Dim l As Byte --> I changed it to lUnitSheetLastrow, because we need to copy the data from sheet1 to sheet 1,2...
' then you need to check the last row of unit sheet and write data to the last row + 1.
Dim lUnitSheetLastrow As Long
Dim FirstMatch As Variant
Dim Start
Start = VBA.Timer
For i = 1 To 40000 Step 1
'For clear code and easy to follow, you need to mention the sheet you want to interact
'Here i use 'Activesheet', i assume that the current sheet is sheet1
If ActiveSheet.Range("A" & i).Value = "Unit Name" Then
' i think we dont need this code line, because we identified the cell in column B has value is "Unit Name"
'Set UnitName = Range("A:A").Find(what:="Unit Name")
' Here you dont need to use Offset
'SheetName = UnitName.Offset(1, 0).Value
SheetName = ActiveSheet.Range("A" & (i + 1)).Value
' Find "First Name" in 20 rows in column E.
' What happen if i<20, the nextline will show the error, because the minimum row is 1
If i < 40 Then
Set FirstName = ActiveSheet.Range("D1" & ":D" & i).Find(what:="First Name:")
Else
Set FirstName = ActiveSheet.Range("D" & i & ":D" & (i + 40)).Find(what:="First Name")
End If
' make sure the SheetName is not empty and Unit sheet is existing in you workbook then copy the first name to unit sheet
If SheetName <> "" And CheckWorkSheetAvailable(SheetName) Then
' Check the first name is not nothing
If Not FirstName Is Nothing Then
'Check if the cell B7 in unit sheet empty or not
If Worksheets(SheetName).Range("H7").Value = "" Then
'if empty, write to B7
Worksheets(SheetName).Range("H7").Value = FirstName.Offset(1, 0).Value
Else
'else, Find the lastrow in column D of unit sheet
lUnitSheetLastrow = Worksheets(SheetName).Cells(Worksheets(SheetName).Rows.Count, 1).End(xlUp).Row
'Write data to lastrow +1
Worksheets(SheetName).Range("A" & (lUnitSheetLastrow + 1)).Value = FirstName.Offset(, 1).Value
End If
End If
End If
'You forgot to put end if here
End If
Next i
Debug.Print Round(Timer - Start, 3)
End Sub
Function CheckWorkSheetAvailable(SheetName As String) As Boolean
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
If ws.Name = SheetName Then
CheckWorkSheetAvailable = True
Exit For
End If
Next
End Function
thank you everyone I found the answer.

Copying values from one sheet based on condition to another workbook

I've written some code that assigns each item in a list a code based on row #. What I want to do from there is choose a copy all information from each row that corresponds with a chosen code, then paste it to another workbook. I've been having some trouble. Here's the code:
Sub LSHP_Distribute()
Dim wbLSHP As Workbook
Dim wsLSHP As Worksheet
Dim CodeRange As Range
Dim FirstRow As Long
Dim LastRow As Long
Dim wbTEST As Workbook
Set wbLSHP = ActiveWorkbook
Set wsLSHP = wbLSHP.Sheets("Sheet1")
'Generate codes for newly added items
Application.ScreenUpdating = False
'Turn off screen updating
With wsLSHP
FirstRow = .Range("F3").End(xlDown).Row + 1
LastRow = .Range("B6", .Range("B6").End(xlDown)).Rows.Count + 5
Set CodeRange = .Range("$F$" & FirstRow, "$F$" & LastRow)
End With
For Each cell In CodeRange
If cell = "" Then
If cell.Row Mod 3 = 0 Then
cell.Value = "1"
ElseIf cell.Row Mod 3 = 1 Then
cell.Value = "2"
ElseIf cell.Row Mod 3 = 2 Then
cell.Value = "3"
Else
End If
End If
Next cell
'Open Spreadsheets to Distribute Items
Dim PasteRow As Long
Dim i As Integer
Set wbTEST = Workbooks.Open(Filename:="V:\Test.xlsx")
PasteRow = wbTEST.Sheets("Sheet1").Range("B6").End(xlDown).Row + 1
Below is where I'm having the problem
wbLSHP.Activate
For Each cell In CodeRange
If cell = "1" Then
Range(ActiveCell.Offset(0, -5), ActiveCell.Offset(0, 20)).Select
Selection.Copy
wbTEST.Sheets("Sheet1").Cells(PasteRow, 1).PasteSpecial xlPasteValues
PasteRow = PasteRow + 1
Else
End If
Next cell
End Sub
First problem is the For loop isn't copying the correct range in "CodeRange", the second problem is it only copies once before I get an Automation Error. Let me know if you have any questions, or know of a more efficient way to write this code.
Thanks so much for your time!
Your range is defined to Start in F3 and end in BSomething, but you store to CodeRange only the F column.
Set CodeRange = .Range("$F$" & FirstRow, "$F$" & LastRow)
Try using:
Set CodeRange = .Range("$B$" & FirstRow, "$F$" & LastRow)
I suggest instead of Copy and Paste, assign the value to a variable and put the value of the variable on wbTEST.

Excel 2007 VBA runtime error when selecting worksheet with variable

I've been recently getting back into VBA and have been testing out a concept of Adding Worksheets by the string in a variable. I've been able to get the worksheets to add successfully and the last two lines of my code are simply to select the sheet name of the variable and then select cell A + the row number that is stored in another variable
In Sheet1, Column A, starting in A1, I have a list of 8 different names that cycles through:
Bob
Jeff
Max
Steve
Rosie
Pippa
Penelope
Rob
I am expecting the macro to end on Sheet "Rob" with cell A9 selected, however i get a runtime 1004 error
I have stepped through the code and it is selecting the sheet correctly with the variable, but when it tries to select row A9, the error presents
My code is below:
Sub Add_worksheets()
Dim sheetName As String
Dim rownum As Integer
rownum = 1
Range("A" & rownum).Select
sheetName = ActiveCell.Value
Do Until Range("A" & rownum).Value = ""
Range("A" & rownum).Select
sheetName = CStr(ActiveCell.Value)
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = sheetName
Sheets("sheet1").Select
rownum = rownum + 1
Loop
Sheets(sheetName).Select
Range("A" & rownum).Select
End Sub
Any help would be greatly appreciated
I also suggest you add if-else to check if the sheet name exists.. Why do you want to select? I do not support selections, since you need it you may try this: Because when you are incrementing rownum it goes to 10th cell, that means, Sheetname no longer has a name but empty..
Dim sheetName As String
Dim rownum As Integer
Dim WS as WorkSheet
rownum = 1
sheetName = Range("A" & rownum).Value '-- remove select
Do Until Range("A" & rownum).Value = ""
Range("A" & rownum).Select
sheetName = CStr(ActiveCell.Value)
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = sheetName
Set WS = Sheets(sheetName)
Sheets("sheet1").Select
rownum = rownum + 1
Loop
rownum = rownum - 1 '-- here
WS.Activate
Range("A" & rownum).Value = rownum
Or you may just use an array to do the creation of the sheets and then select a sheet later....Instead of going back and forth to first sheet...with names..
Sub addSheets()
Dim rowNum as Integer
Dim Ws as WorkSheet
Dim vArray as Variant
'-- creates one dimensional array
vArray = WorkSheetFunction.Transpoe(Sheets(1).Range("A1:A9"))
For rownum = Lbound(vArray) to Ubound(vArray)
If IsEmpty(vArray(rowNum)) Then
On Error Resume Next
Set Ws = Sheets(vArray(rowNum))
If Err.Number <> 0 Then '--no such sheet, so add it
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = vArray(rowNum)
Set Ws = Sheets(vArray(rowNum))
End If
End IF
Next rownum
Ws.Activate
Ws.Range("A1").offset(rownum).value = rownum
End Sub

Resources