I really need help. In my data base on excel and the first column is made up by the codes of my clients. Every client can have different number of rows and so on. What I’m trying to do is create a VBA Macro that can go through my list of client codes and for each code copy it’s rows on the DB to a new worksheet. And to do this for all the client codes I have like on loop, after copying the first one to go automatically to the next code.
Please help :(
I hope this provides a framework for you to do what you want.
Key concepts
Use autofilter to identify all records for each client
store client id in a dictionary to keep track of what has been processed
use SpecialCells to reference filtered rows
My simple input data
My output
Let me know if its helpful
Option Explicit
Sub master_db_to_individual()
Dim ws_in As Worksheet
Set ws_in = ThisWorkbook.Worksheets("master_db")
' Not knowing the actual shape of the data, this is just a simple way to set the required range locations
Dim r_keys As Range
Set r_keys = Range(ws_in.Range("a2"), ws_in.Range("a2").End(xlDown))
Dim r_all_data_with_headers As Range
Set r_all_data_with_headers = ws_in.Range("a2").CurrentRegion
'create a dictionary to store client codes found
Dim client_codes As Object
Set client_codes = CreateObject("Scripting.Dictionary")
' create a new workbook for individual data
Dim wb_individual As Workbook
Set wb_individual = Application.Workbooks.Add
Dim initial_ws_count As Long
initial_ws_count = wb_individual.Worksheets.Count
' loop all entires in the client code column of the master data
Dim client_code As Range
For Each client_code In r_keys
'test if have already processed the current row
' I am assuming here that the order of the client records can not be guaranteed
If Not client_codes.Exists(client_code.Value) Then
' make a record that this client has been processed so if we find another row for this client we know to skip
client_codes.Add client_code.Value, client_code.Value
'ensure a sheet for this client exists by inserting and supressing error if already exists
Dim ws_this_client As Worksheet
Set ws_this_client = wb_individual.Worksheets.Add(after:=wb_individual.Worksheets(wb_individual.Worksheets.Count))
ws_this_client.Name = client_code.Value
'filter all rows that have this client key so they can be copied
r_all_data_with_headers.AutoFilter field:=r_keys.Column, Criteria1:=client_code.Value, Operator:=xlFilterValues
'copy filtered data with headers to new sheet
r_all_data_with_headers.SpecialCells(xlCellTypeVisible).Copy ws_this_client.Range("a1")
End If
Next client_code
' remove autofilter
r_all_data_with_headers.AutoFilter
' remove unsed sheets in new workbook
Dim i As Integer
Application.DisplayAlerts = False
For i = initial_ws_count To 1 Step -1
wb_individual.Worksheets(i).Delete
Next i
Application.DisplayAlerts = True
ws_in.Activate
ws_in.Range("a1").Select
Set client_codes = Nothing
End Sub
Related
I am able to read another workbook and copy the contents, but when I try to paste into the existing Table - Excel hangs and freezes. If I copy the data into another sheet with no existing Table, then it works fine.
I am using this:
Dim sFound as String
Dim lRow as Long
Dim data_sheet As Worksheet
Dim wb as Workbook
Dim wb_data as Workbook
Set wb = ThisWorkbook
sFound = Dir(ActiveWorkbook.Path & "\data*.csv)
If sFound <> "" Then
Workbooks.Open Filename:=ActiveWorkbook.Path & "\" & sFound
End If
Set wb_data = ActiveWorkbook
Set data_sheet = Sheets("raw data")
lRow=data_sheet.Cells(data_sheet.Rows.Count,2).End(xlUp).Row
data_sheet.Range("A10:V" & lRow).Copy
wb.Sheets("Data").Range("Data[Code]").PasteSpecial
Application.CutCopyMode = False
wb_data.Close
Any assistance in why the paste is causing the hang up in the table would be greatly appreciated.
2018-09-21 Update
I managed to fix the freezing and hanging through a combination of Marucciboy2's post and my own research. I stored the entire raw data set I was copying into a variant variable. Then, I resized the new table I was copying to to be the same length as the raw data. Then I just set that entire data range value the same as the variant variable. I will update this with the code.
I am still having one issue with is figuring out how to copy one particular column or certain range of columns of one table into another table. I can resize the new table just fine. I just don't know how to set one column into a variant variable or if I need to do something else. Then, I don't know how to set the new table column to that variant variable. Again, will have to post code tomorrow.
I am writing a macro to add a column of data from an MS Excel sheet into an already existing MS Project document. When I run my macro the correct project is opened, but I get an error message saying that the project I opened has been deleted, even though it has not been deleted.
Here is my current macro:
Sub newProjectColumn()
Dim appProj As MSProject.Application
Dim aProg As MSProject.Project
Dim wb As Workbook
Dim ws As Worksheet
Dim rng As Range
Set wb = ActiveWorkbook
'~~> Open MS Project
Set ws = wb.Sheets("Sheet1")
Set appProj = CreateObject("Msproject.Application")
appProj.FileOpen "Project_1.mpp"
Set aProg = appProj.ActiveProject
appProj.Visible = True
'~~> Next, create new Column in project
TableEditEx Name:="Project_1.mpp", TaskTable:=True, _
NewFieldName:="Actual Duration", Title:="Actual Duration", Width:=12, _
ShowInMenu:=True, _
ColumnPosition:=29
'~~> Next, copy T:T from Excel.Then, paste to 29th column (i,29) in Project.
Set Rng = ws.Range("T:T")
ActiveSheet.Paste Destination:=Rng
SelectTaskColumn Column:="Actual Duration"
End Sub
Any help on what I have done wrong or if there is a better approach would be very much appreciated!
Here's the code you need to update the Actual Duration column. Change the table name as necessary. Update the range reference as necessary; do not include a header cell.
' add Actual Duration as the first column & apply the table changes
appProj.TableEditEx Name:="Entry", TaskTable:=True, _
NewFieldName:="Actual Duration", Title:="Actual Duration", Width:=12, ColumnPosition:=0
appProj.TableApply "Entry"
' copy updated values from Excel (no headers) and paste in new column in Project
Range("T2:T100").Copy
appProj.SelectColumn 2
appProj.EditPaste
' delete the column
appProj.ColumnDelete
Note that when adding a column using the TableEditEx method, the indexes start at 0 whereas when selecting a column using the SelectColumn method, the indexes start at 2.
TableEditEx method
SelectColumn method
new to stackoverflow and need a little advice on modifying this code to include the deletion of records further than the exported range when exporting from Access to a specific excel worksheet:
Query to extract all Access data from = Stocklist
Spreadsheet to paste data to (inc headings) = G:\Project\test1.xlsx
Worksheet to extract to is also named "Stocklist" and the range is A1 onwards - there are four columns of data that need overwritten by the updated list which is derived from the query.
The following selects the correct file and overwrites the range A1 onwards:
Public Sub Export()
Dim rstName As Recordset
Set rstName = CurrentDb.OpenRecordset("Stocklist")
Dim objApp As Object, objMyWorkbook As Object, objMySheet As Object, objMyRange As Object
Set objApp = CreateObject("Excel.Application")
Set objMyWorkbook = objApp.Workbooks.Open("G:\Project\test1.xlsx")
Set objMySheet = objMyWorkbook.Worksheets("Stocklist")
Set objMyRange = objMySheet.Cells(objApp.ActiveSheet.UsedRange.Rows.Count + 1, 1)
With objMyRange
rstName.MoveFirst
.Clear
.CopyFromRecordset rstName
End With
This is great if the data is the same size or larger, but if its smaller it leaves the items outside the pasted/exported range in the list (eg range of 400 records will leave all records after 400 present after overwrite. Is there any way to clear the sheet before the data is added?
Also how transferable is excel macro VBA code as I have some validation rules and error handling in other spreadsheets that I would like to add (eg. check file is not open, return msgbox etc)
Any help much appreciated
Will this work for you?
objMySheet.UsedRange.Clear
With objMyRange
rstName.MoveFirst
.Clear
.CopyFromRecordset rstName
End With
Here is what I am trying to do. I am trying to create a workbook based on a template named by the title and to create a workbook for each row. And for the macro to loop until all rows have been depleted.
The deliverables that I want at the end are 3 excel documents named (Alpha.xlsx, Beta.xlsx, Gamma.xlsx) with the corresponding values from access plugged into their corresponding cells in their corresponding workbook. The subsequent math is there because I need to be able to manipulate the values once they are in excel.
Here is some of the research that I've found that I haven't quite been able to make much sense of due to my lack of experience coding in vba.
Links
(I can't post more than 2 so I'll keep the number of articles terse):
Research: databasejournal.com/features/msaccess/article.php/3563671/Export-Data-To-Excel.htm
Example Database/Spreadsheet:
http://www.sendspace.com/file/iy62c0
Image Album (has a picture of the database and the template in case you don't want to download):
http://imgur.com/pytPK,PY8FP#0
Any help will be much appreciated! I've been reading up and trying to figure out how to get this to work #.#
This isn't complete, but should help you get started...
Option Compare Database
Option Explicit
'Enter Location of your Template Here
Const ExcelTemplate = "C:\MyTemplate.xltx"
'Enter the Folder Directory to save results to
Const SaveResutsFldr = "C:\Results\"
Sub CreateWorkbook()
Dim SaveAsStr As String
Dim ExcelApp, WB As Object
'Create Reference to Run Excel
Set ExcelApp = CreateObject("Excel.Application")
'Create Reference to your Table
Dim T As Recordset
Set T = CurrentDb.OpenRecordset("tblData")
'Loop through all Record on Table
While Not T.BOF And T.EOF
'Open Your Excel Template
Set WB = ExcelApp.Workbooks.Open(ExcelTemplate)
'Enter your data from your table here to the required cells
WB.Worksheets("NameOfYourWorkSheet").Range("A1") = T("numValue1")
'Repeat this line for each piece of data you need entered
'Changing the Sheet name, cell range, a field name as per your requirements
'WB.Wor...
'WB.Wor...
'Save and Close the Workbook
SaveAsStr = SaveResutsFldr & T("Title") & ".xlsx"
WB.SaveAs SaveAsStr
WB.Close
Set WB = Nothing
'Move to the Next Record
T.MoveNext
Wend
'Close down the Excel Application
ExcelApp.Quit
Set ExcelApp = Nothing
End Sub
I created a macro in Excel for creating bar graphs automatically.
Whenever I run it, it gives "smr run time error" and I am not able to figure out what is wrong with my code.
Sub CreateGraph()
'
' CreateGraph Macro
''Initialize variables
Dim lastRow As Integer
Dim xlsPath As String
Dim xlsFile As String
xlsPath = "H:\"
xlsFile = "text.xls"
Workbooks.Open Filename:=xlsPath & xlsFile
ActiveWindow.SmallScroll Down:=-81
Range("A1:B" & lastRow).Select
ActiveSheet.Shapes.AddChart.Select
ActiveChart.SetSourceData Source:=Range("'TEST'!$A$1:$B" & lastRow)
ActiveChart.ChartType = xlBarClustered
ActiveChart.Axes(xlCategory).Select
ActiveSheet.ChartObjects("Chart 2").Activate
ActiveChart.Axes(xlCategory).ReversePlotOrder = True
Range("Q111").Select
ActiveWorkbook.Save
ActiveWorkbook.Close
End Sub
Can anyone help me in solving this puzzle please.
Also for running any macro automatically from SAS, I always have to change the Excel options for "enable all macros" which I suppose is not good. I have seen people creating and running macros without doing this. Can you please tell me how can I run the macros with enabling all macros option in Excel.
The code within this version of the answer is essentially unchanged from the previous version. However, the text has been rewritten to (1) describe my experience of this type of project, (2) answer the true question and (3) better explain the solution.
My experience of this type of project
I have been involved in five such projects. In each case, the client believed they required the automatic creation of charts but detailed discussion revealed that that this was not the requirement. The clients all published a substantial number of charts per month but most of the charts were the same as last month but with new data. They needed to automate the provision of new data for the charts. Every month some charts were revised but this was humans agreeing better ways of presenting the data. They wanted the 90% of charts that were unchanged to go through without any effort and implementation of the revisions to be as easy as possible.
In this case, the questioner publishes 100 charts per month in the form of an Excel workbook. The data for these charts comes from an Access database. The solution allows for the charts to be changed easily but this is to ease the programming and not to provide more than has been requested.
Release Template.xls
The solution requires a hand-crafted workbook named Release Template.xls. This workbook will contain all the charts and the Month 1 data. The solution creates a copy of this workbook named Release YYMM.xls in which the Month 1 data has been overwritten by the MM/YY data.
Release Template.xls contains a worksheet, Params, which will be deleted from the release version. This worksheet has a title row and one data row per chart. There are five columns: Sheet Name, Range, Number of Rows, Number of Columns and SQL command.
Sheet Name and Range define the location of the source data for the chart.
Number of Rows and Number of Columns define the size of the range. These values should be generated from the range (or vice versa) but this generation is not difficult and its inclusion would complicate the answer for little advantage.
SQL command is the command to be used to extract the data for the chart from the database. The code below assumes the SQL command generates a Recordset containing data ready to drop into the worksheet.
These parameters could be in the Access database but I believe they fit more logically in the workbook. These parameters control getting data out of the Access database and into the Excel workbook. If a chart is changed such that it requires new data, these parameters must be changed to match but no change is required to the code.
Envelope
When this code was tested, it was within an Access Module. It could probably be transferred to a form but that has not been tested. There MUST be a reference to the "Microsoft Excel 11.0 Object Library".
This envelope should be suitable for any similar problem.
Option Compare Database
Option Explicit
Sub Control()
' This list includes the variables for the envelope and the generation code
Dim DestFileName As String
Dim Path As String
Dim xlApp As Excel.Application
Dim xlWB As Excel.Workbook
' I have my Excel file and my Access database in the same folder.
' This statement gets me the name of the folder holding my database.
' You may need to define a different path.
Path = Application.CurrentProject.Path
' Create path and file name of "Resource YYMM.xls"
DestFileName = Path & "\" & "Resource " & Format(Date, "yymm") & ".xls"
' Create copy of "Resource Template.xls".
FileCopy Path & "\Resource Template.xls", DestFileName
Set xlApp = New Excel.Application
With xlApp
.Visible = True ' This slows the macro but helps with debugging
' .Visible = False
Set xlWB = .Workbooks.Open(DestFileName)
With xlWB
' Code to amend "Resource YYMM.xls" goes here
.Save ' Save the amended workbook
.Close ' Close the amended workbook
End With
Set xlWB = Nothing ' Clear reference to workbook
.Quit ' Quit Excel
End With Set xlApp = Nothing ' Clear reference to Excel
End Sub
Code to generate copy data to workbook
This code assumes it is possible to create SQL statments that will generate Recordsets of data ready to drop into the workbook.
This code has been partially tested. The tests parameters defined ranges in the workbook which matches the size of the parameters. The data loaded into Params() was written to these ranges.
Dim DestSheetName As String
Dim NumCols As Integer
Dim NumRows As Integer
Dim OutData() as Variant
Dim Params() as Variant
Dim RngDest As String
Dim RowParamCrnt As Integer
Dim RowParamMax As Integer
Dim SQLCommand As String
With .Sheets("Params")
' Find last used row in worksheet
RowParamMax = .Cells(Rows.Count,"A").End(xlUp).Row
' Read entire worksheet into array Params
Params = .Range(.Cells(1, 1), .Cells(RowParamMax, 5)).Value
xlApp.DisplayAlerts = False ' Surpress delete confirmation
.Delete ' Delete parameters sheet
xlApp.DisplayAlerts = True
End With
' Params is an array with two dimensions. Dimension 1 is the row.
' Dimension 2 is the column. Loading Params from the range is
' equivalent to:
' ReDim Params( 1 to RowParamMax, 1 to 5)
' Copy data from worksheet to array
For RowParamCrnt = 2 To RowParamMax
DestSheetName = Params(RowParamCrnt, 1)
DestRng = Params(RowParamCrnt, 2)
NumRows = Params(RowParamCrnt, 3)
NumCols = Params(RowParamCrnt, 4)
SQLCommand = Params(RowParamCrnt, 5)
' Use the SQL command to create a Recordset containing the data
' for the chart.
' Check the Recordset's dimensions against NumRows and NumCols
ReDim OutData(1 to NumRows, 1 to NumCols)
' Note (repeat Note): the first dimension is for rows and the
' second dimension is for columns. This is required for arrays
' to be read from or to a worksheet.
' Move the data out of the Recordset into array OutData.
.Sheets(DestSheetName).Range(DestRng).Value = OutData
Next