Sub AutoFill()
Dim x As Long
Dim y As Long
Dim lastrow As Long
Dim lastcolumn As Long
Application.ScreenUpdating = False
Application.DisplayAlerts = False
lastcolumn = ActiveSheet.UsedRange.Column - 1 + ActiveSheet.UsedRange.Columns.Count
lastrow = ActiveSheet.UsedRange.Row - 1 + ActiveSheet.UsedRange.Rows.Count
For x = 2 To lastrow
If Cells(x, 2).Value = "" Then
Cells(x, 2).Value = Cells(x - 1, 2).Value
Cells(x, 3).Value = Cells(x - 1, 3).Value
Cells(x, 5).Value = Cells(x - 1, 5).Value
End If
Next x
Application.ScreenUpdating = True
End Sub
With the above code My cells are being filled up, but the last row fills till the end of excel sheet. In the Excel sheet column D is already filled in Column B C & E should be auto fill to down. What should be the changes in the code?
Excel VBA Last Row: The Complete Tutorial To Finding The Last Row In Excel With VBA (And Code Examples) recommends using LookIn:=xlFormulas when determining the last with using Cells.Find.
lastrow = Find(What:=” * ”, LookIn:=xlFormulas, SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Because you stated that column D is already filled in I use:
lastrow = Range("D" & Rows.Count).End(xlUp).Row
If column E isn't filled in then Cells(x, 2).Value must be <> "".
Sub AutoFill()
Dim x As Long
Dim y As Long
Dim lastrow As Long
Dim lastcolumn As Long
Application.ScreenUpdating = False
Application.DisplayAlerts = False
lastcolumn = ActiveSheet.UsedRange.Column - 1 + ActiveSheet.UsedRange.Columns.Count
lastrow = Range("D" & Rows.Count).End(xlUp).Row
For x = 2 To lastrow
If Cells(x, 2).Value = "" Then Cells(x, 2).Value = Cells(x - 1, 2).Value
If Cells(x, 3).Value = "" Then Cells(x, 3).Value = Cells(x - 1, 3).Value
If Cells(x, 5).Value = "" Then Cells(x, 5).Value = Cells(x - 1, 4).Value
Next x
Application.ScreenUpdating = True
End Sub
Related
I am new to VBA and have a small doubt. I was trying to convert certain values from a particular cell from hexadecimal to decimal, I have a small difficulty in that. In that cell there are lot of blank cells. For example the first 5 rows are blank then I have a hex value again 3 blank rows and a hex value. I am not able to loop through due to the blank cell. Please if somebody could help. Below is the code I wrote.
Sub Conversion()
Dim j As Integer
Dim LR As Integer
LR = Range("B" & Rows.Count).End(xlUp).Row
For j = 3 To LR
If Cells(j, 2).value = "" Then Cells(j, 3).value = "#N/A" Else
Cells(j, 3).value = CLng("&H" & Cells(j, 2).value)
Next
End Sub
I am getting Mismatch error with this code
You kinda forgot End If at the end. I have organized your code little bit and add End If and seems it works.
Sub Conversion()
Dim j As Integer
Dim LR As Integer
LR = Range("B" & Rows.Count).End(xlUp).Row
MsgBox Range("B" & Rows.Count).End(xlUp).Row
For j = 3 To LR
If Cells(j, 2).Value = "" Then
Cells(j, 3).Value = "#N/A"
Else
Cells(j, 3).Value = CLng("&H" & Cells(j, 2).Value)
End If
Next
End Sub
CLng is not working, as it is giving error in that as far as i read and understood you can use the below code, YOu can use Format instead of the CLNG command in ur code
Sub Conversion()
Dim j As Integer
Dim LR As Integer
LR = Range("A" & Rows.Count).End(xlUp).Row
For j = 1 To LR
If Cells(j, 1).Value = "" Then
Cells(j, 3).Value = "#N/A"
Else
Cells(j, 3).Value = "&H" & Format(Cells(j, 1).Value, "0")
End If
Next
End Sub
Try this:
For j = 3 To LR
If Cells(j, 2).Value = "" Then
Cells(j, 3).Value = "#N/A"
Else
Cells(j, 3).Value = CLng("&H" & Cells(j, 2).Value)
End If
For ignoring errors:
On Error Resume Next
here is one that uses a ternary function
Sub Conversion()
Dim sht As Worksheet
Set sht = ActiveWorkbook.Sheets("Sheet3")
Dim LR As Range
Set LR = sht.Range("B1", sht.Range("B" & sht.Rows.Count).End(xlUp))
Dim cel As Range
For Each cel In LR
cel.Offset(0, 1).Value = IIf(cel.Value = "", "#N/A", CLng("&H" & cel.Value))
Next cel
End Sub
I have 2 workbooks called "Source1" and "Source2".
For each cell in the last column of "Source1" I check if it exists in the last column of "Source2".
If yes, then I copy 4 separate cells from that row based on some critea into a new workbook called "Target".
My macro is working but as I have thousands of cells to loop through, it takes me at least 10 min till the macro finishes. I am running it many times a day so I want to optimize my code so that it will take less time.
Here is my code
Sub Loop_Cells()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.SheetsInNewWorkbook = 1
Dim Source, Source2, Target As Workbook
Dim c As Range
Dim lRow, lRow2 As Long
Dim x, y, w As Integer
Set Source = Workbooks.Open("C:\Reports\Source1.xlsx")
Source.Activate
x = ActiveSheet.UsedRange.Columns.Count
ActiveSheet.Cells(1, x + 1) = "Concate"
lRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lRow
ActiveSheet.Cells(i, x + 1).Value = ActiveSheet.Cells(i, 6).Value & ActiveSheet.Cells(i, 7).Value
Next i
ActiveSheet.Columns(x + 1).NumberFormat = "0"
Set Source2 = Workbooks.Open("C:\Reports\Source2.xlsx")
Source2.Activate
y = ActiveSheet.UsedRange.Columns.Count
ActiveSheet.Cells(1, y + 1) = "Concate"
lRow2 = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lRow2
ActiveSheet.Cells(i, y + 1).Value = ActiveSheet.Cells(i, 48).Value & ActiveSheet.Cells(i, 3).Value
Next i
ActiveSheet.Columns(y + 1).NumberFormat = "0"
Set Target = Workbooks.Add
Target.Sheets(1).Name = "ExistCells"
Source.Sheets(1).Activate
w = 1
For Each c In Source1.Sheets(1).UsedRange.Columns(x + 1).Cells
For j = 2 To lRow2
If c.Value = Source2.Sheets(1).Cells(j, y + 1).Value Then
Target.Sheets(1).Cells(w, 1).Value = Source2.Sheets(1).Cells(j, 48).Value
Target.Sheets(1).Cells(w, 2).Value = Source2.Sheets(1).Cells(j, 3).Value
Target.Sheets(1).Cells(w, 3).Value = Source2.Sheets(1).Cells(j, 27).Value
Target.Sheets(1).Cells(w, 4).Value = Source2.Sheets(1).Cells(j, 41).Value
w = w + 1
End If
Next j
Next c
Workbooks("Source1.xlsx").Close SaveChanges:=False
Workbooks("Source1.xlsx").Close SaveChanges:=False
Target.Activate
ActiveWorkbook.SaveAs FileName:= "C:\Reports\Target.xlsx", _
FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
I think the problem is in this part, when the cell exists I don't need to loop till the last row and I should move to the next.
For j = 2 To lRow2
If c.Value = Source2.Sheets(1).Cells(j, y + 1).Value Then ...
Any Suggestions how to adjust my code?
Collections: VBA.Collection, Scripting.Dictionary, ArrayList, Queue, Stack ... etc.
Collections are optimized for fast lookups. For this reason,they are ideal when matching values.
Consider matching two lists each with 1000 values. Assuming that on average you find a match half way through the list, that's (500 * 1000) or 500K operations. Using a Collection would reduce the number to 1000 iterations + 1000 lookups. Assuming that it takes 1 to 10 operations per lookup (just a guess) then you would reduce the number of operations that it takes to compare two 1000 element lists from 500K to 6K.
Arrays: Reading and writing to arrays is much faster then reading and writing to file (worksheet).
Once a match is found you write 4 values to the new worksheet. Let's say you find 1000 matches, that's 4000 write operations to the worksheet. If instaed you hold these values in an array and then write the array to the worksheet you'll reduce the number of write operations (to the worksheet) from 400 to 1.
Using these techniques should reduce the run time from 10+ minutes to under 20 seconds.
Sub NewLoop()
Application.ScreenUpdating = False
Application.SheetsInNewWorkbook = 1
Dim data As Variant, result As Variant
Dim lastRow As Long, x As Long, x1 As Long
Dim key As String
Dim list As Object
Set list = CreateObject("System.Collections.ArrayList")
With Workbooks.Open("C:\Reports\Source1.xlsx")
With .Worksheets(1)
data = .Range("F2:G" & .Range("A" & Rows.Count).End(xlUp).Row).Value
For x = 1 To UBound(data, 1)
'Create a Unique Identifier using a pipe to delimit the data
'This will keep the data from mixing
key = data(x, 1) & "|" & data(x, 2)
If Not list.Contains(key) Then list.Add key
Next
End With
.Close SaveChanges:=False
End With
With Workbooks.Open("C:\Reports\Source2.xlsx")
With .Worksheets(1)
lastRow = .Range("A" & Rows.Count).End(xlUp).Row
ReDim result(1 To lastRow, 1 To 4)
For x = 2 To lastRow
'Create a Unique Identifier using a pipe to delimit the data
'This will keep the data from mixing
key = .Cells(i, 48).Value & "|" & .Cells(i, 3).Value
If list.Contains(key) Then
x1 = x1 + 1
result(x1, 1) = .Cells(j, 48).Value
result(x1, 2) = .Cells(j, 3).Value
result(x1, 3) = .Cells(j, 27).Value
result(x1, 4) = .Cells(j, 41).Value
End If
Next
End With
.Close SaveChanges:=False
End With
With Workbooks.Add
With Worksheets(1)
.Name = "ExistCells"
.Range("A1:D1").Resize(x1).Value = Results
End With
End With
Application.ScreenUpdating = True
End Sub
Following on from your last point, could you not just exit the loop when the If condition is met? Something like this for example?
For j = 2 To lRow2
If c.Value = Source2.Sheets(1).Cells(j, y + 1).Value Then
Target.Sheets(1).Cells(w, 1).Value = Source2.Sheets(1).Cells(j, 48).Value
Target.Sheets(1).Cells(w, 2).Value = Source2.Sheets(1).Cells(j, 3).Value
Target.Sheets(1).Cells(w, 3).Value = Source2.Sheets(1).Cells(j, 27).Value
Target.Sheets(1).Cells(w, 4).Value = Source2.Sheets(1).Cells(j, 41).Value
w = w + 1
GoTo ExitLoop
End If
Next j
ExitLoop:
The code could be cleaned up a bit...plus you were closing "Source1.xlsx" twice...and tried to refer to Source1 as a variable even though it was never declared. Using Option Explicit at the top of the module will allow you find that type of issue easily. I put in a similar break in the inner For loop like Wilson88 as well.
By using your variables and With you should be able to speed it up some over ActiveWorkbook and ActiveSheet...
Sub Loop_Cells()
Dim Source As Workbook, Source2 As Workbook, Target As Workbook
Dim w As Integer, x As Integer, y As Integer
Dim lRow As Long, lRow2 As Long
Dim c As Range
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.SheetsInNewWorkbook = 1
Set Source = Workbooks.Open("C:\Reports\Source1.xlsx")
With Source
x = .UsedRange.Columns.Count
.Cells(1, x + 1) = "Concate"
lRow = .Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lRow
.Cells(i, x + 1) = .Cells(i, 6). & .Cells(i, 7)
Next i
.Columns(x + 1).NumberFormat = "0"
End With
Set Source2 = Workbooks.Open("C:\Reports\Source2.xlsx")
With Source2
y = .UsedRange.Columns.Count
.Cells(1, y + 1) = "Concate"
lRow2 = .Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lRow2
.Cells(i, y + 1). = .Cells(i, 48) & .Cells(i, 3)
Next i
.Columns(y + 1).NumberFormat = "0"
End With
Set Target = Workbooks.Add
With Target.Sheets(1)
.Name = "ExistCells"
w = 1
For Each c In Source.Sheets(1).UsedRange.Columns(x + 1).Cells
For j = 2 To lRow2
If c.Value = Source2.Sheets(1).Cells(j, y + 1) Then
.Cells(w, 1).Value = Source2.Sheets(1).Cells(j, 48)
.Cells(w, 2).Value = Source2.Sheets(1).Cells(j, 3)
.Cells(w, 3).Value = Source2.Sheets(1).Cells(j, 27)
.Cells(w, 4).Value = Source2.Sheets(1).Cells(j, 41)
w = w + 1
Exit For
End If
Next j
Next c
End With
Source.Close SaveChanges:=False
Source2.Close SaveChanges:=False
Target.SaveAs FileName:= "C:\Reports\Target.xlsx", _
FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
I am trying to write a vba script that will filter on two columns, column A and column D. Preferably, I want to create a button that will execute once I have chosen the filter criteria. Sample of input data below.
Sub Compiler()
Dim i
Dim LastRow As Integer
LastRow = Sheets("Sheet1").Cells(Rows.Count, "A").End(xlUp).Row
Sheets("Sheet4").Range("A2:J6768").ClearContents
For i = 2 To LastRow
If Sheets("Sheet1").Cells(i, "A").Values = Sheets("Sheet3").Cells(3, "B").Values And Sheets("Sheet1").Cells(i, "D").Values = Sheets("Sheet3").Cells(3, "D").Values Then
Sheets("Sheet1").Cells(i, "A" & "D").EntireRow.Copy Destination:=Sheets("Sheet4").Range("A" + Rows.Count).End(xlUp)
End If
Next i
End Sub
Sample Data to run vba script
I have included my previous answer's changes into the full code block that is now provided below.
Sub Compiler()
Dim i
Dim LastRow, Pasterow As Integer
Dim sht As Worksheet
Set sht = ThisWorkbook.Sheets("Sheet4")
LastRow = Sheets("Sheet1").Cells(Rows.Count, "A").End(xlUp).Row
Sheets("Sheet4").Range("A2:J6768").ClearContents
For i = 2 To LastRow
If Sheets("Sheet1").Range("A" & i).Value = Sheets("Sheet3").Range("B3").Value And Sheets("Sheet1").Range("D" & i).Value = Sheets("Sheet3").Range("D3").Value Then
Pasterow = sht.Cells(sht.Rows.Count, "A").End(xlUp).Row + 1
Sheets("Sheet1").Rows(i).EntireRow.Copy Destination:=Sheets("Sheet4").Range("A" & Pasterow)
End If
Next i
Sheets("sheet4").Rows(1).Delete
End Sub
Sheets("Sheet1").Cells(i, "A").Values
Sheets("Sheet3").Cells(3, "B").Values
etc
You keep using values. Don't you mean value?
This answered the question I was asking, I tried to work with Dan's answer but didn't get very far.
Private Sub CommandButton1_Click()
FinalRow = Sheets("Sheet1").Cells(rows.Count, 1).End(xlUp).Row
Sheets("Sheet4").Range(Sheets("Sheet4").Cells(1, "A"), Sheets("Sheet4").Cells(FinalRow, "K")).ClearContents
If Sheets("Sheet4").Cells(1, "A").Value = "" Then
Sheets("Sheet1").Range("A1:K1").Copy
Sheets("Sheet4").Range(Sheets("Sheet4").Cells(1, "A"), Sheets("Sheet4").Cells(1, "K")).PasteSpecial (xlPasteValues)
End If
For x = 2 To FinalRow
ThisValue = Sheets("Sheet1").Cells(x, "A").Value
ThatValue = Sheets("Sheet1").Cells(x, "D").Value
If ThisValue = Sheets("Sheet3").Cells(3, "B").Value And ThatValue = Sheets("Sheet3").Cells(3, "D").Value Then
Sheets("Sheet1").Range(Sheets("Sheet1").Cells(x, 1), Sheets("Sheet1").Cells(x, 11)).Copy
Sheets("Sheet4").Select
NextRow = Sheets("Sheet4").Cells(rows.Count, 1).End(xlUp).Row + 1
With Sheets("Sheet4").Range(Sheets("Sheet4").Cells(NextRow, 1), Sheets("Sheet4").Cells(NextRow, 11))
.PasteSpecial (xlPasteFormats)
.PasteSpecial (xlPasteValues)
End With
End If
Next x
Worksheets("Sheet4").Cells.EntireColumn.AutoFit
End Sub
So I have a code I have written the first part of the code is to create a new worksheet with the headings specified. The second part of the code is meant to populate that table with certain information. The problem I am having is getting the correct bits of information to go into the correct columns.
I need the code to search for the value 9.1 in column G in all worksheets within a workbook
if that value is found I need it to copy this to column b in the new sheet along with the following information :
Engine Effect from Column F Same row must be pasted to Column C in the worksheet entitled FHA
Part number is always located in Cell J3 this must be pasted into column D and is always the same
Part Name Is Always located in C2 this must be pasted into column E and is always the same
FM ID from Column B same row must be pasted to Column F in the worksheet entitled FHA
Failure Mode & Cause from Column C Same row must be pasted to column G in FHA
FMCN Value From Column N pasted to Column H In FHA
As It stands the code I have is
Sub createWSheetFHA()
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = "FHA"
Cells(1, 2) = "FHA TABLE"
Cells(2, 2) = "FHA Ref"
Cells(2, 3) = "Engine Effect"
Cells(2, 4) = "Part No"
Cells(2, 5) = "Part Name"
Cells(2, 6) = "FM I.D"
Cells(2, 7) = "Failure Mode & Cause"
Cells(2, 8) = "FMCM"
Cells(2, 9) = "PTR"
Cells(2, 10) = "ETR"
Range(Cells(2, 2), Cells(2, 10)).Font.Bold = True
Range(Cells(1, 2), Cells(1, 10)).MergeCells = True
Range(Cells(1, 2), Cells(1, 10)).Font.Bold = True
End Sub
Sub Populate_FHA_Table_2()
Dim wks As Excel.Worksheet, i As Integer, n As Integer
Application.ScreenUpdating = False
Sheets("FHA").Range("A2:" & Columns.Count & ":" & Rows.Count).Delete
i = 1
For Each wks In ActiveWorkbook.Worksheets
If wks.Name <> "FHA" Then
wks.UsedRange.AutoFilter Field:=7, Criteria1:="9.1"
Sheets(i).Range(Sheets(i).Range("G1").Offset(1), Sheets(i).Range("B1").End(xlDown)).Copy _
Sheets("FHA").Range("C" & Rows.Count).End(xlUp)
Sheets(i).Range(Sheets(i).Range("F1").Offset(1), Sheets(i).Range("D1").End(xlDown)).Copy _
Sheets("FHA").Range("d" & Rows.Count).End(xlUp)
Sheets(i).Range(Sheets(i).Range("J1").Offset(1), Sheets(i).Range("E1").End(xlDown)).Copy _
Sheets("FHA").Range("e" & Rows.Count).End(xlUp)
Sheets(i).Range(Sheets(i).Range("C1").Offset(1), Sheets(i).Range("H1").End(xlDown)).Copy _
Sheets("FHA").Range("E" & Rows.Count).End(xlUp)
Sheets(i).Range(Sheets(i).Range("B1").Offset(1), Sheets(i).Range("H1").End(xlDown)).Copy _
Sheets("FHA").Range("F" & Rows.Count).End(xlUp)
Sheets(i).Range(Sheets(i).Range("C1").Offset(1), Sheets(i).Range("H1").End(xlDown)).Copy _
Sheets("FHA").Range("G" & Rows.Count).End(xlUp)
Sheets(i).Range(Sheets(i).Range("N1").Offset(1), Sheets(i).Range("H1").End(xlDown)).Copy _
Sheets("FHA").Range("H" & Rows.Count).End(xlUp)
wks.UsedRange.AutoFilter
End If
i = i + 1
Next
Application.ScreenUpdating = True
End Sub
You have some mismatches in your code (Example using 'for each wk' then accessing via an index 'i'; where they may not necessarily match)
Try something like this...
I have added in some dynamic flow control which isn't strictly needed but if and when your headers change in the future, it may be easier to have it in this form.
Likewise I have tried to add in some error handling as well
Sub Create_FHA_Sheet()
Dim Headers() As String: Headers = _
Split("FHA Ref,Engine Effect,Part No,Part Name,FM I.D,Failure Mode & Cause,FMCM,PTR,ETR", ",")
If Not WorksheetExists("FHA") Then Worksheets.Add().Name = "FHA"
Dim wsFHA As Worksheet: Set wsFHA = Sheets("FHA")
wsFHA.Move after:=Worksheets(Worksheets.Count)
wsFHA.Cells.Clear
Application.ScreenUpdating = False
With wsFHA
For i = 0 To UBound(Headers)
.Cells(2, i + 2) = Headers(i)
.Columns(i + 2).EntireColumn.AutoFit
Next i
.Cells(1, 2) = "FHA TABLE"
.Range(.Cells(1, 2), .Cells(1, UBound(Headers) + 2)).MergeCells = True
.Range(.Cells(1, 2), .Cells(1, UBound(Headers) + 2)).HorizontalAlignment = xlCenter
.Range(.Cells(1, 2), .Cells(2, UBound(Headers) + 2)).Font.Bold = True
End With
Dim RowCounter As Long: RowCounter = 3
Dim SearchTarget As String: SearchTarget = "9.1"
Dim SourceCell As Range, FirstAdr As String
If Worksheets.Count > 1 Then
For i = 1 To Worksheets.Count - 1
With Sheets(i)
Set SourceCell = .Columns(7).Find(SearchTarget, LookAt:=xlWhole)
If Not SourceCell Is Nothing Then
FirstAdr = SourceCell.Address
Do
wsFHA.Cells(RowCounter, 3).Value = .Cells(SourceCell.Row, 6).Value
wsFHA.Cells(RowCounter, 4).Value = .Cells(3, 10).Value
wsFHA.Cells(RowCounter, 5).Value = .Cells(2, 3).Value
wsFHA.Cells(RowCounter, 6).Value = .Cells(SourceCell.Row, 2).Value
wsFHA.Cells(RowCounter, 7).Value = .Cells(SourceCell.Row, 3).Value
wsFHA.Cells(RowCounter, 8).Value = .Cells(SourceCell.Row, 14).Value
Set SourceCell = .Columns(7).FindNext(SourceCell)
RowCounter = RowCounter + 1
Loop While Not SourceCell Is Nothing And SourceCell.Address <> FirstAdr
End If
End With
Next i
End If
Application.ScreenUpdating = True
End Sub
Public Function WorksheetExists(ByVal WorksheetName As String) As Boolean
On Error Resume Next
WorksheetExists = (ThisWorkbook.Sheets(WorksheetName).Name <> "")
On Error GoTo 0
End Function
I've been trying to create a macro that extracts specific cell data from several open workbooks that all contain a specific sheet named ("Report_Final")
Currently, my macro goes sth like this:
Sub PerLineItem()
'Main function i'm trying to call for each open workbook
Dim wb As Workbook
Dim ws, ws2 As Worksheet
Dim i, j, k, x, rng As Integer
Dim temp_total As Double
Dim mat_name1, mat_name2 As String
i = 2
j = 2
k = 2
rng = 0
Application.ScreenUpdating = False
Set wb = ActiveWorkbook
Sheets.Add
Set ws = ActiveSheet
'Intermediate sheet to filter only columns 2, 11 & 18'
ws.Name = "Report"
Cells(1, 2) = "WBS"
Cells(1, 3) = "Material"
Cells(1, 4) = "Sell Total Price"
Sheets("zero250").Select
Do While Cells(i, 2) <> ""
rng = rng + 1
i = i + 1
Loop
'Copy and paste columns 2, 11, 18 to 2, 3, 4 in the new sheet("Report")
Do While j < rng
If ((Right(Cells(j, 2), 3) = "RTN") Or (Right(Cells(j, 2), 3) = "NRT")) Then
Union(Cells(j, 2), Cells(j, 11), Cells(j, 18)).Copy
Sheets("Report").Select
Union(Cells(k, 2), Cells(k, 3), Cells(k, 3)).Select
ActiveSheet.Paste
Sheets("zero250").Select
k = k + 1
End If
j = j + 1
Loop
'Create new sheet to group up identical named materials and sum the value up
Sheets.Add
Set ws2 = ActiveSheet
'The debugger always points to the below line "name is already taken" since it is being run in the same workbook
ws2.Name = "Report_Final"
Sheets("Report").Select
i = 2
j = 2
k = 2
x = 2
rng = 1
Do While Cells(i, 2) <> ""
rng = rng + 1
i = i + 1
Loop
'deletes identicals names and sums the value up, puts the values onto sheet("Report_final")
Do While j <= rng
If Cells(j, 3) <> "" Then
mat_name1 = Cells(j, 3).Value
temp_total = Cells(j, 4).Value
For x = j To rng
mat_name2 = Cells(x + 1, 3).Value
If mat_name2 = mat_name1 Then
temp_total = temp_total + Cells(x + 1, 4).Value
Rows(x + 1).ClearContents
End If
Next x
Sheets("Report_Final").Select
Cells(k, 2) = mat_name1
Cells(k, 3) = temp_total
Sheets("Report").Select
Rows(j).ClearContents
k = k + 1
j = j + 1
Else
j = j + 1
End If
Loop
'Labels the new columns in "Report_Final" and calculates the grand total
ws2.Select
Cells(1, 1).Value = wb.Name
Cells(1, 2).Value = "Material"
Cells(1, 3).Value = "Sell Total Price"
Cells(k, 3).Value = Application.Sum(Range(Cells(2, 3), Cells(k, 3)))
Application.DisplayAlerts = False
'Deletes intermediate sheet "Report"
Sheets("Report").Delete
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
In my Main function where I use:
For each wb in Workbooks
PerLineItem
Next wb
It doesn't call PerLineItem for each of the open workbooks but instead trys to perform the function again on the same workbook.
P.S I know there may be a easier way to write all this code but I do not know prior knowledge to VBA :(
Edit : Hi so I've used your code with a little modification and it works fine! But now when i add this next part, it only works through the last workbook, as the counter k does not seem to loop for the earlier workbooks
'~~> cleaning up the sheet still goes here
With wb.Sheets("Report")
rng2 = .Range("B" & .Rows.Count).End(xlUp).Row
MsgBox rng2
Do While j <= rng2
If Cells(j, 3) <> "" Then
mat_name1 = .Cells(j, 3).Value
temp_total = .Cells(j, 4).Value
For x = j To rng2
mat_name2 = .Cells(x + 1, 3).Value
If mat_name2 = mat_name1 Then
temp_total = temp_total + .Cells(x + 1, 4).Value
.Rows(x + 1).ClearContents
End If
Next x
.Rows(j).ClearContents
.Cells(k, 2) = mat_name1
.Cells(k, 3) = temp_total
k = k + 1
j = j + 1
Else
j = j + 1
End If
Loop
MsgBox k
End With
With Application
.ScreenUpdating = True
.DisplayAlerts = True
End With
P.S I've decided to scrap creating another worksheet and work within "Report"
Try this:
Dim wb As Workbook
For Each wb in Workbooks
If wb.Name <> Thisworkbook.Name Then
PerLineItem wb
End If
Next
Edit1: You need to adapt your sub like this
Private Sub PerLineItem(wb As Workbook)
Dim ws As Worksheet, ws2 As Worksheet
Dim i As Long, j As Long, k As Long, x As Long, rng As Long
Dim temp_total As Double
Dim mat_name1 As string, mat_name2 As String
i = 2: j = 2: k = 2: rng = 0
With Application
.ScreenUpdating = False
.DisplayAlerts = False
End With
'~~> Improve initializing ws
Set ws = wb.Sheets.Add(wb.Sheets(1))
ws.Name = "Report"
'~~> Directly work on your object; You can also use the commented lines
With ws
.Cells(1, 2) = "WBS" '.Range("B1") = "WBS"
.Cells(1, 3) = "Material" '.Range("C1") = "Material"
.Cells(1, 4) = "Sell Total Price" '.Range("D1") = "Sell Total Price"
End With
'~~> Same with the other worksheet
With wb.Sheets("zero250")
rng = .Range("B" & .Rows.Count).End(xlUp).Row
.AutoFilterMode = False
.Range("B1:B" & rng).AutoFilter 1, "=*RTN*", xlOr, "=*NRT*"
.Range("B1:B" & rng).Offset(1,0).SpecialCells(xlCellTypeVisisble).Copy _
ws.Range("B" & ws.Rows.Count).End(xlup).Offset(1,0)
End With
'~~> cleaning up the sheet still goes here
End Sub
Above code is the equivalent of your code up to generating the Report Sheet only.
Can you continue? :) I run out of time. ;p
Btw, hope this helps.