runtime error 1004 : excel VBA - excel

I keep getting runtime error 1004, on the following line:
originBook.Sheets(1).Range(Cells(1, 1), Cells(lastRow, lastCol)).Copy
Here's the full code
Sub Obtain_Source()
Application.DisplayAlerts = False
Dim theOrigin, theString, newCol As String
Dim lastRow, lastCol As Long
Dim theRange As Range
Dim originBook, originBookBackup, macroBook As Workbook
Dim originOpen As Boolean
originOpen = False
Set macroBook = Workbooks("FY_Macro_Testt (DYNAMIC).xlsm")
theOrigin = Application.GetOpenFilename(fileFilter:="Excel Files (*.xls; *.xlsm; *.xlsx), *.xls' *.xlsm' *.xlsx", _
Title:="Fiscal Year Selection: Select Only One", ButtonText:="Open", MultiSelect:=False)
If TypeName(theOrigin) = "Boolean" Then
MsgBox "Don't just stand there. Do something." & vbNewLine & _
"Quit hitting CANCEL. >.< ", vbExclamation, "WARNING. CHOKING HAZARD."
Else
originOpen = True
Set originBook = Workbooks.Open(theOrigin)
lastRow = Range("A65536").End(xlUp).Row
lastCol = Range("XFD1").End(xlToLeft).Column
lastCol = originBook.Sheets(1).Cells(1, Columns.Count).End(xlToLeft).Column
originBook.Sheets(2).Visible = False
originBook.Sheets(3).Visible = False
originBook.Sheets(1).Range(Cells(1, 1), Cells(lastRow, lastCol)).Copy
macroBook.Sheets(1).Cells(6, 1).PasteSpecial
i = 1000
Do While 1000 <= 20000
j = i - 999
If originBook.Sheets(1).Cells(i, 1).Value <> vbNullString Or _
originBook.Sheets(1).Cells(i, 1).Value <> "" Then
originBook.Sheets(1).Range(Cells(j, 1), Cells(i - 1, lastCol)).Copy
macroBook.Sheets(1).Cells(j + 5, 1).PasteSpecial
End If
i = i + 1000
Loop
originBook.Sheets(2).Visible = True
originBook.Sheets(3).Visible = True
End If
If originOpen = True Then
originBook.Close
End If
End Sub
which one should I change?

Your error will almost certainly be because you are using
originBook.Sheets(1).Range(Cells(1, 1), Cells(lastRow, lastCol)).Copy
instead of, as #ShaiRado pointed out,
originBook.Sheets(1).Range(originBook.Sheets(1).Cells(1, 1), _
originBook.Sheets(1).Cells(lastRow, lastCol)).Copy
When they are not fully qualified, Cells references refer to cells on the ActiveSheet. Excel is therefore having to try to copy all the cells on Sheets(1) that lie in the area between two cells on the ActiveSheet. It's equivalent to saying "choose all the houses in Los Angeles that lie in the area between the intersection of E 79th St and 1st Avenue and the intersection of E 86th St and York Ave New York". (Not living in the USA, I hope that analogy makes sense.)

Related

How set Each For keep current cell check until a condition be true VBA

