Excel VBA: Split to Multiple Sheets - vba

I'm creating a UserForm that allows the user to select a sheet to perform the macro on and enter in X amount of rows in which the ultimate goal is to split the selected sheet into multiple sheets by X amount of rows.
Code:
Dim rowCount As Long
Dim rowEntered As Long
Dim doMath As Long
rowCount = Sheets(Me.ComboBox1.Value).Cells(Rows.Count, "A").End(xlUp).Row 'Count Number of Rows in selected Sheet
rowEntered = Val(Me.TextBox1.Value) 'User enters X amount
If rowCount < rowEntered Then
MsgBox "Enter in another number"
Else
doMath = (rowCount / rowEntered)
For i = 1 to doMath
Sheets.Add.name = "New-" & i
Next i
'Help!!
For i= 1 to doMath
Sheets("New-" & i).Rows("1:" & rowEntered).Value = Sheets(Me.ComboBox1.Value).Rows("1:" & rowEntered).Value
Next i
End If
The last section of code is where I need help because I can't seem to figure out how to do it properly..
The code currently loops through the newly added sheets and "pastes" in the same rows. For example, if the sheet selected has 1000 rows (rowCount), and rowEntered is 500, then it would create 2 new sheets. Rows 1-500 should go in New-1 and Rows 501-1000 should go into New-2. How can I achieve this?

Check below code. Please, read comments.
Option Explicit
'this procedure fires up with button click
Sub Button1_Click()
SplitDataToSheets Me.ComboBox1.Value, CInt(Me.TextBox1.Value)
End Sub
'this is main procedure
Sub SplitDataToSheets(ByVal shName As String, ByVal rowAmount As Long)
Dim srcWsh As Worksheet, dstWsh As Worksheet
Dim rowCount As Long, sheetsToCreate As Long
Dim i As Integer, j As Long
'handle events
On Error GoTo Err_SplitDataToSheets
'define source worksheet
Set srcWsh = ThisWorkbook.Worksheets(shName)
'Count Number of Rows in selected Sheet
rowCount = srcWsh.Range("A" & srcWsh.Rows.Count).End(xlUp).Row
'calculate the number of sheets to create
sheetsToCreate = CInt(rowCount / rowAmount) + IIf(rowCount Mod rowAmount > 0, 1, 0)
If rowCount < rowAmount Then
If MsgBox("The number of rows in source sheet is less then number of " & vbCr & vbCr & _
"The rest of message", vbQuestion + vbYesNo + vbDefaultButton2, "Question..") = vbYes Then GoTo Exit_SplitDataToSheets
End If
'
j = 0
'create the number of sheets in a loop
For i = 1 To sheetsToCreate
'check if sheet exists
If SheetExists(ThisWorkbook, "New-" & i) Then
'clear entire sheet
Set dstWsh = ThisWorkbook.Worksheets("New-" & i)
dstWsh.Cells.Delete Shift:=xlShiftUp
Else
'add new sheet
ThisWorkbook.Worksheets.Add After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count)
Set dstWsh = ActiveSheet
dstWsh.Name = "New-" & i
End If
'copy data
srcWsh.Range("A" & j + 1 & ":A" & j + rowAmount).EntireRow.Copy dstWsh.Range("A1")
'increase a "counter"
j = j + rowAmount
Next i
'exit sub-procedure
Exit_SplitDataToSheets:
On Error Resume Next
Set srcWsh = Nothing
Set dstWsh = Nothing
Exit Sub
'error sub-procedure
Err_SplitDataToSheets:
MsgBox Err.Description, vbExclamation, Err.Number
Resume Exit_SplitDataToSheets
End Sub
'function to check if sheet exists
Function SheetExists(ByVal wbk As Workbook, ByVal wshName As String) As Boolean
Dim bRetVal As Boolean
Dim wsh As Worksheet
On Error Resume Next
Set wsh = wbk.Worksheets(wshName)
bRetVal = (Err.Number = 0)
If bRetVal Then Err.Clear
SheetExists = bRetVal
End Function
Try!

