segregate the data based on their own value - vba

I have data where list is dynamic. I would like to segregate the data base on their own value.I am unable to predict the exact value coming every time. Example : - This time I got company code as 1959809 and 1960574. I would like to filter data based on company code and would like to paste it in new workbook. This number will get change every time. Next time the company code may be 1960574 and 1963665.
I am thinking that we need to group the company code value so that we can have it in variable. However, I am unable to get the logic.
I am not getting any logic to do so. Hence, I don't have anything to show.
We should get two or more workbooks based on company code along with respective data.

Assuming your data has first column as 'Company Code' and starts from the first row of sheet, Following code will help you achieving your goal:
Sub ExportFilteredData()
Dim Codes As String, CodesArray, Code
Dim Wb As Workbook, CurSht As Worksheet
'Get the company codes from user as comma separated values
Codes = InputBox("Enter Company codes separated by comma")
CodesArray = Split(Codes, ",") 'Split company codes to array
'Save the data sheet reference and remove any applied filter
Set CurSht = ActiveSheet
CurSht.AutoFilterMode = False
'Filter data for each company code and save as new workbook
For Each Code In CodesArray
'Change the 'Field' value to the actual 'Company Code' column number
CurSht.Range("A1").AutoFilter Field:=1, Criteria1:=Trim(Code)
Set Wb = Workbooks.Add
CurSht.AutoFilter.Range.SpecialCells(xlCellTypeVisible).Copy Wb.Sheets(1).Range("A1")
'Change the path and filename as per your requirement
Wb.SaveAs ThisWorkbook.Path & "\" & Trim(Code) & ".xlsx"
Wb.Close False
CurSht.AutoFilterMode = False
Next
End Sub

Related

VBA - Moving large number of records - some records missing

I have a data set of around 1500 sales records. I have written a macro, which would create product category specific work books, which would have an individual work sheet for each product in the product category.
The macro is working as expected, but I have found out that it is consistently ignoring some products. I put debug statements to see if I am getting zero records when I filter based on the product code (since I use this selection to paste the records to a separate work sheet). The selection seems to be working fine, as I get the number of rows selected.
A pattern I saw was that the product codes which were having zero records were generally the first ones or the last ones to get processed before or after a file operation (either I open a category specific work book, or I am closing a work book). But even here, the table header was copied to the individual work sheet. Only the data rows were getting ignored.
Is there a chance where the macro is processing the records too fast, while there is some time lag in doing File I/O operations (which makes a few records to get ignored)?
I am attaching the code, which I have used for looping
'loop through each row and get the product id and the category (Ann & Bnn).
' Dim catWorkBook As Workbook
oProductCat = "0" 'the initial value set as 0, which would NEVER be a category
With wkScrap 'this is a rough sheet which has the product items and categories
For i = 2 To lProdRow
cProductCode = .Cells(i, 1).Value
cProductCat = .Cells(i, 2).Value
'FILE OPEN: will need to open a category specific .xls file
If (StrComp(cProductCat, oProductCat) <> 0) Then
'save the existing workbook
FileIO.CloseExcelFile oProductCat, catWorkBook
Set catWorkBook = Nothing 'clear all traces of the old worksheet
Set catWorkBook = CreateBlankWorkBook()
oProductCat = cProductCat
End If
'COPY DATA: Filtering on product code, and then moving it into a new
'worksheet
CopyCategoryToWorksheet cProductCode, catWorkBook
If i = lProdRow Then
'we are at the end of the loop. Proceed to close the current
'workbook
FileIO.CloseExcelFile oProductCat, catWorkBook
End If
Next
End With
Here is the function which does the actual copying
Private Sub CopyCategoryToWorksheet(prodCode As String, catWkBook As Workbook)
'check for a meaningful prod code
If (Trim(prodCode & vbNullString) = vbNullString) Then
Exit Sub
End If
Dim wkRData As Worksheet
Dim rRData As Range
Dim rDataMaxRows As Integer
Set wkRData = SalesReport.Sheet1
'We know that we have to create a work sheet for this product code.
'Let us do that first.
Dim prodCatSheet As Worksheet
catWkBook.Activate
Set prodCatSheet = catWkBook.Sheets.Add(After:=catWkBook.Sheets(catWkBook.Sheets.Count))
prodCatSheet.Name = prodCode
wkRData.Activate 'for this sub routine, all processing is happening on the raw data sheet
rDataMaxRows = Cells(rows.Count, 1).End(xlUp).Row
Set rRData = Range("A1:H" & rDataMaxRows)
rRData.AutoFilter 3, Criteria1:="=" & Trim(prodCode)
rRData.Select
Selection.SpecialCells(xlCellTypeVisible).Select
Selection.Copy
'activate the newly created sheet, and paste all the selected rows there
prodCatSheet.Activate
prodCatSheet.PasteSpecial
Set wkRData = Nothing 'just clear some memory
End Sub

