I have an access db with some tables, queries, macro... etc
One table is a result of a query and it's used to populate a sharepoint. This table has a column [User] that has no records but I would like to fill with a list of users before upload to the sharepoint.
Ex. the table has 58 rows and I whant to use the 10 users.
Row1 - User 1
Row2 - User 2
...
Row10 - User 10
Row11 - User 1
and so on...
I realy don't know what is the best way to do this.
Can anyone help me? Thanks.
I would suggest using Visual Basic for Applications (VBA) for this.
Create a new Module and then create a procedure that will populate the data.
Its relatively simple - you want to loop through all the users and update the parent table.
For my code, I am assuming that you have one table holding your query results (with the empty "User" field), and that you have another table holding all of your users (using the field name "UserName")
Public Sub PopulateUsers()
Dim dbs As DAO.Database
Dim rstUsers As DAO.Recordset
Dim rstComputers As DAO.Recordset
' Open up our tables
Set dbs = CurrentDb
Set rstUsers = dbs.OpenRecordset("Users")
' If there are no users then complain and quit
If rstUsers.EOF Then
rst.Close
MsgBox "There are no users to populate", vbInformation, "Error"
Set rstUsers = Nothing
Exit Sub
End If
Set rstComputers = dbs.OpenRecordset("ComputerUsers")
' Loop through all of our computer records
Do Until rstComputers.EOF
rstComputers.Edit
rstComputers!User = rstUsers!UserName
rstComputers.Update
rstUsers.MoveNext
If rstUsers.EOF Then
rstUsers.MoveFirst
End If
rstComputers.MoveNext
Loop
' Close tables
rstUsers.Close
rstComputers.Close
' Clear object references to free up memory
Set dbs = Nothing
Set rstUsers = Nothing
Set rstComputers = Nothing
debug.print "Users Populated"
End Sub
You can press Control + G to open the immediate window and then type "PopulateUsers".
Related
I have a database which I'm working on. It is composed of split database, both front and multiple links to backend tables.
I am working on a report which is composed of 15 different sub-reports. I have a form which allows me to input start date and end date for the report. There's a button which generates the final report. The problem is when I want to generate the report, I would have to re-run each of the different make-table queries for each of the sub-reports. The issue with this is that there would be 2 warnings for each query, one to delete my table and another for rows added to the table.
I researched online and found this code to run the Execute command which will remove all the warnings. I'm new to VB but I figured I'll give it a try and I get the following run-time error "3078: The MS Access database engine cannot find the input table or query". I checked the query name and it matches so I'm not sure why I'm getting this error. I've only tried one of the 15 queries so I can make sure it works. Once I get this to work, my other question is would combining all these into 15 execute commands work in the module?
Private Sub PS_Report_Date_AfterUpdate()
Dim dbs As DAO.Database
Dim lngRowsAffected As Long
Dim lngRowsDeleted As Long
Dim sql$
sql = "[qry_Maui_Division_KWH_Produced]"
Set dbs = CurrentDb
' Execute runs both saved queries and SQL strings
dbs.Execute sql, dbFailOnError
' Get the number of rows affected by the Action query.
' You can display this to the user, store it in a table, or trigger an action
' if an unexpected number (e.g. 0 rows when you expect > 0).
lngRowsAffected = dbs.RecordsAffected
dbs.Execute "DELETE FROM tbl_Maui_Division_KWH_Produced WHERE Bad", dbFailOnError
lngRowsDeleted = dbs.RecordsAffected
End Sub
SQL Code:
SELECT
tbl_MPP_DailyGenerationReport.DateLog,
[MPP_Daily_Gross_Gen_kWh]+[Total_Gross_kWh] AS Maui_Gross_kWh_Produced,
[Total_Aux]+[Total_Aux_kWh] AS Maui_Gross_Aux_kWh_Produced, [MPP_Daily_Gross_Gen_kWh]-[Total_Aux]+[Total_Net_kWh] AS Maui_Net_kWh_Produced,
Round(([Total_MBTU_Burned]*1000000)/([MPP_Daily_Gross_Gen_kWh]+[Total_Gross_kWh]),0) AS Maui_Gross_BTU_kWh,
Round([Total_MBTU_Burned]*1000000/([MPP_Daily_Gross_Gen_kWh]-[Total_Aux]+[Total_Net_kWh]),0) AS Maui_Net_BTU_kWh,
Round(([MPP_Daily_Gross_Gen_kWh]+[Total_Gross_kWh])/[Total_Barrels_Burned],0) AS Maui_Gross_kWh_BBL,
Round(([MPP_Daily_Gross_Gen_kWh]-[Total_Aux]+[Total_Net_kWh])/[Total_Barrels_Burned],0) AS Maui_Net_kWh_BBL
INTO tbl_Maui_Division_KWH_Produced
FROM ((tbl_MPP_DailyGenerationReport
INNER JOIN tbl_KPP_DailyGenerationReport
ON tbl_MPP_DailyGenerationReport.DateLog = tbl_KPP_DailyGenerationReport.DateLog)
INNER JOIN tbl_MPP_Aux_DailyGenerationReport
ON tbl_MPP_DailyGenerationReport.DateLog = tbl_MPP_Aux_DailyGenerationReport.DateLog)
INNER JOIN qry_Maui_Total_Fuel_Burned
ON tbl_MPP_DailyGenerationReport.DateLog = qry_Maui_Total_Fuel_Burned.DateLog
WHERE (((tbl_MPP_DailyGenerationReport.DateLog)=[Forms]![Power Supply Reports]![PS_Report_Date]));
This will run your queries without warnings:
Private Sub PS_Report_Date_AfterUpdate()
DoCmd.SetWarnings False
DoCmd.OpenQuery "qry_Maui_Division_KWH_Produced"
DoCmd.RunSQL "DELETE FROM tbl_Maui_Division_KWH_Produced WHERE Bad"
DoCmd.SetWarnings True
End Sub
The SELECT ##IDENTITY statement in Access VBA, would allow one to view/obtain the AutoNumber that has been generated in a table, for which a record has just been inserted, on the database. This is somewhat easy to track and maintain, if there is just one user and only one INSERT takes place at any moment of time.
My application is multi user, so far only one person used to do data entry. Now we have two people and when one user (Mr Brown) inserts a record (Auto ID : 1234) and within a second (we are dealing with milliseconds) another (Mr Green) INSERTS a record (Auto ID : 1235), the ##IDENTITY seems to return the latest ID 1235 for Mr. Brown and not 1234 which he inserted. As the same Mr. Green gets the same 1235, which is correct.
My Question is, is there a way to make sure that ##IDENTITY return the AutoID of that particular INSERT for that user that performed the INSERT. This is my code, if that helps.
tranDB As DAO.Database
Set tranDB = CurrentDb
tranSQL = "INSERT INTO Transactions (Password....." 'My Insert goes here
tranDB.Execute tranSQL
Dim idRS As DAO.Recordset
Set idRS = tranDB.OpenRecordset("SELECT ##IDENTITY AS LastID;")
TranID = idRS!LastID
idRS.Close
Set idRS = Nothing
EDIT: Not a Duplicate of MS Access TableAdapter Get Identity after insert. As the other thread involves with SQL Server, mine is JET Engine and Not .NET, I am using this code in VBA.
Paul have your tried to encapsulate it within a transaction? try this
Dim tranDB As DAO.Database
Set tranDB = CurrentDb
tranSQL = "INSERT INTO Transactions (Password....." 'My Insert goes here
dbEngine.BeginTrans
on Error goto ERROR_INSERT:
tranDB.Execute tranSQL, dbFailOnError
Dim idRS As DAO.Recordset
Set idRS = tranDB.OpenRecordset("SELECT ##IDENTITY AS LastID;")
'ideally put another error trap here
TranID = nz(idRS("LastID"),0)
DBEngine.CommitTrans
On Error resume Next
idRS.Close
Set idRS = Nothing
SET tranDB = nothing
Exit sub/Function
ERROR_INSERT:
dbengine.rollback
'and other stuffs or resume to exit label
Paul,
I have used this technique for forever and it works for me (I would have lost my job many times over if it didn't work!!).
1) You have tagged this as an Access 10 question. So, are you using this reference in your project?:
Microsoft Office 14.0 Access database engine Object Library
C:\Program Files (x86)\Common Files\Microsoft Shared\OFFICE14\ACEDAO.DLL
Older DAO references might be problematic. This feature is not supported before DAO 4.0.
2) Regarding krish's suggestion: transactions, while a good idea, are not required for this feature to work. The last Identity value is locally stored by the current connection. You just have have to call it before the user does another insert.
3) But, it is a good idea to use the same database reference to do both the Insert and retrieve the Identity. In your example, your use of tranDB should be correct -- but if you are re-assigning it to CurrentDB before calling Identity, this could be the problem.
4) Are you using Timestamps to be sure that Brown is inserting before Green?
5) As a last resort, you can try an all-DAO alternative:
'------------------------------------------------------------------------------------------
' The query insert method is used here because DAO respects record-level locking
' on programmatically opened recordsets
'------------------------------------------------------------------------------------------
Set idRs = tranDB.OpenRecordset("SELECT ID, Password, InsertTime FROM Transactions (Password.....", dbOpenDynaset, dbAppendOnly + dbSeeChanges, dbOptimistic)
With idRs
.AddNew
!Password = sPassword
!InsertTime = Now
.Update
' Move to New Record
.Bookmark = .LastModified
lIdentity = !ID
.Close
End With
See if this yields different results.
So I'm converting an access back-end to SQL. I've tried a few different tools (SSMA, Upsizing Wizard, and a simple import). I've found so far that the SSMA tool and importing seem to work the best, eliminating most of the work necessary for me. However, I'm running into one issue I can't figure out how to overcome.
Two fields allow multiple values (dropdown with check boxes). In converting these, it errors in a way that it not only doesn't carry all of the information over, but also grabs information from another field (and doesn't carry that information over).
I've tried forcing access to only accept the first value (and get rid of multi-values all together), but it won't let me.
Any ideas?
This should get you started. It will turn all those values which are selected in the multi select field into their own table. You will need to establish the relationships between the three tables to create a true many to many relationship after the fact.
Sub ExtractMultiValueFields()
Dim JoinTable As New DAO.TableDef
JoinTable.Name = "JoinTable"
With JoinTable
.Fields.Append .CreateField("MainTableId", dbInteger)
.Fields.Append .CreateField("JoinToValue", dbText)
End With
Dim joinRs As DAO.Recordset
CurrentDb.TableDefs.Append JoinTable
Set joinRs = CurrentDb.OpenRecordset("JoinTable")
Dim rs As DAO.Recordset
Dim childrs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("select * from table1")
Do While Not rs.EOF
Debug.Print rs("ID")
Set childrs = rs("col1").Value
Do While Not childrs.EOF
Debug.Print childrs("value") 'always "value"
joinRs.AddNew
joinRs("MainTableId") = rs("ID")
joinRs("JoinToValue") = childrs("value")
joinRs.Update
childrs.MoveNext
Loop
rs.MoveNext
Loop
End Sub
I performed some research how do I need to set up my DB but I need your advice how to.
I have few tables in my db ( db is for incoming material ) in this db are below tables:
Material table
incoming delivery
measurements
supplier
time measurement
Let me explain logic of this db.
When delivery come user will input some data in form (creation of incoming list) where he will basically enter all data necessary to start process of receiving. So once he hit button save record he will create record in tables incoming delivery and time measure.
Until this point everything works perfectly. When next user received this incoming list he got some data where was one hyperlink to file where they put it measurements.
And here come my problem.
I want data to be input in Access rather than to excel (form input looks much more better [yes this is most important reason :) ] ).
So for that I created table called measurements, where I plan input [incoming delivery ID], [material id], [primal key] , and that 41 another columns for measurement(this columns need to be separated cause we have many parts and each got different No. of measurement and user will get information via user form ( opening different form based on material id [this works]).
So after describing its logic I am requesting you people how do i create with 1 record to measurement table each time different numbers of measurements in measurements table for it.
put it even more simple just for case. When user hit button to save the record which creates record in delivery list will also create for example additional 5 records (this number will be based on cell value) in measurement table linked with incoming delivery. (relation is of course set up to one-many)
so in the end when i will create somehow continuous table for data input. User will see form where he got incoming delivery No. some information from other tables and as mentioned 41 items to measure 5 times ( 41 columns and 5 rows )
Hope that my explanation is clear and rly need your help i am screwed :D
Hints:
Use VBA to automate the creation of records. Look for information about DAO and/or ADO and how to use them to insert records (I personally use DAO when I work with Access, it works but it's old).
Do your homework. Before asking a question, it is important that you do your research and that you try to solve the problems by yourself. Try to help yourself before asking others. Please read this article.
Maybe this snippet of code can help you. You'll need to call this method from an event (button_clic or something in your form):
public sub addRecords(id as integer)
dim db as dao.database, rsIn as dao.recordset, rsOut as dao.recordset
dim strSQL as String
dim someValue as integer, i as integer ' Test values
' "Connect" to your current database
set db = currentdb
' Create a recordset with the input data you need (read only)
strSQL = "select * from tbl_inputTable where id=" & id
set rsIn = db.openrecordset(strSQL, dbOpenDynaset, dbReadOnly)
' Create a recordset to your output table
set rsOut = db.openRecorset("tbl_outputTable", dbOpenDynaset, dbAppendOnly)
' Read the data from the input table
with rsIn
.moveFirst
someValue = rsIn![aField]
end with
' Write some test data to your output table
with rsOut
for i = 1 to someValue
.addNew
rsOut![fk_id] = id
rsOut![theValue] = i
.update
next i
end with
' Close every recordset and databases (this does not close your application)
rsIn.close
rsOut.close
db.close
end sub
In your input form, write this in the "On Click" event:
sub button1_click()
call addRecords(txtId.value) ' I am assuming that there's a text box called "txtId"
end sub
This is just a sample of what you can do with DAO. I won't (and maybe nobody else would) write the full code for you: You'll need to fit this to your particular problem.
It's a very common question but I'm having trouble getting the ID of the last inserted record. I'm using DAO with ODBC linked tables to duplicate a record and it's child records. My tables are in SQL Server 2008 and have Identity fields for ID fields.
Here's what I've tried so far. My first bit of code here results in error 3167, Record is Deleted. If I do a debug.Print the recordset actually contains 3 records.
Dim r as DAO.Recordset, db as DAO.Database
Set db = CurrentDb
Set r = db.OpenRecordset("SELECT TOP 2 * FROM item ORDER BY DateTimeModified DESC", dbOpenDynaset, dbSeeChanges)
r.AddNew
'Set field values here
r.Update 'Completes without error
r.Bookmark = r.LastModified
Debug.Print r("ItemID") 'Error 3167, Record is deleted
Here's the next thing I tried:
Debug.Print db.OpenRecordset("SELECT ##identity FROM item")(0)
This last one completes without any problem but the value returned is incorrect. Where the actual new ItemID is 321 this returns the value 614. The value it is returning does appear to be incremental (it changes as I keep testing this) but it does not appear to relate at all to my table. There is no field with the value 614. I've double checked to make sure I'm looking up the correct table.
I know I could use something like DLookup or DMax but I don't think that would be considered bullet proof in a multi-user environment.
I suppose I could use a Stored Procedure with ADO to get around this problem. I'm wondering if that is my only option?
Edit1:
I'm now using the following code and it is doing what I need/want it to. I suspect this is basically the same as using DMax.
Dim r as DAO.Recordset, db as DAO.Database
Set db = CurrentDb
Set r = db.OpenRecordset("SELECT TOP 1 * FROM item ORDER BY ItemID DESC", dbOpenDynaset, dbSeeChanges)
r.AddNew
'Set field values here
r.Update
r.Requery
r.MoveFirst
Debug.Print r("ItemID")
As far as I'm aware ##IDENTITY doesn't work for cursor-based inserts. DAO and ADO both use cursors behind the scenes.
After you .Update the record you should be able to get the identity value back simply by reading the value.
The following works fine for me via an ADO Recordset opened with Keyset semantics:
r.Update
Debug.Print r("ItemID")
The following works fine for me via a DAO Recordset opened with Dynaset semantics:
r.Update
r.Bookmark = r.LastModified
Debug.Print r("ItemID")
You should avoid .Requery and .MoveFirst, you're introducing concurrency problems. Consider:
Dim r as DAO.Recordset, db as DAO.Database
Set db = CurrentDb
Set r = db.OpenRecordset("SELECT TOP 1 * FROM item ORDER BY ItemID DESC", dbOpenDynaset, dbSeeChanges)
r.AddNew
''// Set field values here
r.Update
''// At this point another user adds a new record
r.Requery
r.MoveFirst ''// ORDER BY ItemID DESC means that you're going to see the new user's row
Debug.Print r("ItemID")
The following works as expected (using Office 2013 and SQL Server 2014)
Set rsProjects = db.OpenRecordset("JobProjects", dbOpenDynaset, dbSeeChanges Or dbAppendOnly)
rsProjects.AddNew
rsProjects.Name = 'xyz'
rsProjects.Update
rsProjects.Bookmark = rsProjects.LastModified
lNewProjectID = rsProjects!ProjectID.Value
Key point: instead of using 'SELECT TOP 2' or 'SELECT TOP 1', etc. I used 'dbSeeChanges Or dbAppendOnly'. I verified in sql profiler that opening the recordset does not generate any queries to SQL Server.
When you issue the update, access generates an insert statement followed immediately by a SELECT ##IDENTITY to get the id of the new record.
Edited: add missing .AddNew, Remove duplicate .Update.
it dosnt work with sql server backend(in multi user app
). for access table it work
for sql use stored procedure.use this way
CREATE PROCEDURE dbo.AddAsset
#Name VARCHAR(500),
#URL VARCHAR(2000),
#new_identity INT = NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.Assets(Name, URL) SELECT #Name, #URL;
SET #new_identity = SCOPE_IDENTITY();
END
GO
then use this sp in front end
Simply get the value of the key field before you execute the Update statement. As pointed out in the comment below, this process will not work if you are using a different backend than Microsoft Access. But I leave this response here in case that is your use case and you are just searching for an answer to the general question of how you get the ID of the last inserted record.
For your example, you can do this with Microsoft Access:
Dim r as DAO.Recordset, db as DAO.Database
Dim lKey As Long
Set db = CurrentDb
Set r = db.OpenRecordset("SELECT TOP 2 * FROM item ORDER BY DateTimeModified DESC", dbOpenDynaset, dbSeeChanges)
r.AddNew
'Set field values here
'Retrieve the key value before executing the Update
lKey = r!ItemID
r.Update
Debug.Print lKey