Modify that problematic code snippet as shown below:
For i = 1 To doMath
Sheets("New-" & i).Range("1:" & rowEntered).Value = Sheets(Me.ComboBox1.Value).Range((i - 1) * rowEntered + 1 & ":" & i * rowEntered).Value
Next i
Also modify the following line to calculate the "Ceiling" value:
doMath = Fix(rowCount / rowEntered) + IIf(rowCount Mod rowEntered > 0, 1, 0)
The simulated VBA "Ceiling" function used to calculate the doMath value could be also written as:
doMath = Int(RowCount / rowEntered) + Abs(RowCount Mod rowEntered > 0)
Note: In this particular sample, you can use VBA INT and FIX functions interchangeably.
Hope this will help.

Related

search for multiple strings to delete within a excel worksheet

In my VBA code below it searches for any cell for red to delete. The line is at
Dim colors_to_delete As String: colors_to_delete = "red"
What would I add to this code so it delete red and blue?
Sub collapse_columns()
Dim x As Integer
For x = 1 To 4
collapse_column x
Next
End Sub
Sub collapse_column(column_number As Integer)
Dim row As Long
Dim s As Worksheet
Dim last_row As Long
Set s = ActiveSheet ' work on the active sheet
'Set s = Worksheets("Sheet1") 'work on a specific sheet
last_row = s.Cells(s.Rows.Count, column_number).End(xlUp).row
Dim colors_to_delete As String: colors_to_delete = "red"
For row = last_row To 1 Step -1
If InStr(1, " " & s.Cells(row, column_number).Value & " ", " " & colors_to_delete & " ") > 0 Then
s.Cells(row, column_number).Delete xlUp
End If
Next row
End Sub
You could use an array of color names:
Sub collapse_column(column_number As Integer)
Dim row As Long
Dim s As Worksheet
Dim last_row As Long, clr, c as Range
Set s = ActiveSheet ' work on the active sheet
last_row = s.Cells(s.Rows.Count, column_number).End(xlUp).row
For row = last_row To 1 Step -1
Set c = s.Cells(row, column_number)
For Each clr in Array("red", "blue") '<< array to check against
If InStr(1, " " & c.Value & " ", " " & clr & " ") > 0 Then
c.Delete xlUp
Exit For 'stop checking
End If
Next clr
Next row
End Sub

VBA - How to match headers from two different sheet to make sure they are same name and at same order?

