I have a Staff Recruitment Database. When all formalities are complete I click a button and basic data is appended to the (recruited) Staff Database .
I also have data for the shift the recruit will work: Hours, Rate of pay etc. This goes into a Linked table.
To append this data I need to know the Primary Key of the recruit. How can I append the data automatically without looking at the table where the basic data is to find the PK?
I'm using INSERT INTO. Staff Database contains the main Staff table and the linked Shifts table.
If the "main" table has an AutoNumber field as its Primary Key then immediately after performing the INSERT INTO statement you can use some code like this to retrieve the PK value you just inserted:
Dim rst AS DAO.Recordset, newPK as Long
Set rst = CurrentDb.OpenRecordset("SELECT ##IDENTITY", dbOpenSnapshot)
newPK = rst(0).Value
rst.Close
Set rst = Nothing
You can then use the newPK value as a foreign key in the related tables.
Edit re: using the new value
Based on the code sample in your comment, try this instead:
strSQL = _
"INSERT INTO tblShifts (StartDt, [To], Hours, StaffLookup) " & _
"IN ""C:\__tmp\Staff.accdb"" " & _
"SELECT qryAdd.DateStarted, qryAdd.To, qryAdd.Hours, " & newPK & " AS StaffLookup FROM qryAdd"
If [tblShifts] really is a linked table then you shouldn't need to use the IN (mydatabase) clause because a linked table will behave just like a local table in this case. Note the corrections to the syntax as well, especially the bracketing of [To] which is a reserved word in Access.
Think I have got a solution. I can retrieve the PK into the recruitment db like this:
DoCmd.RunSQL "INSERT INTO tblCBSStaffLookup ( StaffLookupCBS, NINO ) " & _
"SELECT tblStaff.ID, tblStaff.NINO " & _
"FROM tblStaff IN 'C:\Users\Peter.Home-PC\Documents\NEMS\Databases\Frontends\Staff.accdb' " & _
"WHERE (((tblStaff.NINO)=[Forms]![frmSuccess]![NINO])) "
tblCBSStaffLookup is a table I have now made in the recruitment db to collect the PK and NINO.
WHERE matches the newly arrived NINO to a form in the recruitment db which already has the NINO. I have set up constraints to make sure that NINO's are valid. I have also set up a query in the recruitment db to retrive all NINO's from the main db, so that new recruits don't get added the the main db twice.
Related
So, I know how to add an autonumber field to a table using SQL:
dblocal.Data.Execute "CREATE TABLE " & TableName & " (" & FieldName & " COUNTER(1,1) )"
Where dblocal is the passed database reference with TableName & FieldName the appropriate names for the desired creation of the table.
However, I want the counter to start at ZERO not ONE. And I know it's possible because the table I need to repair / duplicate starts with ZERO
What am I not finding on the internet to aid me in this task?
My search-fu fails me.
First of all, I'm very new with coding, so please bear with me, secondly;
I am currently trying to draw records from another database inside a network into my database. This has proved to be a little troublesome, because I would want to fill all fields in all tables that have the same primary key.
My current code looks like this
varPrimaryKey = InputBox("Specify primary key:")
strPrimaryKey = module1.Item1
If Not varPrimaryKey = "" Then
MsgBox ("Get data from: " & varPrimaryKey)
If Not (tdf.Name Like "MSys*" Or tdf.Name Like "~*") Then
For Each tdf In externalDb.TableDefs
For Each fld In tdf.Fields
db.Execute ("INSERT INTO CurrentDb.fld.Name SELECT fld.Name FROM tdf.Name WHERE fld.Name = 'Value' AND varPrimaryKey = 'Value'")
Next fld
Next tdf
End If
End If
Right now I'm getting a type mismatch error from .CurrentDb , but I have a feeling that there's something else wrong with this code too, just can't put my finger on it. If someone could help, I would really appreciate it!
Reconsider this entire approach. For user application needs, databases should not be copied versions of each other as gathered from above comment:
I meant that I would want to draw ALL records from ALL tables that
have the same primary key ID as the one that the user has entered
inside an input box
One of the central tenets of a relational database is to avoid duplication of data. Plus, if users add/edit data it will reflect live on the system. Data transference between databases should only be run for migration purposes where one is to be archived and other for production.
With that said, consider the following steps to build your user application:
Link all needed tables from network database. The GUI dialog allows a Select All feature or holding SHIFT and/or CTRL for multiple tables.
Build a temp table to hold current user's primary key and insert data value via VBA. This is the only table to hold data (one column/one row structure) in application database. See below steps:
Create a table with code or via Table Design (one row/one column)
CREATE TABLE TmpPrimaryKey (
PrimaryID Long
)
Append using user input as below shows with parameterization with VBA. This code should be run regularly for any change to PK. Ideally, run this at startup of application.
Dim qdef As QueryDef
Dim strSQL As String
Dim varPrimaryKey As Variant
varPrimaryKey = InputBox("Specify primary key:")
' CLEAN OUT TEMP TABLE
CurrentDb.Execute "DELETE FROM TmpPrimaryKey", dbFailOnError
' APPEND TO TEMP TABLE
strSQL = "PARAMETERS [PkParam] LONG;" _
& " INSERT INTO TmpPrimaryKey (PrimaryID) VALUES ([PkParam])"
Set qdef = CurrentDb.CreateQueryDef("", strSQL)
qdef![PkParam] = varPrimaryKey
qdef.Execute dbFailOnError
Set qdef = Nothing
Create a filtered query for every linked table aligning to TmpPrimaryKey (i.e., the target primary key). Doing so, the user will only see such records. Use these queries for forms/reports recordsources or module recordsets.
Queries can use the JOIN, IN, EXISTS clauses such as below examples of separate SQL statements. Tables below would be linked tables from network database (step #1).
Query1
SELECT src.*
FROM [Table1] src
INNER JOIN TmpPrimaryKey tmp ON src.ID = tmp.PrimaryID;
Query2
SELECT src.*
FROM [Table2] src
WHERE src.ID IN (SELECT PrimaryID FROM TmpPrimaryKey);
Query3
SELECT src.*
FROM [Table3] src
WHERE EXISTS
(SELECT 1 FROM TmpPrimaryKey tmp WHERE src.ID = tmp.PrimaryID);
Because you potentially have many tables, build above SQL queries in VBA loop using TableDefs and QueryDefs. NOTE: Below loop routine to create queries should be run only once.
Dim tdef As TableDef
Dim qdef As QueryDef
Dim strSQL As String
' LOOP THROUGH ALL TABLES OF APP DB (I.E., LINKED TABLES)
For Each tdef in CurrentDb.TableDefs
If tdef.Name <> "TmpPrimaryKey" And tdef.Name Not Like "MSys*" Then
' ASSUMING EACH TABLE'S PK IS NAMED ID
strSQL = "SELECT src.* FROM [" & tdef.Name & "] src" _
& " INNER JOIN TmpPrimaryKey tmp ON src.ID = tmp.PrimaryID;"
' NAME EACH QUERY SAME AS TABLE WITH "Q_PK" SUFFIX
Set qdef = CurrentDb.CreateQueryDef(tdef.Name & "Q_PK", strSQL)
Set qdef = Nothing
End If
Next tdef
Set tdef = Nothing
Again, set all needed application objects (forms, reports, modules, etc.) to point to these queries as the data sources and not linked tables, holding all data. Queries should be updateable for user to add/edit records.
From there, distribute copies of this application database to all users in a frontend/backend split architecture, maintaining one centralized and normalized database and many app files that hold no data (except of course, the temp PK value).
You just reference the table you want to INSERT into. What you need is path to the other db. Need to concatenate variables. You don't show declaring and setting variables db, tdf, fld, externalDB. Need to swap the If and first For lines. Your INSERT SELECT will not work the way you think, unless you really want each field inserted into its own record. Consider:
For Each tdf In CurrentDb.TableDefs
If Not (tdf.Name Like "MSys*" Or tdf.Name Like "~*") Then
CurrentDb.Execute ("INSERT INTO [" & tdf.Name & "] SELECT * FROM [" & tdf.Name & _
"] IN 'other db path\filename.accdb' WHERE [Value] = '" & varPrimaryKey & "'")
End If
Next tdf
However, autonumber fields will interfere with this simple INSERT SELECT. Also, fields in both tables must be arranged in same order in table design.
Value is a reserved word and really should avoid using reserved words as names for anything. If Value is a number data type then eliminate the apostrophe delimiters.
Why have that MsgBox?
But then why all this effort anyway and not just link to the backend tables?
I have a user form that inserts data into "user" table and "organizer" table when I click a button, user data gets inserted with no problem, but it prompts me to enter the value (organization_name) again in a small dialogue box -which supposed to take from the text field and insert into organizer table- ,
then gives me an error saying "ms access set one row null due to validation rule violation"
NOTE: I didn't put any validation rule for the "organization_name" anywhere
Private Sub InsertSqlIntoOrgTable()
Dim orgName As String, SqlOrgNameInsert As String
orgName = txtOrgName.Value 'takes the value from text field
SqlOrgNameInsert = "INSERT INTO ORGANIZER (ORG_NAME) VALUES (" & orgName & ") "
DoCmd.RunSQL SqlOrgNameInsert
End Sub
SqlOrgNameInsert = "INSERT INTO ORGANIZER (ORG_NAME) VALUES ('" & orgName & "') "
if the field name in table ORGANIZER is really ORG_NAME. Show us your complete table definition in case that this doesn't solve your problem. Because in your last question you posted:
sqlOrgInsertUsrId = "INSERT INTO ORGANIZER (USER_ID) VALUES (" & orgUserId & ")"
Both inserts run into the same table but try to create new independent rows. If USER_ID is primary key then your insert into ORG_NAME can't work that way.
You should learn more about SQL.
I am doing my best to build my first database, but I have come up against a problem I just cannot find an answer to. I am a complete newbie in this forum and writing any sort of code so please be gentle.
I am trying to create a new record in a table when a student's name is double clicked inside a list box which is inside a form.
List box where I want to take first (StudentID) column value from = lstStudent
Combo box where I want to take the second (CourseID) column value from: cboCourseID
Text box where I want to take third (NoteID) column value from = txtCourseNoteID
The new record is being created in the desired table and there are no incorrect code errors but there are no values being carried across to the fields. The autonumber is being created (AttendanceID) but the other columns are blank. Here is my code:
Private Sub lstStudent_DblClick(Cancel As Integer)
CurrentDb.Execute "INSERT INTO tblAttendance (StudentID, CourseID, NoteID) VALUES ('me.lstStudent','me.cboCourseID','me.txtCourseNoteID')"
End Sub
The fields are populated, so this isn't the issue. The formatting is correct for the target fields and I can't think of anything else in my way.
The new record is being created in the desired table and there are no
incorrect code errors but there are no values being carried across to
the fields. The autonumber is being created (AttendanceID) but the
other columns are blank.
With this INSERT statement, you're supplying text values for those 3 fields in the new row ...
INSERT INTO tblAttendance (StudentID, CourseID, NoteID)
VALUES ('me.lstStudent','me.cboCourseID','me.txtCourseNoteID')
However StudentID, CourseID, and NoteID are numeric fields, so will not accept those text values. In that situation, there is nothing the db engine can insert. You still get a new row added (with the new autonumber value in AttendanceID), but those other fields are empty.
If you include the dbFailOnError option with .Execute, Access will notify you about the problem (error #3464, "Data type mismatch in criteria expression") and abort the insert --- a new row will not be added ...
CurrentDb.Execute "INSERT INTO tblAttendance (StudentID, CourseID, NoteID) VALUES ('me.lstStudent','me.cboCourseID','me.txtCourseNoteID')", dbFailOnError
Use an approach similar to what #HarveyFrench suggested, but eliminate the single quotes from the VALUES list ...
Dim strInsert As String
strInsert = "INSERT INTO tblAttendance (StudentID, CourseID, NoteID)" & vbCrLf & _
"VALUES (" & Me.lstStudent.Value & "," & Me.cboCourseID.Value & "," & _
Me.txtCourseNoteID.Value & ");"
Debug.Print strInsert ' <- view this in Immediate window; Ctl+g will take you there
CurrentDb.Execute strInsert, dbFailOnError
Based on what you've told us, I suspect that will work, but I'm not sure it's the best way to reach your goal. You could open a DAO.Recordset and add the new row there. Or if you can use a bound form, Access would automatically take care of storing a new row ... without the need to write code.
Change this
CurrentDb.Execute "INSERT INTO tblAttendance (StudentID, CourseID, NoteID) VALUES ('me.lstStudent','me.cboCourseID','me.txtCourseNoteID')"
to be this
CurrentDb.Execute "INSERT INTO tblAttendance (StudentID, CourseID, NoteID) _
VALUES ('" & me.lstStudent & "','" & me.cboCourseID & "','" & me.txtCourseNoteID "');"
See also here for useful info
Can someone please help me with the following line. I am trying to create a table that will have a column with the Id that automatically increments when a record is inserted. This is for microsoft access.
"CREATE TABLE " & tblName & " ([P_Id] integer not null AUTOINCREMENT(100, 5))"
Try the following to create an MS Access table with an auto-number field:
"CREATE TABLE [" & tblName & "] ([P_Id] integer not null IDENTITY)"
I do not know if you can specify a start-value and increment, but you can try it.