How to delete unselected columns from range

I am new to VBA and am trying to delete unwanted columns loaded from a .csv file. I am importing a large amount of data but then I ask the user what columns they want to keep going by "ID num.". There are a lot of columns with different ID no. and I want to ask the user what they want to keep and delete the rest.
The problem is I need to delete all the other columns the user didn't want but I still need to keep the first 6 columns and the last two columns as that is different information.
Here is what I have so far:
Sub Select()
'the below will take the users inputs
UserValue = InputBox("Give the ID no. to keep seperating with a comma e.g"12,13,14")
'the below will pass the user inputs to the example to split the values
Call Example(UserValue)
End Sub
Sub Example(UserValue)
TestColArray() = Split(UserValue, ",")
For Each TestCol In TestColArray()
' keep all the columns user wants the delete the rest except the first 6 columns and last 2
Next TestCol
End Sub
That is what I have so far, it is not much but the user could put in a lot of columns with different ID number in the input box the way the Excel sheet is laid out all the ID no.s are in row 2 and the first 6 and last 2 columns are blank of row 2 since the ID no. does not apply. I hope that helps.
try this (commented) code:
Option Explicit '<--| use this statament: at the cost of having to declare all used variable, your code will be much easier to debug and maintainable
Sub MySelect()
Dim UserValue As String
'the below will take the users inputs
UserValue = Application.InputBox("Give the ID no. to keep seperating with a comma e.g: ""12,13,14""", Type:=2) '<--| use Type:=2 to force a string input
'the below will pass the user inputs to the example to split the values
Example UserValue '<--| syntax 'Call Example(UserValue)' is old
End Sub
Sub Example(UserValue As String)
Dim TestCol As Variant
Dim cellsToKeep As String
Dim firstIDRng As Range, lastIDRng As Range, IDRng As Range, f As Range
Set firstIDRng = Range("A2").End(xlToRight) '<-- first ID cell
Set lastIDRng = Cells(2, Columns.Count).End(xlToLeft) '<-- last ID cell
Set IDRng = Range(firstIDRng, lastIDRng) '<--| IDs range
cellsToKeep = firstIDRng.Offset(, -6).Resize(, 6).Address(False, False) & "," '<--| initialize cells-to-keep addresses list with the first six blank cells at the left of first ID
For Each TestCol In Split(Replace(UserValue, " ", ""), ",") '<--| loop through passed ID's
Set f = IDRng.Find(what:=TestCol, LookIn:=xlValues, lookat:=xlWhole, MatchCase:=False) '<--| search for the current passed IDs range
If Not f Is Nothing Then cellsToKeep = cellsToKeep & f.Address(False, False) & "," '<--| if the current ID is found then update cells-to-keep addresses list
Next TestCol
cellsToKeep = cellsToKeep & lastIDRng.Offset(, 1).Resize(, 2).Address(False, False) '<--| finish cells-to-keep addresses list with the firts two blank cells at the right of last ID
Range(cellsToKeep).EntireColumn.Hidden = True '<-- hide columns-to-keep
ActiveSheet.UsedRange.EntireColumn.SpecialCells(xlCellTypeVisible).EntireColumn.Delete '<--| delete only visible rows
ActiveSheet.UsedRange.EntireColumn.Hidden = False '<-- unhide columns
End Sub
it's assumed to be working with currently active worksheet
A simple google search produces this. On the first page of results too. Perhaps this will suit your needs.
If the data set that needs to be deleted is really large (larger than the ranges you want to keep too.) Then perhaps only select the columns you want to have whilst you import the csv? This stackoverflow question shows how to import specific columns.
EDIT:
So from what I believe the OP is stating as the problem, there is a large csv file that is being imported into excel. After importing there is alot of redundant columns that should be deleted. My first thought would be to only import the needed data (columns) in the first place. This is possible via VBA by using the .TextToColumns method with the FieldInfo argument. As stated above, the stackoverflow question linked above provides a means of doing so.
If the selective importing is not an option, and you are still keen on making an inverse of the user selection. One option would be to create 2 ranges (one being the user selected Ranges and the second being the entire sheet), you could perform an intersect check between the two ranges and delete the range if there is no intersection present (ie. delete any cell that is not part of the users selection). This method is provided by the first link I supplied and is quite straight forward.

How to select column and display its current format using VBA Macro?

Please find my requirement below for which I am unable to find any solution:
1. Iterate over workSheet from workbook
2. Find all the columns containing date values using current format/type of column (Here is a trick. Worksheet is not static, it can contain any number of columns containing date values. Columns containing date values may have any name. And such worksheets can be more than one in number)
3. Apply macro on date columns for date formatting (below macro) if "Flag" value is "y"
<code>
Sub FormatDate()
If wksSecDist.Range("Flag").value = "y" Then
LastRowColA = Range("X" & Rows.Count).End(xlUp).Row
' Here I am finding total number of rows in column X
wksSecDist.Range("X2", "X" & LastRowColA).NumberFormat = "dd/mmm/yyyy"
' Here applying specified date format to Range("X2", "X10") [if last row index for column X is 10]
End If
End Sub
</code>
I am just a beginner to VBA.
Thanks in advance.
I suspect you didn't find a solution on the internet because you looked simply for a solution and not the parts needed to build your own solution.
You mention you are a VBA beginner, please take the below answer to be of educational use and begin you in getting you where you need your tool to be. Note, if it doesn't answer your question because of information that was not included, it has still answered your question and the missing information should form part of a new question. That said, lets get this function up and running.
From what you have written I have interpreted the requirement to be: -
Look over all worksheets in a workbook ('worksheets can be more than one in number')
Check every column to see if it holds a date value
If it does, set the whole column to a specific format
What is needed to accomplish this is iteration(loops), one to loop through all worksheet, and another to loop through all columns: -
The is pseudo code of the target: -
.For each Worksheet in the Workbook
..For each Column in the Worksheet
...If the Column contains dates then format it as required
..Process next column
.Process next Worksheet
We achieve this using a variable to reference a Worksheet and using a loop (For Each) to change the reference. The same goes for the columns.
Public Sub Sample()
Dim WkSht As Excel.Worksheet
Dim LngCols As Long
Dim LngCol As Long
'This loop will process the code inside it against every worksheet in this Workbook
For Each WkSht In ThisWorkbook.Worksheets
'Go to the top right of the worksheet and then come in, this finds the last used column
LngCols = WkSht.Range(WkSht.Cells(1, WkSht.Columns.Count).Address).End(xlToLeft).Column
'This loop will process the code inside it against every column in the worksheet
For LngCol = 1 To LngCols
'If the first cell contains a date then we should format the column
If IsDate(WkSht.Cells(2, LngCol)) Then
'Set right to the bottom of the sheet
WkSht.Range(WkSht.Cells(2, LngCol), WkSht.Cells(WkSht.Rows.Count, LngCol)).NumberFormat = "dd/mmm/yyyy"
End If
Next
Next
End Sub
Hopefully that has all made sense, this does work on the premise that the header row is always row 1 and there are no gaps in the columns, but these are separate issues you can approach when you're ready to.

How can I copy & paste entire rows with distinct values to a new sheet on varying cell ranges?

I know there's many StackOverlow Q&A's on copying & pasting from a cell value in VBA. However, I can't seem to make it work for my own project. I want to copy the entire row(s) if it matches the Distinct Store# (non incremental) in Column H into a new sheet (in this code below, "Sheet1") which already has a template layout where I copy/paste the values. The template looks the same on every sheet before any data is filled in, except the first 2 tabs which have the data ("Appointments" and "Invoices").
I came up with the VBA below, but here's the catch- the cell# that it pastes the row(s) (in the code below, "A10") changes based on the Store #. This is because I am copying rows from the 1st sheet ("Appointments") in the workbook from the distinct Store#, then deleting the empty rows above the area where the 2nd sheet ("Invoices") data goes. Some stores may return 10 rows or none at all. The Case, which is the Store #, is currently manually put in one by one. Should it be an array instead?
Anyway...I was hoping to automate the copying/pasting and loop for each store to their sheet. Maybe I'm going about this wrong, but would anyone be kind enough to suggest how to solve my error code "Method or data member not found." as well as provide any suggestions on making my code better for a loop for filtered cell copying to different spots for each sheet.
Simple explanation of my step by step process:
1.Filter Store # from "Appointments" sheet.
2. Copy all rows for that store and paste into a new sheet with template named "Sheet1" in B3.
3. Filter Store # from "Invoices" sheet.
4. Copy all rows for that store and paste into the previously made sheet named "Sheet" under the above rows. (Some stores do not have invoices, so this section is blank/NULL). Paste destination cell for "Invoices" will be different for each store# depending on how many rows they get from the "Appointments" sheet (could be A10 or A25).
5. LOOP- Next store #, next sheet (sheet2).
Sub CopyToNewSheetInv()
Dim i As Range
Dim book As Workbooks
Dim sheet1 As Worksheets
Dim sheet2 As Worksheets
Set book = Workbooks("SampleWorkbookName")
Set sheet1 = Worksheets("AllInvoices")
Set sheet2 = Worksheets("Sheet1")
For Each i In sheet1.Range("H:H")
Select Case i.Value
Case 1243
sheet2.Range("A10").End(xlUp).Offset(1, 0).EntireRow.Value = i.EntireRow.Value
Case Else
End Select
Next i
End Sub
Try this:
Sub CopyToNewSheetInv()
Dim i As Range
Dim book As Workbook
Dim sheet1 As Worksheet
Dim sheet2 As Worksheet
Set book = Workbooks("SampleWorkbookName.xlsx")
Set sheet1 = book.Worksheets("AllInvoices")
Set sheet2 = book.Worksheets("Sheet1")
'iterate only thorugh those cells in H that have data, not all 1.04 million
For Each i In sheet1.Range("H1", sheet1.Range("H" & sheet1.Rows.Count).End(xlUp))
Select Case i.Value
Case 1243,"1243"
sheet2.Rows(sheet2.Range("A10000").End(xlUp).Offset(1, 0).Row).Value = sheet1.Rows(i.Row).Value
Case Else
End Select
Next i
End Sub

Merge tables from many separate workbooks

I want to merge specific contents of 2713 workbooks into a single worksheet. Lets say the individual files contain sales revenues for different sales outlets.
Each of the workbooks uses only 1 worksheet. Each of those worksheets contains one or more tables in identical format. Worksheets contain no fuctions whatsoever. This sample shows cells A1:E7
A1 contains the number of the specific outlet
A2 contains the reference date, e.g. 31.12.2014
A3:E3 contain the column headers: No.; Item; Revenue current period; Revenue previous period
A4:E10 contain the info I want transported to the new single file
A11:E11 contains the total amounts
Row 12 is blank
Another table with info for 31.12.2013 starts from row 13.
...
Most of the worksheets have more than just one table. All of them start like the one above. The tables have identical layout.
Unfortunately, the number of products varies a lot (1-250). For the example, I just assumed its 7 products. I don't need the row for headline or total.
How can I get those rows into a new single worksheet?
The outlet number in cell A1 on every sheet should be added in the cell to the right of the cells containing comment.
I want to avoid having to open the 2713 files one after the other in order to copy and paste the info in 2713 drag and drop moves into a merged worksheet.
I hope you can help or its gonna be a long weekend.
Best wishes,
Peter
I'm assuming here that when you say tables you mean defined tables of data.
The code below assumes that all tables are the same size (target and source tables).
There's no error checking and minimal testing - so check on some test workbooks first.
Sub GetTables()
Dim colWrkBks As Collection 'Contains path to all workbooks.
Dim vPath As Variant 'Current workbook path.
Dim wrkBk As Workbook 'Current workbook.
Dim wrksht As Worksheet 'Worksheet within wrkBk.
Dim oListObject As Object 'Tables within wrksht.
Dim oTargetTable As Object 'The table to hold all the data.
Dim sTmp As String
Dim sDirectory As String
'Make sure you have a table defined to place all the data in.
'Update worksheet and table name as required.
Set oTargetTable = ThisWorkbook.Worksheets("Sheet1").ListObjects("Table1")
'Get full path of all workbooks in source folder.
'*Update directory and file extension as required
Set colWrkBks = New Collection
sDirectory = "C:\Users\Darren\Documents\Work\New folder\"
sTemp = Dir$(sDirectory & "*.xls*")
Do While Len(sTemp) > 0
colWrkBks.Add sDirectory & sTemp
sTemp = Dir$
Loop
'Open each workbook and copy the data from source table to target table.
For Each vPath In colWrkBks
Set wrkBk = Workbooks.Open(vPath, False)
'1 references the first worksheet - you can use "Sheet1" for a specific sheet name.
Set wrksht = wrkBk.Worksheets(1)
'Cycle through each table in the worksheet.
For Each oListObject In wrksht.ListObjects
oTargetTable.ListRows.Add
oListObject.DataBodyRange.Rows("1:" & oListObject.DataBodyRange.Rows.Count).Copy _
oTargetTable.DataBodyRange.Rows(oTargetTable.DataBodyRange.Rows.Count)
Next oListObject
wrkBk.Close False
Next vPath
End Sub