I have two excel sheet ReportOld and ReportNew, what I want to check and make sure all the column herder from both sheets are matching name and in same order. Basically need to check there should not be any new column added or removed from last report.. bot are identical.
Till now I tried the code is:
Sub colLookup()
Dim ShtOne As Worksheet, ShtTwo As Worksheet
Dim shtOneHead As Range, shtTwoHead As Range
Dim headerOne As Range, headerTwo As Range
Dim x As Integer
Dim lastCol As Long
Set ShtOne = Sheets("ReportOld")
Set ShtTwo = Sheets("ReportNew")
lastCol = ShtOne.Cells(1, Columns.Count).End(xlToLeft).Column
Set shtOneHead = ShtOne.Range("A1", ShtOne.Cells(1, lastCol))
lastCol = ShtTwo.Cells(1, Columns.Count).End(xlToLeft).Column
Set shtTwoHead = ShtTwo.Range("A1", ShtTwo.Cells(1, lastCol))
For Each headerTwo In shtTwoHead
For Each headerOne In shtOneHead
If headerTwo.Value = headerOne.Value Then
Else
x = MsgBox("Headers are not matching in both sheets.")
MsgBox "value is:" & headerTwo.Value
Exit Sub
End If
Next headerOne
Next headerTwo
End Sub
Try this code. It counts the headings on both sheets and fills an array of headings from both sheets. Then it compares the headings one each sheet and displays a message if the headings don't match. It then compares the number of columns and if they don't match, another message is displayed...
Sub colLookup()
Dim ShtOne As Worksheet, ShtTwo As Worksheet
Dim shtOneHead As Range, shtTwoHead As Range
Dim headerOne As Range, headerTwo As Range
Dim x As Integer
Dim lastCol As Long
Set ShtOne = Sheets("ReportOld")
Set ShtTwo = Sheets("ReportNew")
lastCol = ShtOne.Cells(1, Columns.Count).End(xlToLeft).Column
Set shtOneHead = ShtOne.Range("A1", ShtOne.Cells(1, lastCol))
lastCol = ShtTwo.Cells(1, Columns.Count).End(xlToLeft).Column
Set shtTwoHead = ShtTwo.Range("A1", ShtTwo.Cells(1, lastCol))
For Each headerTwo In shtTwoHead
For Each headerOne In shtOneHead
If headerTwo.Value = headerOne.Value Then
Else
x = MsgBox("Headers are not matching in both sheets.")
MsgBox "value is:" & headerTwo.Value
Exit Sub
End If
Next headerOne
Next headerTwo
End Sub
Sub new_code()
Dim a As Integer
Dim b As Integer
Dim x As Integer
Dim HeadNew As Integer
Dim HeadOld As Integer
Dim HeadingsNew() As String
Dim HeadingsOld() As String
a = 1
b = 1
HeadNew = 0
HeadOld = 0
Erase HeadingsNew
Erase HeadingsOld
Worksheets("ReportNew").Activate
Do Until Len(Trim(Cells(1, a))) = 0
DoEvents
ReDim Preserve HeadingsNew(1 To a)
HeadingsNew(a) = Trim(Cells(1, a))
a = a + 1
Loop
a = a - 1
HeadNew = a
Worksheets("ReportOld").Activate
Do Until Len(Trim(Cells(1, b))) = 0
DoEvents
ReDim Preserve HeadingsOld(1 To b)
HeadingsOld(b) = Trim(Cells(1, b))
b = b + 1
Loop
b = b - 1
HeadOld = b
x = 1
Do Until x > a
DoEvents
If HeadingsNew(x) <> HeadingsOld(x) Then
MsgBox " Headings are different" & Chr(10) & Chr(10) & _
" column number " & x & Chr(10) & _
" ReportNew: " & (HeadingsNew(x)) & Chr(10) & _
" ReportOld: " & (HeadingsOld(x)), vbCritical, "Data Issue"
End If
x = x + 1
Loop
If HeadOld <> HeadNew Then
MsgBox " The number of headings don't match", vbcritacal, "Data Issue"
End If
End Sub
I suggest a variant array. Here is a simple solution.
Sub Compare()
Dim header1 As Variant, header2 As Variant, i as long
header1 = sheets("ReportOld").Rows(1).Value
header2 = sheets("ReportNew").Rows(1).Value
For i = 1 To 100000
If header1(1, i) <> vbNullString Then
If header1(1, i) <> header2(1, i) Then
MsgBox "Compare Failed at column " & i
Exit For
End If
Else
MsgBox "Compare ="
Exit For
End If
Next i
End Sub

Program Error Subscript out of Range ... Tried On Error Resume

