Copy from Excel into Access using VBA -dynamic columns - ms-access

I have an access database where users are supposed to copy from Excel and import into an Access table. The users can select from several "imports", and they can create new imports themselves. Once they have selected an import - a query is created on the fly with the required columns to be imported into the table. All imports will populate the same table, but not all columns are relevant for each import. So if Import1 is selected, then the query will display eg. column2, column3 and column4. If import2 is selected, then it could be column2 and column5 etc. Afterwards the import query is then deleted in the VBA code.
I am not sure this is the best solution to the problem, but in principle it works (however sometimes there may be problems deleting the queries if users exit the database before completing etc- so some manual removal of old queries may be required).
The problem is however that I need some columns to be completed with a predefined value set in the VBA code in addition to the data copied into the table by the user. An example of this could be that I need an ImportID column storing the ID of the import the user has selected for each row copied by the user. This needs to be done simultaneously as the user pastes data from Excel into the query. Otherwise I will not be able to identify the data in the table from other imports as required.
My only solution to this is to dynamically create a form (for each import that is requested), include the ImportID column in the form, set a predefined value for the Import column through VBA, lock the import column and then hide it in the form. That way, when the user pastes the data from Excel - the ImportID column is also populated with the correct value - without the user having to relate to that.
The issue is that I am worried this is a "messy" solution, creating multiple queries and forms in the database through VBA that need to be deleted - and I am sure a lot of them will be left as users will exit during the process before completing etc.
If anyone has a better approach to this, it will be much appreciated. I do need the imports to be done through copy/paste however (not reading files, although that could be an addition - it can not replace the current solution).
I’ll try to explain how the process works in more detail: First of all we have defined a «chart of accounts». Where let’s say account 4000-4100 is data from a CRM system. Account 5000-5100 is data from a payroll system. The user may then set up one import called «CRM import» requiring column 2, column3 and and column5 to be completed with accounts 4000-4100, and one import called «Payroll import» requiring column2, column3 and column7 to be completed with accounts 5000-5100.
When launching the «CRM» import – the VBA code simply opens a query created by VBA (DoCmd.OpenQuery) displaying column 2,3 and 5. In the Excel sheet – the user has the data on the same format. So the user then simply copies from the Excel sheet and pastes into the open Access query. Similarly when the user launches the «Payroll import», column2,3 and 7 are displayed in the VBA generated query. The user has another Excel sheet on this format to copy from as well. These are «power users» copying and pasting into the database – not just any users. All the data from the different sources are copied into the same access table in order to be processed later (so the queries simply display the relevant columns of the same table). Copy/paste from Excel is the preferred method of getting these data into Access for this solution.
Update 18th. March:
The issue I've still got is that I can not have one predefined form for each import. There can be multiple imports, imports may be deleted, added and modified by the user through the interface. So my idea is that when the user selects an import from a list, the form is opened (one form for all imports). And based on the import selected, the VBA code selects which columns should be displayed in the subform. Which columns two display, need to be checked each time an import is opened.
However if I do this in VBA, can two users open the same form at the same time (they work in the same access file) with two different imports and have different columns displayed ? Or do I need to create an instance of the form for each user, and then delete that instance when the user is done ? That doesn't seem like the best idea, but I'm not sure how to solve this.

If I understand the setup and the process users are following correctly, you have a master table to store all the various records users will copy and paste from CRM and payroll spreadsheet. For example a table like this:
You've then got separate CRM and Payroll queries, that simply show a different set of columns from the import table:
You've then got some form set up, which allows users to open the correct query:
..e.g. qryCRM:
..and copy/paste data from the relevant Excel spreadsheet:
I think you are going to have trouble trying to catch any user interaction with a query object as query objects, as far as I know, don't have many events to trigger VBA code from.
What I'd suggest doing is setting up a form with a subform for each of your CRM, payroll, etc imports.
The subform can then take your CRM and Payroll queries as a recordsource. For example, here's a subform using the query qryCRM as a recordsource:
...and if you also set the subform to a default view of "Datasheet"..
...users will be able to interact with the subform in a similar spreadsheet-style of the query object itself:
You can then set up your navigation form to point to the form rather than query:
Private Sub cmdImportCrm_Click()
DoCmd.OpenForm "frmCRM"
End Sub
You can now utilise a range of events on the subform to get additional data in to the dataset when the user pastes new records.
The best way I've found so far is to use the subform's BeforeInsert event:
This event is triggered each time a new record is added to the dataset, so if you paste 5 new rows, the event should trigger for each of those 5 rows.
For this event I simply specified that I wanted the ImportID column to get the text "CRM Import" (you can obviously specify something else):
Private Sub Form_BeforeInsert(Cancel As Integer)
Me.ImportID = "CRM Import"
End Sub
So when we paste our data as new records, we also get the text we specified for the ImportID column as well:
Hope this helps :)

