Get data from specific areas in multiple sheets in selected workbooks - vba

I've to make a macro that allows me to gather data from specific areas, e.g., A1-Ax, and G1-Gx in one sheet and B1-Bx in another sheet and so on, in many different workbooks into one main excel sheet. I've like 5-6 Excel files I have to gather data from and they all contain like 4-5 worksheets.
With the code below, I'm able to gather all the data in each Worksheet, in the selected Workbooks.
But the data I have to gather is from a specific Range which varies per Worksheet and/or Workbook.
My code so far looks like this:
Function LastUsedCell(wks As Excel.Worksheet) As Excel.Range
With wks
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
Set LastUsedCell = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False)
End If
End With
End Function
Function GetNextRowStart(wks As Excel.Worksheet) As Excel.Range
Dim lastCell As Excel.Range
Dim nextRow As Integer
nextRow = 1
Set lastCell = LastUsedCell(wks)
If Not lastCell Is Nothing Then nextRow = lastCell.Row + 1
Set GetNextRowStart = wks.Cells(nextRow, 1)
End Function
Sub Multi()
Dim outputWorkbook As Excel.Workbook
Dim outputWorksheet As Excel.Worksheet
Dim filepath As Variant
Set outputWorkbook = Workbooks.Open("C:\Users\z003k50s\Desktop\Test\Output.xlsx")
Set outputWorksheet = outputWorkbook.Sheets("Sheet1")
For Each filepath In Application.GetOpenFilename(FileFilter:="Excel Files (*.xl*), *.xl*", MultiSelect:=True)
Dim wkbk As Excel.Workbook
Dim wks As Excel.Worksheet
Set wkbk = Workbooks.Open(filepath, , True)
For Each wks In wkbk.Sheets
Dim sourceRange As Excel.Range
Dim outputRange As Excel.Range
With wks
Set sourceRange = .Range(.Cells(1, 1), LastUsedCell(wks))
End With
Set outputRange = GetNextRowStart(outputWorksheet)
sourceRange.Copy outputRange
Next
Next
outputWorksheet.Columns.AutoFit
End Sub

I know it sounds like a lot of work, but just hard code it with copy and paste. It's definitely not the best way to do it, but it'll do the job.

Related

Copying data based on cell value