I want to check if a cell in a sheet s4 has the same value for each cell in the sheet s1
So i tried to "stop" the Next c setting the c value as the previous cell, until the condition be true.
i put msgbox c.Value & "hiiiii" to check the c position, and is always the next cell.
Dim s1 As Worksheet
Dim s2 As Worksheet
Dim s3 As Worksheet
Dim s4 As Worksheet
Set s1 = ThisWorkbook.Sheets("test1")
Set s2 = ThisWorkbook.Sheets("test2")
Set s3 = ThisWorkbook.Sheets("test3")
Set s4 = ThisWorkbook.Sheets("test4")
Dim l As Integer
l = 8
lastrow = s4.Range("J" & s4.Rows.count).End(xlUp).row
Set rd = s4.Range("J2:J" & lastrow)
Set rf = s1.Range("A" & l)
For Each c In rd
msgbox c.Value & "hiiiii"
If rf.Value = "" Then: Exit For
If c.Value = rf.Value Then
s1.Range("B" & l).Value = c.Offset(, -1)
l = 8
Set rf = s1.Range("A" & l)
Else
l = l + 1
Set rf = s1.Range("A" & l)
Set c = c.Offset(-1, 0)
End If
Next c
There's a way to make it works?
Thank you
EDIT 1:
After some hours of breaking my head i changed the code and now it is working:
Dim l As Integer
Dim i As Integer
lastrow = s4.Range("J" & s4.Rows.count).End(xlUp).row
LastRow2 = s1.Range("A" & s1.Rows.count).End(xlUp).row
l = 8
i = 8
Set rd = s4.Range("J2:J" & lastrow)
Set rf = s1.Range("A" & i)
For Each c In rd
If c.Value <> rf.Value Then
For i = 8 To LastRow2
Set rf = s1.Range("A" & i)
If rf.Value = c.Value Then
rf.Offset(, 1).Value = c.Offset(, -1)
End If
Next i
Else
rf.Offset(, 1).Value = c.Offset(, -1)
End If
Next c
End Sub
A special thanks for Cyril and his tip about the another for options.
Screenshots/here refer:
CONSTRUCT
Fixed: comprises list of cells - press CMD button 'RUN' to select which values you want to compare against every populated cell of every other sheet.
This runs the macro Soln() (below).
test1-test3: arbitrary sheets comprising a medley of matching and mis-matched cell values/text etc. (contiguous / isolated cells etc.). Most content in test 1.
Audit_Trail: This will be removed/deleted if it exists when you run the macro so that a fresh sheet can be produced. This will display, for each target cell (selected step 1) and sheet (see 2) every cell (sheet/link/content) that did not match the respective target values.
CODE
(essential modules: Soln(), select cells - all the rest is 'bonus' - hope this works/helps you - assuming I understood issue correclty☺.)
Global addr(), target_cells(), s As String
Sub s_(new_txt)
Application.StatusBar = False
s = s & " --> " & new_txt
Application.StatusBar = s
End Sub
Sub Soln()
Application.StatusBar = False
s_ ("sub soln")
'Application.StatusBar = "Sub Soln()"
ReDim Preserve addr(0), target_cells(0)
Sheets("fixed").Move Before:=Sheets(1)
Call select_cells
Application.ScreenUpdating = False
m = -1
N_ = -1
K_ = -1
'Sheets(1).Activate
If sheet_exists("Audit_Trail") Then
Application.DisplayAlerts = False
Sheets("Audit_Trail").Delete
ThisWorkbook.Sheets.Add( _
After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count)).Name = "Audit_Trail"
Application.DisplayAlerts = True
End If
With Sheets("Audit_Trail")
.Range("a1").Value = "Target_value"
.Range("b1").Value = "Sheet"
.Range("c1").Value = "Link/Content"
End With
For Each sh In ActiveWorkbook.Sheets
For Each yy In target_cells
sh.Activate
If (sh.Name = "fixed") Or (sh.Name = "Audit_Trail") Then
Exit For
'ActiveSheet.Next.Select
Else
On Error Resume Next
Selection.SpecialCells(xlCellTypeConstants, 23).Select
For Each c In Selection
If c.Value = yy Then
Resume Next
Else
addr_temp = Evaluate("ADDRESS(" & c.Row & "," & c.Column & ",1,1,""" & c.Worksheet.Name & """)")
With Sheets("Audit_Trail")
m = m + 1
.Range("a2").Offset(m).Value = yy
.Range("b2").Offset(m).Value = sh.Name
.Range("c2").Offset(m).Value = "=" & addr_temp
End With
End If
Next
End If
Next
Next
Application.ScreenUpdating = True
Application.StatusBar = False
Call pivot_summary
End Sub
Sub select_cells() '#Tim Williams (2011) - https://stackoverflow.com/questions/7353711/let-the-user-click-on-the-cells-as-their-input-for-an-excel-inputbox-using-vba
s_ ("sub select_cells()")
Dim rRange As Range
N_ = -1
On Error Resume Next
Application.DisplayAlerts = False
Sheets("fixed").Activate
Default_ = Sheets("fixed").Range("J2:J4").Address
Set rRange = Application.InputBox(Prompt:= _
"Please select range with cells you would like to compare against every other cell in this workbook.", Title:="SPECIFY RANGE", Default:=Default_, Type:=8)
Application.DisplayAlerts = True
If rRange Is Nothing Then
Exit Sub
Else
For Each c In rRange
N_ = N_ + 1
ReDim Preserve target_cells(0 To N_)
target_cells(N_) = c.Value
Next
End If
Return
End Sub
Function sheet_exists(sh As String) As Boolean
s_ ("sheet_exists()")
'Dim w As Excel.Worksheet
On Error GoTo eHandle
Set w = ThisWorkbook.Worksheets(sh)
sheet_exists = True
Exit Function
eHandle:
sheet_exists = False
End Function
'******not really required - could ignore *********'
Sub pivot_summary()
Range("a1").Select
Range(Selection, Selection.End(xlDown)).Select
Range(Selection, Selection.End(xlToRight)).Select
ActiveWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:= _
Selection, Version:=8).CreatePivotTable TableDestination:= _
ActiveSheet.Range("g2"), TableName:="PivotTable5", _
DefaultVersion:=8
With ActiveSheet.PivotTables("PivotTable5").PivotFields("Target_value")
.Orientation = xlRowField
.Position = 1
End With
With ActiveSheet.PivotTables("PivotTable5").PivotFields("Sheet")
.Orientation = xlRowField
.Position = 2
End With
ActiveSheet.PivotTables("PivotTable5").AddDataField ActiveSheet.PivotTables( _
"PivotTable5").PivotFields("Link/Content"), "Sum of Link/Content", xlSum
With ActiveSheet.PivotTables("PivotTable5").PivotFields("Sum of Link/Content")
.Caption = "Count of Link/Content"
.Function = xlCount
End With
ActiveSheet.PivotTables("PivotTable5").CompactLayoutRowHeader = "Target"
Range("H2").Select
ActiveSheet.PivotTables("PivotTable5").DataPivotField.PivotItems( _
"Count of Link/Content").Caption = "# mismatch"
Columns("G:H").Select
Selection.ColumnWidth = 11.27
Selection.Font.Name = "Brush Script MT"
Range("G22").Select
ActiveCell.FormulaR1C1 = "That's all folks! ?"
Range("G23").Select
ActiveWorkbook.Save
End Sub
GIF DEMO
OTHER INFO
To replicate for a single value, simply uapte the list in 1 (fixed) accordingly
This also creates a pivot in the Audit_Trail sheet summarises the extent of mismatches per sheet for each desired 'target value'.

VBA Macro is ignoring nextBlankRow and duplicates

What I want the Macro to accomplish:
I want the user to be able to fill in data from E2 to E9 on the spreadsheet. When the user presses the "Add Car" button the macro is supposed to be executed. The makro then should take the handwritten data, copy everything from E2:E9 and put it into a table that starts at with C13 and spans over 7 columns, always putting the new set of data in the next free row. It is also supposed to check for duplicates and give an alert while not overwriting the original set of data
So my problem is, that I want the Macro I'm writing to take the information put into certain cells and then copy them into a table underneath.
I'm starting the Macro like this
Sub addData()
Dim lastrow As Long, nextBlankRow As Long
lastrow = Cells.Find(What:="*", _
After:=Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlPrevious, _
MatchCase:=False).Row
nextBlankRow = lastrow + 1
Here I try to define how the Macro is supposed to find the last empty cell and also define lastrow and nextBlankRow.
After that I'm starting with a simple If statement to see if the person has at least something in E2 on the same sheet.
If Range("E2") = "" Then
MsgBox "Wählen Sie ein KFZ aus!"
Range("E2").Select
Exit Sub
End If
This works. When I'm not putting something into E2 I get the textbox with the alert.
Anyway if the IF-Statement is not triggered to exit the sub the Macro is given the instructions to get the information and put it in the table below
Cells(nextBlankRow, 3) = Range("E2")
Cells(nextBlankRow, 4) = Range("E3")
Cells(nextBlankRow, 5) = Range("E4")
Cells(nextBlankRow, 6) = Range("E5")
Cells(nextBlankRow, 7) = Range("E6")
Cells(nextBlankRow, 8) = Range("E7")
Cells(nextBlankRow, 9) = Range("E8")
Here seems to be a problem that probably relates to me failing to define variables correctly?
Because the Macro finds the right row but only overwrites into that row. So it ignores the fact that it "should" skip to the nextBlankrow which I defined earlier as
nextBlankRow = lastrow + 1
In addition to that I also have a line of code inplace which is supposed to check for duplicates
Dim p As Long, q As Long
p = 13
q = p + 1
Do While Cells(p, 3) <> ""
Do While Cells(q, 3) <> ""
If Cells(p, 3) = Cells(q, 3) And Cells(p, 4) = Cells(q, 4) Then
MsgBox "Datensatz schon vorhanden!"
Range(Cells(q, 3), Cells(q, 9)).ClearContents
Else
q = q + 1
End If
Loop
p = p + 1
q = p + 1
Loop
End Sub
Which always gives a false return. So even if the same set of Data is copied twice into the same row (as it does) it only "refreshes" the data and doesn't say "you're not allowed to do that".
I'm at a loss here.
Here's the full code for ease of use
Sub addData()
Dim lastrow As Long, nextBlankRow As Long
lastrow = Cells.Find(What:="*", _
After:=Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlPrevious, _
MatchCase:=False).Row
nextBlankRow = lastrow + 1
If Range("E2") = "" Then
MsgBox "Wählen Sie ein KFZ aus!"
Range("E2").Select
Exit Sub
End If
Cells(nextBlankRow, 3) = Range("E2")
Cells(nextBlankRow, 4) = Range("E3")
Cells(nextBlankRow, 5) = Range("E4")
Cells(nextBlankRow, 6) = Range("E5")
Cells(nextBlankRow, 7) = Range("E6")
Cells(nextBlankRow, 8) = Range("E7")
Cells(nextBlankRow, 9) = Range("E8")
Dim p As Long, q As Long
p = 13
q = p + 1
Do While Cells(p, 3) <> ""
Do While Cells(q, 3) <> ""
If Cells(p, 3) = Cells(q, 3) And Cells(p, 4) = Cells(q, 4) Then
MsgBox "Datensatz schon vorhanden!"
Range(Cells(q, 3), Cells(q, 9)).ClearContents
Else
q = q + 1
End If
Loop
p = p + 1
q = p + 1
Loop
End Sub
```![enter image description here](https://i.stack.imgur.com/dJozM.jpg)![enter image description here](https://i.stack.imgur.com/Q90Ah.jpg)
Please, test the next code:
Sub copyRangeOnLastEmptyRow()
Dim sh As Worksheet, arr, lastERow As Long, matchCel As Range
Set sh = ActiveSheet
arr = sh.Range("E2:E9").value
lastERow = sh.Range("C" & sh.rows.Count).End(xlUp).row + 1
If lastERow < 13 Then lastERow = 13
'check if the range has not been alredy copied:
Set matchCel = sh.Range("C13:C" & lastERow - 1).Find(WHAT:=sh.Range("E2").value, LookIn:=xlValues, Lookat:=xlWhole, MatchCase:=False)
If Not matchCel Is Nothing Then
MsgBox sh.Range("E2").value & " has been found in cell " & matchCel.Address & "."
'bring up the data of the existing row:
sh.Range("E3:E9").value = Application.Transpose(sh.Range(matchCel.Offset(0, 1), matchCel.Offset(0, 7)).value)
Exit Sub
End If
sh.Range("C" & lastERow).Resize(1, UBound(arr)).value = Application.Transpose(arr)
sh.Range("E2:E9").ClearContents
End Sub

Need to copy columns to new sheet, but certain cells need to be concatenated and cleaned up

This is my first time using VBA and macros in excel, or excel really for that matter. I appreciate any help or insight that you could give me, ranging from what functions to loops can help me succeed in this task
I am trying to get this workbook set up from this:
Sample Work Book
I get a list that has to be reordered in order to import into another system. My task list is as follows for a macro:
Names and companies have to be merged into one, if there is a different name of a person, that must be concatenated. There will not be two different companies per company header.
Every File ID per company must be concatenated
Individual fees must be replaced with total fee per company.
Sorted by internal ID #, A-Z
Only one header on the new sheet
To look like this:
Target Work Book
My code below runs this: Current Progress
Sub format()
Application.ScreenUpdating = False
'This is the setup to get rid of unnecessary cells'
Dim rCell As Range
Dim cRow As Long, LastRow As Long
LastRow = Worksheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
'''Delete Merged Cells'''
With Worksheets("Sheet1").Range("A1", Worksheets("Sheet1").Range("A" & Rows.Count).End(xlUp))
Do
Set c = .Find(What:="*Company Name:*", After:=[A1], LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
If Not c Is Nothing Then
cRow = c.Row
c.EntireRow.Delete
End If
Loop While Not c Is Nothing And cRow < LastRow
End With
'''Delete Headings'''
With Worksheets("Sheet1").Range("A1", Worksheets("Sheet1").Range("B" & Rows.Count).End(xlUp))
Do
Set c = .Find(What:="*File #*", After:=[A1], LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
If Not c Is Nothing Then
cRow = c.Row
c.EntireRow.Delete
End If
Loop While Not c Is Nothing And cRow < LastRow
End With
''' Delete Sub Total"""
With Worksheets("Sheet1").Range("A1", Worksheets("Sheet1").Range("B" & Rows.Count).End(xlUp))
Do
Set c = .Find(What:="*Sub Total:*", After:=[A1], LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
If Not c Is Nothing Then
cRow = c.Row
c.EntireRow.Delete
End If
Loop While Not c Is Nothing And cRow < LastRow
End With
End Sub
Again, I appreciate any help on this matter. Thank you!
There are a lot of ways to loop through the cells.
I picked column D with the company name as it didn't have too much clutter.
It's usually good to find the last row, to not loop through cells that we don't need. THere is a lot of ways for doing so as well. Today we'll go with Range("D" & .Rows.Count).End(xlUp).Row.
For the loop, we can use the For next approach, example:
For i = 1 To Sheets(1).Range("A" & Sheets(1).Rows.Count).End(xlUp).Row
If Not Cells(i, 4).Value = "" Then
Next i
But this time, I went with the For Each, because I think it's a bit more readable.
Sub groupingEach()
Dim entry As Variant, prev As String, lRow As Long, lRow2 As Long
Dim inSht As Worksheet, outSht As Worksheet
Set inSht = Sheets(1)
Set outSht = Sheets(2)
lRow = inSht.Range("D" & inSht.Rows.Count).End(xlUp).Row 'last row
For Each entry In inSht.Range("D1:D" & lRow) 'loop 1st sheet
lRow2 = outSht.Range("D" & outSht.Rows.Count).End(xlUp).Row 'last row in output
If entry = prev And Not entry = "" Then
'-Group'
If InStr(outSht.Cells(lRow2, 3), entry.Offset(, 1)) = 0 Then 'does name exist?
outSht.Cells(lRow2, 3) = outSht.Cells(lRow2, 3) & vbNewLine & entry.Offset(, 1)
End If
outSht.Cells(lRow2, 5) = outSht.Cells(lRow2, 5) & vbNewLine & entry.Offset(, -2)
outSht.Cells(lRow2, 6) = outSht.Cells(lRow2, 6) + entry.Offset(, 2)
ElseIf Not entry = prev And Not entry = "" And Not entry = "Company" Then
'-New row
prev = entry 'Save company name for comparison
outSht.Cells(lRow2 + 1, 1) = entry.Offset(, -3)
outSht.Cells(lRow2 + 1, 2) = "Payable" 'Where to get this value?
outSht.Cells(lRow2 + 1, 3) = entry.Offset(, 1)
outSht.Cells(lRow2 + 1, 4) = entry
outSht.Cells(lRow2 + 1, 5) = entry.Offset(, -2)
outSht.Cells(lRow2 + 1, 6) = entry.Offset(, 2)
End If
Next entry
outSht.Cells(lRow2 + 3, 1).Value = "Grand Total:"
outSht.Cells(lRow2 + 3, 2).Formula = "=SUM(F:F)"
End Sub
From the examples, this should handle the document all the way from the Sample to the target. I wanted to loop the value copying, but the change in column order made it annoying.

controlling excel cells and writing it to other cells

I have a excel sheet like at below. I want to find some strings in my excel's third cell. The string is 180 days. When the cell value includes 180 days, I want write previous cells value in next to empty cells like in below picture. I want to write process plan in first cell, operation title in second cell. I wrote this codes but it's not working like what I want.
Sub Button1_Click()
Dim excelRange As Long
Dim i As Long
Dim k As Long
'Dim txt As String
excelRange = ActiveSheet.Cells(1048576, 3).End(xlUp).Row
k = 2
For a = 2 To excelRange
txt = Cells(a, 3)
k = a
If InStr(1, txt, "180 days") > 0 Then
For i = a To 2 Step -1
txt1 = Cells(i, 3)
If InStr(1, txt1, "Oper Title") > 0 Then
Cells(a, 2) = Cells((k + 1), 3)
ElseIf InStr(1, txt1, "Process") > 0 Then
Cells(a, 1) = Cells(k, 3)
Else:
k = k - 1
End If
Next i
End If
Next a
End Sub
Sub test()
Dim excelRange As Range
Dim criteriRange As Range
Dim evaluateRange As Range
Dim c As Range
Dim i As Long
Set excelRange = Range("C1:C" & Cells(1048576, 3).End(xlUp).Row)
For Each cell In excelRange
If UCase(cell.Text) Like "*180 DAY*" Then
If criteriRange Is Nothing Then
Set criteriRange = cell
Else
Set criteriRange = Union(criteriRange, cell)
End If
End If
Next
If Not criteriRange Is Nothing Then
For Each c In criteriRange
For i = c.Row To 1 Step -1
If UCase(Cells(i, 3)) Like "*PROCESS PLAN*" Then
c.Offset(0, -2) = Cells(i, 3)
Exit For
End If
Next
For i = c.Row To 1 Step -1
If UCase(Cells(i, 3)) Like "*OPER TITLE*" Then
c.Offset(0, -1) = Cells(i + 1, 3)
Exit For
End If
Next
Next
End If
End Sub
Instead of looping through a range, your macro will run much faster if you use the Range.Find method.
In your code, you did not check to ensure that all of your sets of Process | Title | 180 Days are complete. I added that to the code below, by making sure that the Process and Title rows were found after the previous 180 day row (or before the 180 day row for the first instance).
In your code, you did not check to see if the cells where you want to output this information are, in fact, empty. If you really want to do that, you can easily modify this code to check these cells before writing to them.
Hopefully, through the comments and the use of meaningful variable names, you will be able to understand what is going on. But you might want to also read through VBA Help for the Range.Find method.
In general, we search down to find the 180 day row, then search up from there to find the associated Process and Title rows.
If a preceding Process or Title row should be before the preceding 180 day row, then we have an incomplete set, output the error message, and terminate the procedure.
If necessary, you could develop procedures to deal with incomplete data sets.
Option Explicit
Sub Info()
Dim searchRng As Range, C As Range, cProcessPlan As Range, cOperTitle As Range
Dim firstAddress As String 'to check when we are done
Dim lastAddress As String 'to check for incomplete data sets
'Where are we looking?
Set searchRng = ThisWorkbook.Worksheets("Sheet1").Columns(3)
With searchRng
Set C = .Find(what:="180 Days", after:=.Cells(1, 1), LookIn:=xlValues, _
lookat:=xlPart, searchorder:=xlByRows, _
searchdirection:=xlNext, MatchCase:=False)
If Not C Is Nothing Then
firstAddress = C.Address
lastAddress = C.Address
Set cOperTitle = .Find(what:="Oper Title", after:=C, searchdirection:=xlPrevious)
Set cProcessPlan = .Find(what:="Process Plan", after:=C, searchdirection:=xlPrevious)
If Not cOperTitle Is Nothing Or Not cProcessPlan Is Nothing Then
'check for full set
If cOperTitle.Row > Range(lastAddress).Row Or cProcessPlan.Row > Range(lastAddress).Row Then
MsgBox "Incomplete Data Set" & vbLf & "Before: " & C.Address
Exit Sub
End If
C.Offset(0, -1) = cOperTitle.Offset(1, 0)
C.Offset(0, -2) = cProcessPlan
Else
MsgBox "Title or Process Plan not found"
Exit Sub
End If
Do
Set C = .Find(what:="180 Days", after:=C, LookIn:=xlValues, _
lookat:=xlPart, searchorder:=xlByRows, _
searchdirection:=xlNext, MatchCase:=False)
If C.Address = firstAddress Then Exit Do
Set cOperTitle = .Find(what:="Oper Title", after:=C, searchdirection:=xlPrevious)
Set cProcessPlan = .Find(what:="Process Plan", after:=C, searchdirection:=xlPrevious)
'check for a full set
If cOperTitle.Row < Range(lastAddress).Row Or cProcessPlan.Row < Range(lastAddress).Row Then
MsgBox "Incomplete Data Set" & vbLf & "Between: " & lastAddress & " and " & C.Address
Exit Sub
End If
C.Offset(0, -1) = cOperTitle.Offset(1, 0)
C.Offset(0, -2) = cProcessPlan
lastAddress = C.Address
Loop
End If
End With
'next stuff
End Sub
Using a variant array is fast.
Sub test()
Dim Ws As Worksheet
Dim rngDB As Range
Dim vDB As Variant
Dim vRow(), vTitle(), vProcess()
Dim i As Long, j As Long, k As Long, m As Long
Set Ws = ActiveSheet
With Ws
Set rngDB = .Range("a1", .Range("c" & Rows.Count).End(xlUp))
End With
vDB = rngDB
For i = 1 To UBound(vDB, 1)
If InStr(vDB(i, 3), "180 days") Then
j = j + 1
ReDim Preserve vRow(1 To j)
vRow(j) = i
ElseIf InStr(vDB(i, 3), "Oper Title") Then
k = k + 1
ReDim Preserve vTitle(1 To k)
vTitle(k) = vDB(i + 1, 3)
ElseIf InStr(vDB(i, 3), "Process") Then
m = m + 1
ReDim Preserve vProcess(1 To m)
vProcess(m) = vDB(i, 3)
End If
Next i
For i = 1 To j
vDB(vRow(i), 1) = vProcess(i)
vDB(vRow(i), 2) = vTitle(i)
Next i
rngDB = vDB
End Sub

From data in an excel file, write new excel files populated with data based on a column's value

I am essentially trying to slice my "master excel" file into a bunch of new files using the same data. I am able to create the new file, make an entry and then save; however, I am unable to add multiple entries into one file. I feel like I'm brain farting on some basic coding logic.
The master excel file looks as follows:
A B C D
1 XXX-01 100 Description1 4
2 XXX-01 104 Description2 2
3 XXX-01 209 Description3 3
4 XXX-02 102 Description4 5
5 XXX-02 355 Description5 1
6 XXX-02 322 Description6 1
7 XXX-02 943 Description7 9
8 XXX-02 231 Description8 4
9 XXX-03 124 Description9 4
10 XXX-03 555 Description10 2
Where
A: GroupID
B: Part_Number
C: Description
D: Quantity
My desire, from the above, would to make 3 excel files (XXX-01, XXX-02, XXX-03) where each file contains it's respective data.
For instance, XXX-01.xlsx would look like the following:
A B C D
1 Item# Part Description Qty
2 1 100 Description1 4
3 2 104 Description2 2
4 3 209 Description3 3
Where row 1 is for headers that are the same for each XXX-## file.
In order to establish a baseline of where my code is at: the following works to create the file insert one row, but will then close and overwrite the previous file. (Stolen from: Create, name, and populate new workbook with data)
Sub CreateBooks()
Dim oCell As Excel.Range
Dim oWorkbook As Excel.Workbook
Application.DisplayAlerts = False
For Each oCell In Range("A:A")
If oCell.Value = "" Then Exit For
Set oWorkbook = Workbooks.Add
oWorkbook.Sheets(1).Cells(1, 1).Value = oCell.Offset(0, 1).Value
oWorkbook.Close True, oCell.Value
Next oCell
Application.DisplayAlerts = True
End Sub
I added the following in order to insert my save path into column A of the Master:
Dim Path As String
Path = "C:\Users\MyComputer\Documents"
For Each oCell In Range("A:A")
If oCell.Value = "" Then Exit For
oCell.Value = Path & oCell.Value
Next oCell
My goal with the below edits was to get the for loop to repeat if the cell below oCell is equivalent to the value of oCell. Perhaps a Do While loop would be more applicable here; however.
Dim Row_Counter As Integer
For Each oCell In Range("A:A")
If oCell.Value = "" Then Exit For
Set oWorkbook = Workbooks.Add
oWorkbook.Sheets(1).Cells(Row_Counter, 2).Value = oCell.Offset(0, 1).Value
oWorkbook.Sheets(1).Cells(Row_Counter, 3).Value = oCell.Offset(0, 2).Value
oWorkbook.Sheets(1).Cells(Row_Counter, 4).Value = oCell.Offset(0, 3).Value
For Each Next_oCell In Range("A:A")
If Next_oCell.Value = oCell.Value Then
Row_Counter = Row_Counter + 1
oWorkbook.Sheets(1).Cells(Row_Counter, 2).Value = Next_oCell.Offset(0, 1).Value
oWorkbook.Sheets(1).Cells(Row_Counter, 3).Value = Next_oCell.Offset(0, 2).Value
oWorkbook.Sheets(1).Cells(Row_Counter, 4).Value = Next_oCell.Offset(0, 3).Value
End If
Next Next_oCell
That being said, I am still only getting the one file that is being overwritten. I think my issue (or at least one of them) is that I don't have a means of saying "go through all rows with this value in column A, then skip to the first row with a new number."
Any help would be greatly appreciated!
Here's one approach:
Sub Divide()
Dim dict As Object, v, k, c As Range, i As Long, sht As Worksheet
Set dict = CreateObject("scripting.dictionary")
'collect all the distinct values and matching cell references
For Each c In Range("A:A")
v = c.Value
If Len(v) = 0 Then Exit For
If Not dict.exists(v) Then dict.Add v, New Collection 'new key if needed
dict(v).Add c 'add the cell to the appropriate collection
Next c
'process each group id in turn
For Each k In dict.keys
'create and save a workbook (to the same location as this workbook)
With Workbooks.Add
.SaveAs ThisWorkbook.Path & "\" & k & ".xlsx"
.Sheets(1).Range("a1").Resize(1, 4).Value = _
Array("Item#", "Part", "Description", "Qty")
i = 1
'process each cell in the collection for this Group
For Each c In dict(k)
.Sheets(1).Cells(i + 1, 1).Value = i
.Sheets(1).Cells(i + 1, 2).Resize(1, 3).Value = _
c.Offset(0, 1).Resize(1, 3).Value
i = i + 1
Next c
.Close True 'save changes
End With
Next k
End Sub
Does this solution work?
Sub SeperateMasterFile()
'
' This part of the macro sorts Column A in Ascending Order
Dim lRowD As Long
Dim lRowA As Long
'Find the last non-blank cell in column D(4)
lRowD = Cells(Rows.Count, 4).End(xlUp).Row
'
'Find the last non-blank cell in column A(1)
lRowA = Cells(Rows.Count, 1).End(xlUp).Row
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add2 Key:=Range("A1"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range("A1:D" & lRowD)
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Dim LastI As Integer
Dim NewValueInColumnA As String
Dim NewValueInColumnARowNumber As Integer
For I = 1 To lRowA + 1
LastI = I - 1
'If LastI = 0 then we will make LastI = 1, because Range"(A0)".select would be invalid
If LastI = 0 Then
I = 1
End If
'When the For loop starts the following if statement
'will put the value in A1 into the variable NewValueInColumnA
If NewValueInColumnA = "" Then
NewValueInColumnA = Range("A1").Text
NewValueInColumnARowNumber = 1
End If
If NewValueInColumnA = Range("A" & I) Then
Else
'If A3 has a different value to A2, then the following code selects A1:D2
'If A7 has a different value to A6, then the following code selects A3:D6
Range("A" & NewValueInColumnARowNumber & ":D" & LastI).Select
NewValueInColumnARowNumber = I
NewValueInColumnA = Range("A" & I)
'The following code now runs the macro called 'MoveToNewWorkBook'
Call MoveToNewWorkbook
End If
Next I
End Sub
Sub MoveToNewWorkbook()
'
' MoveToNewWorkbook Macro
'
Selection.Copy
Workbooks.Add
Range("A2").Select
ActiveSheet.Paste
Application.CutCopyMode = False
Range("A1").Value = "Item#"
Range("B1").Value = "Part"
Range("C1").Value = "Description"
Range("D1").Value = "QTY"
ActiveWorkbook.SaveAs Filename:="C:\Users\HP\Documents\" & Range("A2").Text & ".xlsx", _
FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
ActiveWindow.Close
End Sub

Resources