Related

Unable to Save Due to Record Locking (by Current Machine)

Updated***
To quickly summarize what I said before which was lengthy and probably too roundabout confusing...
My issue was I have a main form interface with 2 subforms that does the following:
the First one is always shown for current daily event task(s) based on a label control with current date or any given dates via the prev/next toggle buttons as criteria.
The second one is part of the main subform that will be called based on the selection from the main navigation controls. This subform shows all the event tasks that are created in the database.
Both use saved query select statements with a snapshot and no record lock as recordsource in a continuous form. The table source is linked via split database in the same shared network drive and the table itself contains only 8 fields:
ID (12 chars randomly generated with specific sequence via VBA with no duplicate allowed)
Event Name (Text)
Event Desc (Long Text/Memo)
Occurrence (Text)
Start Date (Date)
Selected Day (Text)
Allow Weekend (Text)
Active (Boolean)
To edit a selected record, it will be called and populated onto a popup unbound model form via VBA. Here everything works fine as for records with fewer chars found in the Event Desc field. However, for records with a large number of chars (so far those that I noticed with issues were the ones with >4000 chars). I can call and display them fine to the detail view form (unbound) but when making edits, by the time it gets to the updating field for Event Desc, it would generate the record locking error by the same user (me) for those with large text size.
After several trials and errors, I noticed it has to do with the displayed continuous subforms that I have presenting. I noticed that the form for them were originally set as dynaset to which I tried to switch over to snapshot and it was a hit and miss (mostly miss). I don't know how much of this setting was an issue to the record updating as I had no problem saving records with smaller character counts.
Finally, I decided to before saving the record, I went and remove the recordsource for both of the continuous forms to empty ("") then save then reassign the query (saved or direct doesn't matter) and it worked without errors after. I personally don't like doing it this way as it makes the continuous forms update look ugly and not smooth (see the #Name?) in the assigned controls due to unrecognized control source since the recordsource is now empty. However, this was the best way that I could think up at the moment.
I even tried using a bounded form for editing the record instead of the unbound form and the same error outcome, but that time it gave a different record locking error# but pretty much for the same reason.
I'm sure this issue is not related to how my VBA code was written nor the queries used in the continuous forms. It's most likely the form settings themselves or just some limitation of Access?

How to prevent a form in Access from deleting data from other tables used to filter in the data source query

I am new to MS Access and VBA coding, and what I know I had to teach myself through video tutorials and reading up on the web. I have an input Form which which gets its data from a query. The query itself gets its information from a table and another query. The reason is that the other query is what filters the data so that the current user can only see his/ her own records, and not that of others. It has been designed in such a way that if a subordinate changes from supervisor, one merely have to update the supervisor name, and all the prior data in the table for that subordinate will also then reflect for the new supervisor, and no longer the old supervisor.
The problem is that the delete button on the input Form (which was created with the button wizard) not only delete the record from the table, but also from the table used to filter the subordinates. I only want it to delete the record from the actual table used in the data source query.
How would I go about to stop it from deleting in both tables?
I have attached a snapshot of a portion of the data source query, just so that you can understand what is meant by the above. The delete button on the input Form deletes the data from the table named "TableReviewNotes" and "TableAuditorNames". It should only delete the record from "TableReviewNotes".
Thanks in advance.

MS Access - Track changes made to existing table into another table (using table datasheet view - not form)

I want to be able to track any changes made to any of the fields in an existing table. The scenario is as follows:
the user opens the datasheet view for an existing table in MS Access 2007/2010
updates values in 2 fields and 5 rows (10 cells)
saves the table (overwrites it)
I want to be able to push the changes (10 changes/rows) to a new table and then be able to open it in datasheet view to refer to it. Is there a way I can do this in access without using form?
In 2010 and later you can use data macros, or what often other systems called table triggers.
You cannot in 2007.
Keep in mind that your use of the term “save table” is VERY wrong in the context here. In fact VERY wrong in the context of most databases. The user does not “save” the table.
You can ONLY edit ONE ROW at a time in a datasheet. When you move off that record then the ROW is saved (not the table). , and if you move off, then the record is saved.
In 2010 and later, you have use of table procedure code. This thus will allow one to use a table trigger.
So 2010 and later does support table triggers and store procedure code. But since your question in includes Access 2007, then my suggestion to use table triggers (called data macros) may not work unless you can restrict users to 2010 and beyond.
In the follow example, when a user updates a row, then a “audit” table is updated with the user information. The function fosusername() is in fact a VBA function. This code is called from the before change update event for the table.
Of course the problem here is the VERY basis of your question assumes that users save a table – they don’t, they edit + save “single” records, or a single row at a time. So figuring “out” how a user is done would certainly be a challenge. So while code can be run when the users edit data, having table code run “when” the user closes the table is not possible.
As the end of the day, it likely best you create a datasheet that looks just like the table, and then change a few settings to “lock down” and prevent the user from using tables directly.
As far as I know there is no solution for this without using a form. I do not know of events (like a change or dirty event) for the actual data tables.
In a form you could use the dirty property to make sure you fetch the data. You can make the form look like a datahseet with DoCmd.RunCommand acCmdDatasheetView or set the form in datasheet view on default.

How do I populate a field with static header row information on import?

As it stands, I am currently looking to import data from an Excel spreadsheet into a table on a monthly basis. The header row in the spreadsheet contains the date that the original query was run.
I have one master table in access consisiting of multiple files. I would like to set up an automated process to capture the date in the header upon import, and then record it in a field for every new record that was imported.
There are two caveats here:
Spreadsheet sizes will vary depending on where data exists.
I have no control over how the data is provided. Fields that contain no data for the month will not populate to the spreadsheet.
Less frequently fields will be added that do not exist.
So far I have been identifying these new additions manually and creating a new field for them at the end of the field list. I realize that this is very inefficient and I would like to automate it, if I can.
Does anyone have any insight? Any assistance would be greatly appreciated.
OK, here's the steps you'll want to take.
Create a link from Access to your Excel spreadsheet. Access will now see this as a table.
Create a make table query using the Excel table as the source and adding the date (derived from a sub-query) as an additional field.
Then run the query. This will automatically create all the fields.
If, however, you need to create new fields in an existing table, then you'll have to use VBA, read each header in the Excel table, compare it to the schema of the existing table, and execute an alter table query to add the field.
Good luck

Access Application with SQL backend blanking form details

I have an ancient Access application that I've recently moved the data to a SQL backend using the SQL Server Migration Assistant, and almost everything is working except for one issue.
In the application, we have a form with another form inside of it. The outside form finds specific "issues" entered into the system, and then looks for a history record(the inside form) that is associated with this issue. If a history record is present, it works perfectly, as the record shows up in the embedded form just fine. However, if there is no history record yet present in the database, the entire details sections of the embedded form blank out entirely. The properties are all set exactly the same as when it was a pure Access Database, but now that I've switched it to pull from SQL using Linked Tables, the form is now blank when I don't have a record to pull from.
EDIT: I learned that there are two conditions that when both met will cause a form's details pane to go blank: (1) there are no existing records to be displayed, and (2) it is not possible to add a new record.
This means that the second condition is where my issue lies. I tried scrolling to the bottom of each of the linked tables in Access, and for the History records table, I was not able to add any new rows, but for the Issues table, I was. Something is keeping me from being able to edit this one table for some reason.
I think the behavior you described may happen when the record source of the subform (your "inner form") is read-only. When matching rows exist, they are displayed. But, when no matching rows exist, you can't add a row so the subform's bound data controls are disabled.
Open the subform in Design View. Select the form and open its property sheet (Alt+Enter). Find the Record Source property on the Data tab of the property sheet. If the property value is a SELECT statement, copy it and past into SQL View of a new Access query then switch the query to Datasheet View. If the property is the name of a table or saved query, open that object directly in Datasheet View.
Once you have the form's record source opened in Datasheet View, are you able to add a row? If not, make sure the SQL Server user has INSERT permission for the data source. However, even with INSERT privilege, Access may have linked the data source as read-only if it was unable to identify a field or combination of fields which uniquely identify each row. If that is the case, you may need to re-link the table and tell Access which field(s) to use as the primary key.