I am a bit stuck and hoping to find some help. I have some experience in VBA but this particular problem exceeds my programming knowledge.
I have a sheet with 1000 - 1250 rows of data, and anywhere from 20 - 60 columns that can change monthly.
What I am hoping to do is look at each cell for an X, and when found it will create a new line on a separate tab. The line would contain the first cell in the row where the X was found and the column header from the column the X was found in.
I have been able to write some things that will find the X's in the sheet, create new items on another page and the like, but I can't get one script to do everything I need.
This is an example of the data structure:
Data
Expected result:
Output
Sorry for the links, I am too new to post photos.
Any help on how this can be achieved, documents, tips or the like would be super helpful and most appreciated. Thank you for looking!
Andrew
EDIT:
Some of the code I have put together:
Dim uSht As String
Dim wsExists As Boolean
Dim lRow As Long
Dim lcol As Long
Dim ws As Worksheet
Sub CopyData()
'Setup Sheetnames
uSht = "UPLOAD"
uTem = "TEMPLATE"
' Stop flicker
Application.ScreenUpdating = False
' Check for Upload Worksheet
WorksheetExists (uSht)
'MsgBox (wsExists)
If wsExists = False Then
' If it does not exist, create it
Call CreateSheet("UPLOAD")
End If
'Setup stuff
Dim i As Integer
Dim ws1 As Worksheet: Set ws1 = ThisWorkbook.Sheets(uTem)
Dim ws2 As Worksheet: Set ws2 = ThisWorkbook.Sheets(uSht)
lRow = Cells(Rows.Count, 1).End(xlUp).Row
lcol = Cells(1, Columns.Count).End(xlToLeft).Column
'MsgBox (lRow)
'MsgBox (lCol)
Range(Cells(lRow, lColumn)).Select
Application.ScreenUpdating = True
End Sub
Sub CreateSheet(wsName)
'Creates the uSht worksheet
With ThisWorkbook
.Sheets.Add(After:=.Sheets(.Sheets.Count)).Name = uSht
End With
End Sub
Function WorksheetExists(wsName As String) As Boolean
'Check to see if uSht exists and return.
wsName = UCase(wsName)
For Each ws In ThisWorkbook.Sheets
If UCase(ws.Name) = wsName Then
wsExists = True
Exit For
End If
Next
WorksheetExists = wsExists
End Function
Using FindAll from here: Extracting specific cells from multiple Excel files and compile it into one Excel file
(but change LookAt:=xlPart to LookAt:=xlWhole)
Rough outline:
Dim col, c, dest As Range
Set dest = sheets("results").Range("A2")
Set col = FindAll(sheets("data").range("a1").currentregion, "X")
For each c in col
dest.resize(1,2).value = array(c.entirerow.cells(1).value, _
c.entirecolumn.cells(1).value)
set dest = dest.offset(1, 0)
next
You need a Find/FindNext loop that will locate all X values in the first worksheet. After a found cell is located, the cell's row and column can be used to identify the location and project.
Option Explicit
Sub Macro1()
Dim addr As String, loc As String, pro As String
Dim ws2 As Worksheet, fnd As Range
Set ws2 = Worksheets("sheet2")
With Worksheets("sheet1")
Set fnd = .Cells.Find(What:="x", after:=.Cells(1, 1), _
LookIn:=xlFormulas, LookAt:=xlWhole, _
SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not fnd Is Nothing Then
addr = fnd.Address(0, 0)
Do
loc = .Cells(fnd.Row, "A").Value
pro = .Cells(1, fnd.Column).Value
With ws2
.Cells(.Rows.Count, "A").End(xlUp).Offset(1, 0) = loc
.Cells(.Rows.Count, "A").End(xlUp).Offset(0, 1) = pro
End With
Set fnd = .Cells.FindNext(after:=fnd)
Loop Until addr = fnd.Address(0, 0)
End If
End With
End Sub

VBA Run-Time Error 438

I have been working on a small macro but have run into an error.
The function of the macro is as follows: There is a list of stocks in an existing sheet. The macro goes into the folders and opens a spreadsheet where the recommendations are stored. It then goes back to the original sheet, takes each stock code and then goes into the recommendations sheet to see if there is a corresponding stock and what its recommendation is.
The code works fine, however I am now getting a VBA run-time error 438 when I am trying to get the macro to switch which workbook it needs to work on.
The error occurs on the lines application.wb2.activate and then lower down again with application.wb2.activate and application.wb.activate
When I replace wb and wb2 with the full directory, i.e. H:\A\AA\recommendations.xlsx and H:\A\AA\november 2017.xlsm, it works fine.
Would appreciate any help here! Thanks!
Option Explicit
Option Compare Text
Sub gsr()
Dim firstrow As Integer, lastrow As Integer, i As Integer
Dim gsr As Range, msr As Range
Dim stock, findstock As Range, col As Integer
Dim sPath As String, sFile As String
Dim sPath2 As String, sFile2 As String
Dim wb As Workbook, wb2 As Workbook
Dim xlrange As Range, xlcell As Range, xlsheet As Worksheet
Dim xllastrow As Integer
Dim foundlocationG As String, foundlocationM As String
With ActiveWorkbook
sPath2 = ActiveWorkbook.Path & "\"
sFile2 = sPath2 & ActiveWorkbook.Name
Set wb2 = ActiveWorkbook
End With
sPath = "H:\A\AA\"
sFile = sPath & "Recommendations.xlsx"
Set wb = Workbooks.Open(sFile)
Set xlsheet = Sheets("Sheet1")
xllastrow = xlsheet.Range("A1").End(xlDown).Row
Set xlrange = xlsheet.Range("A1:A" & xllastrow)
Application.wb2.Activate
With wb2.Sheets("Sheet1").Range("A:Z")
Set stock = .Find(what:="Stock", After:=.Cells(.Cells.Count), LookIn:=xlValues, Lookat:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False)
Set gsr = .Find(what:="GS", After:=.Cells(.Cells.Count), LookIn:=xlValues, Lookat:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False)
Set msr = .Find(what:="MS", After:=.Cells(.Cells.Count), LookIn:=xlValues, Lookat:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False)
firstrow = stock.Row + 1
lastrow = .Cells(.Rows.Count, stock.Column).End(xlUp).Row
lastrow = lastrow - 1
col = stock.Column
For i = firstrow To lastrow
For Each xlcell In xlrange
If xlcell.Value = Cells(i, col) Then
Application.wb.Activate
foundlocationG = Cells(xlcell.Row, 2)
foundlocationM = Cells(xlcell.Row, 3)
Application.wb2.Activate
Cells(i, gsr.Column) = foundlocationG
Cells(i, msr.Column) = foundlocationM
End If
Next xlcell
Next i
End With
End Sub
You seem to be confusing the Workbook.Activate and Application.Activate¹ methods.
Activate is a direct method of the Workbook object. If you have correctly assigned (e.g. Set) an object-level variable to the Workbook object, you should be able to call the Activate method directly.
Solution: drop the Application and simply Activate the open workbook from the assigned object variable.
wb2.Activate
...
wb.Activate
For all intents and purposes, activating the workbooks as you have done is not necessary and is not the more efficient code. See How to avoid using Select in Excel VBA for more information.
¹ Application.Activate is more commonly used within Word VBA projects.

Update Pivot Data Range String or Range

I'm working on a code that I've pieced together, but what I'm finding is that after the "used" range is found (I'm trying not to use .usedrange due to reliability) is that the SourceData:= is expecting a string (I think).
Is there a way to pass through the range from the Data sheet to the pivot table data range? I tried appending RealUsedRange.Address, but that was no luck either.
Sub UpdatePivotRange()
Dim Rng1 As Range
Dim oWB As Workbook
Dim oWS As Worksheet
Dim DataSheet As Worksheet
Dim oPT As PivotTable
Set oWB = ThisWorkbook
Set DataSheet = oWB.Sheets("Data")
Set Rng1 = RealUsedRange
If Rng1 Is Nothing Then
MsgBox "There is no used range, the worksheet is empty."
Else
For Each oWS In oWB.Worksheets
For Each oPT In oWS.PivotTables
'ERRROR BEGINS HERE #####
oPT.ChangePivotCache _
oWB.PivotCaches.Create(SourceType:=xlDatabase, SourceData:=Rng1)
'ERROR ENDS HERE #####
Next oPT
Next oWS
End If
End Sub
Public Function RealUsedRange() As Range
Dim FirstRow As Long
Dim LastRow As Long
Dim FirstColumn As Integer
Dim LastColumn As Integer
Dim DataSheet As Worksheet
Dim oWB As Workbook
On Error Resume Next
Set oWB = ThisWorkbook
Set DataSheet = oWB.Sheets("Data")
With DataSheet
FirstRow = DataSheet.Cells.Find(What:="*", After:=Cells(1, 1), LookIn:=xlValues, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext).Row
FirstColumn = DataSheet.Cells.Find(What:="*", After:=Cells(1, 1), LookIn:=xlValues, LookAt:= _
xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext).Column
LastRow = DataSheet.Cells(.Rows.Count, "A").End(xlUp).Row
LastColumn = DataSheet.Cells(1, Columns.Count).End(xlToLeft).Column
Set RealUsedRange = Range(Cells(FirstRow, FirstColumn), Cells(LastRow, LastColumn))
End With
MsgBox "The range is" & RealUsedRange.Address
On Error GoTo 0
End Function
I was able to amend the errored line by adding:
oPT.ChangePivotCache _
oWB.PivotCaches.Create(SourceType:=xlDatabase, SourceData:="Data!" & Rng1.Address(ReferenceStyle:=xlR1C1))
Hope this helps anyone looking in the future.