I am having problem with the subscript out of range with this line:
datasheet = wbook.Sheets("Month and Year")
I have tried to use On Error Resume but I might have done it wrong.
This code is suppose to establish month and year so that later, I am able to use it when I create a new sheet and refer to the previous one named similarly "Forecast Month Year". afterwards, it looks at 3 columns to validate that it is the row that it wants to copy and paste and then establishes it on the respective sheet.
Sub repeatingrows()
Dim wbook As Workbook
Set wbook = Application.ActiveWorkbook
'CHECKS THE MONTH TO INCREASE THE YEAR
Dim datasheet As Worksheet
datasheet = wbook.Sheets("Month and Year")
Dim m As Integer
Dim y As Integer
Dim t As Integer
For t = 2 To 13
For m = 1 To 13
If m = 13 Then
y = y + 1
m = 1
End If
Next m
m = .Cells(t, 1)
.Cells(t, 1) = .Cells(t, 2)
Next t
'MAKE NEW SHEET AND RENAME IT
Dim oldsheet As Worksheet
Dim newsheet As Worksheet
Set oldsheet = Application.ActiveSheet
oldsheet = Sheets("Forecast " & m & " " & y)
newsheet = Sheets("Forecast " & (m + 1) & " " & y)
Sheets.Add.Name = "Forecast " & (m + 1) & " " & y
'CHECK IF the 3 columns ARE SIMILAIR TO PREVIOUS PAGE
Dim rrow As Integer
For rrow = 3 To 500
If Sheets(3).Cell(rrow, 2) = Sheets(2).Cell(rrow, 2) Then
If Sheets(3).Cell(rrow, 5) = Sheets(2).Cell(rrow, 5) Then
If Sheets(3).Cell(rrow, 6) = Sheets(2).Cell(rrow, 6) Then
With newsheet
oldsheet.Range(oldsheet.Cells(rrow, 16), oldsheet.Cells(rrow, 19)).Copy
.Range(.Cells(b, a), .Cells(99, 51)).PasteSpecial xlPasteValues, xlPasteSpecialOperationAdd
End With '^COPY AND PASTES THE ROW
Else
End If
Else
End If
Else
End If
Next rrow
End Sub
try:
Set datasheet = wbook.Sheets("Month and Year")
and check the spelling of the sheetnameand check that the sheet exists in the proper workbook.and don't use .Cells() without a With
(there may be other errors)

Excel VBA Runtime Error 1004 while looping through sheets and extracting data

I'm writing an excel VBA script to loop through a set of 4 sheets, find a string at the top of a column of data, loop through all the data in that column and print the header and data in a summary tab.
I'm new to VBA and even after extensive research can't figure out why I'm getting Runtime error 1004 "Application-defined or object-defined error."
Here is the VBA code:
Private Sub CommandButton1_Click()
Dim HeaderList(1 To 4) As String, sheet As Worksheet, i As Integer, j As Integer, Summary As Worksheet
'Define headers to look for
HeaderList(1) = "Bananas"
HeaderList(2) = "Puppies"
HeaderList(3) = "Tigers"
'Loop through each sheet looking for the right header
For Each sheet In Workbooks("Tab Extraction Test.xlsm").Worksheets
i = i + 1
'Debug.Print i
'Debug.Print HeaderList(i)
Set h = Cells.Find(What:=HeaderList(i))
With Worksheets("Summary")
Worksheets("Summary").Cells(1, i).Value = h
End With
Col = h.Column
Debug.Print Col
Row = h.Row
Debug.Print Row
j = Row
'Until an empty cell in encountered copy the value to a summary tab
Do While IsEmpty(Cells(Col, j)) = False
j = j + 1
V = Range(Col, j).Value
Debug.Print V
Workbooks("Tab Extraction Test.xlsm").Worksheets("Summary").Cells(j, i).Value = V
Loop
Next sheet
End Sub
The error occurs at
Worksheets("Summary").Cells(1, i).Value = h
From other posts I thought this might be because I was trying to add something to a different cell than the one that was active in the current loop so I added a With statement but to no avail.
Thank you in advance for your help.
Following the comments above, try the code below.
Note: I think your Cells(Row, Col) is mixed-up, I haven't modified it yet in my answer below. I think Cells(Col, j) should be Cells(j, Col) , no ?
Code
Option Explicit
Private Sub CommandButton1_Click()
Dim HeaderList(1 To 4) As String, ws As Worksheet, i As Long, j As Long, Summary As Worksheet
Dim h As Range, Col As Long
'Define headers to look for
HeaderList(1) = "Bananas"
HeaderList(2) = "Puppies"
HeaderList(3) = "Tigers"
' set the "Summary" tab worksheet
Set Summary = Workbooks("Tab Extraction Test.xlsm").Worksheets("Summary")
'Loop through each sheet looking for the right header
For Each ws In Workbooks("Tab Extraction Test.xlsm").Worksheets
With ws
i = i + 1
Set h = .Cells.Find(What:=HeaderList(i))
If Not h Is Nothing Then ' successful find
Summary.Cells(1, i).Value = h.Value
j = h.Row
'Until an empty cell in encountered copy the value to "Summary" tab
' Do While Not IsEmpty(.Cells(h.Column, j))
Do While Not IsEmpty(.Cells(j, h.Column)) ' <-- should be
j = j + 1
Summary.Cells(j, i).Value = .Cells(j, h.Column).Value
Loop
Set h = Nothing ' reset range object
End If
End With
Next ws
End Sub
Try this one.
Private Sub CommandButton1_Click()
Dim HeaderList As Variant, ws As Worksheet, i As Integer, j As Integer, Summary As Worksheet
Dim lastRow As Long, lastCol As Long, colNum As Long
HeaderList = Array("Bananas", "Puppies", "Tigers", "Lions")
For Each ws In Workbooks("Tab Extraction Test.xlsm").Worksheets
lastCol = ws.Range("IV1").End(xlToLeft).Column
For k = 1 To lastCol
For i = 0 To 3
Set h = ws.Range(Chr(k + 64) & "1").Find(What:=HeaderList(i))
If Not h Is Nothing Then
lastRow = ws.Range(Chr(h.Column + 64) & "65536").End(xlUp).Row
colNum = colNum + 1
' The below line of code adds a header to summary page (row 1) showing which workbook and sheet the data came from
' If you want to use it then make sure you change the end of the follpowing line of code from "1" to "2"
' ThisWorkbook.Worksheets("Summary").Range(Chr(colNum + 64) & "1").Value = Left(ws.Parent.Name, Len(ws.Parent.Name) - 5) & ", " & ws.Name
ws.Range(Chr(h.Column + 64) & "1:" & Chr(h.Column + 64) & lastRow).Copy Destination:=ThisWorkbook.Worksheets("Summary").Range(Chr(colNum + 64) & "1")
Exit For
End If
Next i
Next k
Next ws
End Sub
Sometimes you have to remove blank sheets. Say you have 2k sheets because you combined a bunch of txt files into one workbook. But they're all in one column. So you loop through to do a text2columns. It does some of them but not all of them. It stops to give you run-time error 1004. Try removing blank sheets before looping through to do text2columns or something else.
Sub RemoveBlankSheets_ActiveWorkbook()
'PURPOSE: Delete any blanks sheets in the active workbook
'SOURCE: www.TheSpreadsheetGuru.com/the-code-vault
Dim sht As Worksheet
Application.ScreenUpdating = False
Application.DisplayAlerts = False
For Each sht In ActiveWorkbook.Worksheets
If WorksheetFunction.CountA(sht.Cells) = 0 And _
ActiveWorkbook.Sheets.Count > 1 Then sht.Delete
Next sht
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub

How to Import CSV to Excel with VBA

I Have a Red Lion Data station that records temperatures from about 25 ovens and the data is stored on a network in CSV files. I would like to import this data into an Excel file once every two minutes, but only import the changes after the initial import. After the import, the VBA must release the CSV file for the 2 minutes so that it can be updated by the data station. I have searched the web, this site and the closest thing I have found is the following code. This code looks for changes but it does not import the file. any help would be appreciated.
Dim NextTime As Date
Function LastModTime(FileSpec As String) As Date
'Returns the date-time the file specified by FileSpec (path string) was last modified
Dim fs, f, s
Set fs = CreateObject("Scripting.FileSystemObject")
Set f = fs.GetFile(FileSpec)
LastModTime = f.DateLastModified
End Function
Sub Check4Changes()
'Checks the file FilePath for changes every 60 seconds
'If file has changed, pops up a message box. Stores the
'last modified time in cell M1 of Sheet1
ChDir "Q:\Manufacturing\Equipment\DispatchLogs\logs\7-DES"
Const FilePath As String = "Q:\Manufacturing\Equipment\DispatchLogs\logs\7-DES\*.csv"
Dim LastMod As Date
On Error GoTo ReSchedule
LastMod = LastModTime(FilePath)
With Worksheets("Sheet1").Range("C1")
If IsEmpty(.Value) Then
.Value = LastMod
GoTo ReSchedule
ElseIf .Value < LastMod Then
.Value = LastMod
MsgBox FilePath & " updated.", vbInformation, "Check4Changes"
End If
End With
ReSchedule:
'Reschedule this same routine to run in one minute.
NextTime = Now + 2 / 1440
Application.StatusBar = "Next check at " & NextTime
Application.OnTime NextTime, "Check4Changes"
End Sub
Sub CancelChecking()
Application.OnTime NextTime, "Check4Changes", Schedule:=False
Application.StatusBar = False
End Sub
I have written some code which will give you the basic idea
Sub Main()
Dim Wbk_CSV As Excel.Workbook
Dim Excel_Wbk As Excel.Workbook
Dim Var_WholeCSVData As Variant
Dim Var_ExcelData As Variant
Dim Var_ToUpdate As Variant
Dim NumOfRows As Long
Dim Last_Row As Long
Set Wbk_CSV = Workbooks.Open("PathWithFileName")
Wbk_CSV.Sheets(1).Activate
Last_Row = ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row
'Taking whole data in a variant
'Change the range as per the data in csv file
Var_WholeCSVData = Wbk_CSV.Sheets(1).Range("A2:D" & Last_Row).Value 'Considering first row as header row and there are 4 columns
'After taking whole data in varinat close csv file without saving
Wbk_CSV.Close savechanges:=False
Set Wbk_CSV = Nothing
'Now open excel file in which data will be updated
Set Excel_Wbk = Workbooks.Open("PathWithFileName")
Excel_Wbk.Sheets(1).Activate
Last_Row = ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row
Var_ExcelData = Excel_Wbk.Sheets(1).Range("A2:D" & Last_Row).Value 'Considering first row as header row
NumOfRows = 0
'This function will return count of updated rows and data to update
Var_ToUpdate = Delete_Duplicates(Var_WholeCSVData, Var_ExcelData, NumOfRows)
Excel_Wbk.Sheets(1).Activate
'paste data
If NumOfRows > 0 Then
ActiveSheet.Range("A" & Last_Row + 1 & ":D" & Last_Row + NumOfRows).Value = Var_ToUpdate
End If
Excel_Wbk.Close savechanges:=True
Set Excel_Wbk = Nothing
'result
MsgBox ("Number of rows imported: " & NumOfRows)
End Sub
Function Delete_Duplicates(Var_FromCSV As Variant, Var_FromExcel As Variant, ByRef NumberOfRowToupdate As Long) As Variant
'using dictinpary objects
Dim dict_Duplicates As Object
Dim i_AddToDict, i, j As Long
Dim Str_value As String
Dim Var_Temp As Variant
Dim lng_temp As Long
Set dict_Duplicates = CreateObject("Scripting.Dictionary")
ReDim Var_Temp(1 To UBound(Var_FromCSV, 1), 1 To UBound(Var_FromCSV, 2))
'Add excel data to dict. by concatenating
'All unique values will be added
For i_AddToDict = 1 To UBound(Var_FromCSV)
Str_value = CStr(Var_FromExcel(i_AddToDict, 1) & Var_FromExcel(i_AddToDict, 2) & Var_FromExcel(i_AddToDict, 3) & Var_FromExcel(i_AddToDict, 4))
If dict_Duplicates.exists(Str_value) Then
'do nothing
Else
dict_Duplicates.Add Str_value, 1
End If
Next i_AddToDict
'looking for values which are not available in excel file
For i = 1 To UBound(Var_FromCSV)
Str_value = CStr(Var_FromCSV(i_AddToDict, 1) & Var_FromCSV(i_AddToDict, 2) & Var_FromCSV(i_AddToDict, 3) & Var_FromCSV(i_AddToDict, 4))
If dict_Duplicates.exists(Str_value) Then
'do nothing
Else
'storing values in a variant
For j = 1 To 4
Var_Temp(lng_temp, j) = Var_FromCSV(i, j)
Next j
lng_temp = lng_temp + 1
dict_Duplicates.Add Str_value, 1
End If
Next i
NumberOfRowToupdate = lng_temp - 1
Delete_Duplicates = Var_Temp
End Function