Search for specific string format using VBA and paste to a new excel worksheet

I am attempting to consolidate some data into a specific excel template I have created. My data is titled as PAxxx.xx where x could be any number between 0-9. Is there a way I can search through my current workbook for that specific title "PAxxx.xx" and populate it into my created template field.
I current have this search function in VBA:
Sub CopyPasteCellData()
Dim FirstAddress As String
Dim searchTerms As Variant
Dim Rcount As Long
Dim I As Long
Dim Rng As Range
Dim currentWorkbook As Workbook
Dim newWorkbook As Workbook
Dim currentWorksheet As Worksheet
Dim newWorksheet As Worksheet
Set currentWorkbook = Workbooks("LVX Release 2015 (2).xlsm")
Set currentWorksheet = currentWorkbook.Sheets("PA5179.01")
Set newWorkbook = Workbooks("Test.xlsx")
Set newWorksheet = newWorkbook.Sheets("Sheet1")
'newWorksheet.Range("C2").Value = currentWorksheet.Range("A1").Value
searchTerms = Array("PA")
With currentWorksheet.UsedRange
Rcount = 0
For I = LBound(searchTerms) To UBound(searchTerms)
Set Rng = .Find(What:=searchTerms(I), _
After:=.Cells(.Cells.Count), _
LookIn:=xlFormulas, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
FirstAddress = Rng.Address
Do
Rcount = Rcount + 1
newWorksheet.Range("A" & Rcount).Value = Rng.Value
Set Rng = .FindNext(Rng)
Loop While Not Rng Is Nothing And Rng.Address <> FirstAddress
End If
Next I
End With
End Sub
Just not sure how to search the sheet for all data sets PAxxx.xx.
Thanks in advance :)
Here is a basic principle how to loop through all the sheets and find for a PAxxx.xx -> read instructions of Like operator if you need to change the validation ->
Sub LoopTroughWorkSheetsAndFindPA()
Dim wb As Workbook: Set wb = ThisWorkbook 'anyreference of a workbook you want
Dim ws As Worksheet
For Each ws In wb.Worksheets
If ws.Name Like "PA###.##" Then
'do some operations here for example ->
Debug.Print ws.Name
End If
Next
End Sub

Excel VBA - Find and Replace from External File

I have a file that I would like to run a Find and Replace on using data from another Excel file.
I have this so far, what am I doing wrong?
Sub LegalName()
Dim NameListWB As Workbook
Dim NameListWS As Worksheet
Set NameListWB = Workbooks.Open("File.xlsx")
Set NameListWS = NameListWB.Worksheets("Sheet1")
Dim rng As Range
Set rng = NameListWS.Range("A:B").Select
Do Until IsEmpty(ActiveCell)
Worksheets("Sheet1").Columns("F").Replace _
What:=ActiveCell.Value, Replacement:=ActiveCell.Offset(0, 1).Value, _
SearchOrder:=xlByColumns, MatchCase:=False
ActiveCell.Offset(1, 0).Select
Loop
End Sub
I see that you started by declaring your objects but missed out on few. Also, you need to avoid the use of .Select Interesting Read
Is this what you are trying (UNTESTED)?
Sub Sample()
Dim NameListWB As Workbook, thisWb As Workbook
Dim NameListWS As Worksheet, thisWs As Worksheet
Dim i As Long, lRow As Long
'~~> This is the workbook from where your code is running
Set thisWb = ThisWorkbook
'~~> Change this to the sheet name where you want to replace
'~~> in Column F
Set thisWs = thisWb.Sheets("Sheet1")
'~~> File.xlsx
Set NameListWB = Workbooks.Open("C:\File.xlsx")
Set NameListWS = NameListWB.Worksheets("Sheet1")
With NameListWS
'~~> Find last row in Col A of File.xlsx
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Loop though Col A
For i = 1 To lRow
'~~> Do the replace
thisWs.Columns(6).Replace What:=.Range("A" & i).Value, _
Replacement:=.Range("B" & i).Value, _
SearchOrder:=xlByColumns, _
MatchCase:=False
Next i
End With
End Sub