I am making a rather simple inventory tracking database. And I want to retrieve the record by ID, and add or remove the specified number to the amount. If it doesn't exist I want to add it. Is it even possible to do this without binding to a table?
Sounds like you have a candidate ID value. Maybe it's contained in a numeric variable named MyID. And you have another numeric value, MyAmtChange, which is to be added to the value in a field named amount in your table for the row where the ID field value matches MyID.
A complication is there may be no row in your table whose ID value matches MyID. In that case, you need to add a row for it.
If that's correct, INSERT a row for MyID when one doesn't exist. Then you can simply UPDATE the amount in the row which matches MyID.
Dim strInsert As String
Dim strUpdate As String
Dim db As DAO.Database
Set db = CurrentDb
If DCount("*", "YourTableNameHere", "ID = " & MyID) = 0 Then
strInsert = "INSERT INTO YourTableNameHere (ID)" & vbCrLf & _
"VALUES (" & MyID & ");"
Debug.Print strInsert
db.Execute strInsert, dbFailOnError
End If
strUpdate = "UPDATE YourTableNameHere" & vbCrLf & _
"SET amount = Nz(amount, 0) + " & MyAmtChange & vbCrLf & _
"WHERE ID = " & MyID & ";"
Debug.Print strUpdate
db.Execute strUpdate, dbFailOnError
Set db = Nothing
If this guess is reasonably close, add an error handler block to that code to deal with any issues surfaced by dbFailOnError ... or any other errors.
I don't know what do you want exactly, but this code show how to manipulate data with VB-Access.
Sub fnStudent()
On Error GoTo insertError
Dim studentQuery As String
'INSERTING INTO TABLE
studentQuery = "INSERT INTO Students values ('10','YAHYA','02/10/2012')"
CurrentDb.Execute studentQuery, dbFailOnError
'UPDATING
studentQuery = "UPDATE Students Set name='YAHYA OULD ABBA' WHERE stdID='10'"
CurrentDb.Execute studentQuery, dbFailOnError
'LISTING VALUES
Dim studentsRS As Recordset
Set studentsRS = CurrentDb.OpenRecordset("SELECT * FROM Students WHERE upper(name) like '%YAHYA%';")
Do While Not studentsRS.EOF
MsgBox "ID : " & studentsRS.Fields(0) & "Name : " & studentsRS.Fields(1) & "Birth Date : " & studentsRS.Fields(2)
studentsRS.MoveNext
Loop
'DELETING
studentQuery = "DELETE FROM Students WHERE stdID='10'"
CurrentDb.Execute studentQuery, dbFailOnError
Exit Sub 'exit if there was no error
'UPDATE:
errorHandler:
If Err.Number = 3022 Then
MsgBox "Can't have duplicate key; index changes were unsuccessful", vbMsgBoxRtlReading + vbCritical, "Error " & Err.Number
Else : MsgBox "Error" & vbCrLf & Err.Description, vbMsgBoxRtlReading + vbCritical, "Error " & Err.Number
End If
End Sub
here you find a list of vba errors http://www.halfile.com/vb.html
Related
this is to add records from expenses record to an invoice details table using an invoice input form with sub forms
all related by "inv no"
i am coping info from
Exp_Inv_input_Form
to
sub form = service atlan of main form = atlan inv main
i have been trying to use INSERT INTO with no luck and cant figure out where i am going wrong
Private Sub btn_copy_Click()
Dim strSql As String
Dim IngID As Long
If Me.Dirty Then
Me.Dirty = False
End If
If Me.NewRecord Then
MsgBox "select the record to duplicate."
Else
With Me.RecordsetClone
.AddNew
!description_date = Me.TransactionDate
!description = Me.description
!hours = Me.Quantity
!Price = Me.SubTotal
!Total = Me.SubTotal
.Update
.Bookmark = .LastModified
IngID = !inv_no
If Me.RecordsetClone.RecordCount > 0 Then
strSql = "insert into [service atlan subform]([inv no], [description date], description, hours, Price, Billed )" _
"SELECT " & lngID & " As NewID, description, Quantity, Total, from_exp " & _
"FROM [service atlan] WHERE inv no = " & Me.inv_no & ";"
DBEngine(0)(0).Execute strSql, dbFailOnError
Else
MsgBox "Main record duplicated, but there were no related records."
End If
Exit_Handler:
Exit Sub
Err_Handler:
MsgBox "Error " & Err.Number & " - " & Err.description, , "cmdDupe_Click"
Resume Exit_Handler
End Sub
now its telling me that there is a problem with my strSql
do i need to name the colums the same in both the tables as i was led to belive that its the sequance in which they are placed
thanks in advance
There are few issues with your sql statement. If you have blank space in column name, enclose with [] .
Also number of columns in the insert statement not matching with select statement
Also there is , after the table name in the Insert statement
I Have been messing around with the SLQ changed the table structure a bit and have had success my bigest problem was the structure of the Select statment
"INSERT INTO [Transaction List] ([TransactionDate], [Inv No], [Division], [MomsrevLookup], [Total], [Catagory]) " & _
"Select """ & Me.[TransactionDate].Value & """, """ & Me.[inv no].Value & """,""" & Me.[Division].Value & """,""" & Me.revmoms.Value & """,""" & Me.[Inv_Total].Value & """,""" & Me.[Catagory].Value & """"
it is now coping selected rows from the form and pasting them to new records on another table
I am using the below function to determine the field data types from whichever table is given in the function parameter. Basically the function reads the data type from the table and compares it to what it should be based on the "FieldDataTypes" table. If it doesn't match, then I would like to run an Alter table SQL statement as shown below. However I am realizing that once I open the recordset I am unable to alter the table. When I run the Sub/Function below I get the error:
The database could not lock table "TEST TABLE" because it is already in use by another person or process. 3211.
How can I get around this so that I can loop through the fields and still alter the data types as necessary?
Thanks,
Charlie
Sub TestReFormat()
FncFormatFields ("TEST TABLE")
End Sub
Public Function FncFormatFields(strTableName As String)
Dim rst As DAO.Recordset
Dim fld As Field
Dim strFieldName As String
Dim strSQL As String
Dim intDataType As Integer
Dim intDataTypeCheck As Integer
On Error GoTo FormatFieldsErr:
rstSQL = "SELECT * FROM [" & strTableName & "]"
Set rst = CurrentDb.OpenRecordset(strTableName)
For Each fld In rst.Fields
strFieldName = fld.Name
intDataType = fld.Type
Debug.Print strFieldName & " " & intDataType
intDataTypeCheck = DLookup("DataTypeInt", "FieldDataTypes", "[FieldName] = '" & strFieldName & "'")
Debug.Print intDataTypeCheck
If intDataTypeCheck <> intDataType Then
strSQL = "ALTER TABLE [" & strTableName & "] ALTER COLUMN [" & strFieldName & "] " & intDataTypeCheck & ""
DoCmd.RunSQL (strSQL)
End If
Continue2428:
Next fld
Exit Function
FormatFieldsErr:
If Err.Number = 2428 Then
Resume Continue2428
Else
MsgBox Err.Description & " " & Err.Number
End If
End Function
Break your function into two parts:
A Function that examines the table returns a SQL array of ALTER TABLE statements
A Function that executes the SQL array
The query that locks the table in 1) will be closed, allowing you to alter it in 2) without error.
PS: Use rstSQL = "SELECT TOP 1 * FROM [" & strTableName & "]" so you don't waste resources returning multiple rows.
You can update data in a table without locking. In fact FEW know that the Access database engine JET/ACE can even update columns in records that are currently in use and dirty by other users (the update has to be specific to the one column - this is possible in some cases).
However, to modify a table structure and data type? You will require full exclusive rights and other users cannot have the table open, and you need full lock rights to the whole database.
Since in this case the data is of no interest, only the table structure, you can use a TableDef object to get the table structure; this will get around the lock:
Public Function FncFormatFields(tablename As String)
Dim dbs As Database, tdf As TableDef, fld As Field
On Error GoTo FormatFieldsErr:
Set dbs = CurrentDb
Set tdf = dbs.TableDefs(tablename)
For Each fld In tdf.Fields
Dim fieldname As String
fieldname = fld.Name
Dim datatype As Integer
datatype = fld.Type
Debug.Print fieldname & " " & datatype
Dim finalDatatype As Integer
finalDatatype = DLookup("DataTypeInt", "FieldDataTypes", "[FieldName] = '" & fieldname & "'")
Debug.Print finalDatatype
If datatype <> finalDatatype Then DoCmd.RunSQL "ALTER TABLE [" & tablename & "] ALTER COLUMN [" & fieldname & "] " & finalDatatype & ""
Next
Continue2428:
Next fld
Exit Function
FormatFieldsErr:
If Err.Number = 2428 Then Resume Continue2428
MsgBox Err.Description & " " & Err.Number
End Function
Even if the data is of interest, TableDef has an OpenRecordset method that returns the data in the table.
It might also be possible to use a snapshot-type recordset, which doesn't have an open connection to the database, and therefore shouldn't be affected by the lock. (I didn't test this.)
Note: I've only tested this with an .accdb; if this works as well with an .mdb that would be good to know.
I've inherited some Access VBA code and there are controls on a form (such as a listbox named lstOrderID, mentioned below) which have no RowSource property set (an empty string). I look in the code and find statements like this in various places:
Forms!frm_Customer.lstOrderID = rstCust!OrderID ' set from a record set
Forms!frm_Customer.lstOrderID.Requery
Me.lstOrderID = Me.lstOrderID.ItemData(0) ' set to first item in self
But nowhere in the code is lstOrderID.RowSource being set.
How can Requery be called on a listbox that has no RowSource?
How can a listbox be set to a single value (rstCust!OrderID) from a record set, unless this is a list of values (although the debugger shows an integer in lstOrderID.Value)?
Here is more code:
Dim rstCust As Recordset
Set db = CurrentDb
Set rstCust = db.OpenRecordset("SELECT * FROM Orders WHERE CustID=" & ID & _
"AND Datetaken =Date() " & _
"AND VendorID='" & Forms!frm_Customer.cboVendorID & "'")
Forms!frm_Customer.lstOrderID = rstCust!OrderID
rstCust.Close
db.Close
Another section:
Dim rstCust As Recordset
Dim blStatus As Boolean
Dim strSql As String
Set db = CurrentDb
strSql = "SELECT Orders.OrderID " & _
"FROM Orders " & _
"WHERE (((Orders.DateTaken)=#" & Date & "#) " & _
"AND ((Orders.VendorID)='" & Forms!frm_Customer.cboVendorID & "') " & _
"AND ((Orders.CustID)=" & ID & "));"
Set rstCust = db.OpenRecordset(strSql)
Forms!frm_Customer.lstOrderID = rstCust!OrderID
Forms!frm_Customer.lstOrderID.Requery
Forms!frm_Customer.lstOrderID = rstCust!OrderID
rstCust.Close
db.Close
Also this:
Me.lstOrderID.Requery
Me.lstOrderID = Me.lstOrderID.ItemData(0)
I have a database with linked tables- Staff, Courses and Training_Record. Each staff member has a numeric primary key, as does each course and each entry in the Training_Record table. The Staff_ID and Course_ID in the Training_Record reference records in Staff and Courses.
When a staff member or course is added, the Training_Record (fields: Staff_ID, Course_ID, Date_Taken, Notes) has staff,course records inserted- so adding staff member 1 would insert records (1,1,,,), (1,2,,,) etc, adding course 8 would insert records (1,8,,,), (2,8,,,) and so on. This works.
I then have a form to record training. The user selects the course, enters the date and selects staff members from a listbox. I have a save button which triggers VBA code. The date and course are pulled from the boxes and I loop round the listbox, concatenating selected staff members into a string. This all works and a message box displays, verifying that. Then, an update SQL query should be run, updating the Training_Record.
The problem I have is with the SQL update. I have an update query that will work in the SQL query editor, though it uses written in variables:
UPDATE Training_Record
SET Date_Taken = '12/12/12'
WHERE Staff_ID IN (1,2,3,4,5) AND Course_ID = 4
This updates the Training_Record to show that staff 1,2,3,4 and 5 took course 4 on 12/12/12. However, in VBA this will not work. This is my SQL query in VBA:
strSQL = "UPDATE Training_Record" _
& "SET Date_Taken = (" & strDate & ")" _
& "WHERE Staff_ID IN (" & strCriteria & ") AND Course_ID = (" & strCourse & ")"
DoCmd.RunSQL strSQL
The error that the code generates is "Run-time error '3144': Syntax error in UPDATE statement." and the debugger highlights the DoCmd.RunSQL statement following the query.The entire VBA code:
Private Sub SaveTraining_Click()
Dim db As DAO.Database
Dim VarItem As Variant
Dim strCriteria As String
Dim strDate As Variant
Dim strCourse As Variant
Dim strSQL As String
Set db = CurrentDb()
'Extract the course ID and the training date from the form
strCourse = Me!CourseID.Value
strDate = Me!TrainingDate.Value
'Dealing with empty boxes- zero length
If IsNull(strCourse) Then
MsgBox "Please select a course." _
, vbOKOnly, "No course selected"
End If
If IsNull(strDate) Then
MsgBox "Please enter a date." _
, vbOKOnly, "No date given"
End If
If StaffMembers.ItemsSelected.Count = 0 Then
MsgBox "Please select staff members." _
, vbOKOnly, "No staff members"
End If
If (Not IsNull(strCourse)) And (Not IsNull(strDate)) And (StaffMembers.ItemsSelected.Count > 0) Then
'Extract each selected member and concatenate into a string for sql query
For Each VarItem In Me!StaffMembers.ItemsSelected
strCriteria = strCriteria & "," & Me!StaffMembers.ItemData(VarItem)
Next VarItem
'Gets rid of extra comma on query string
strCriteria = Right(strCriteria, Len(strCriteria) - 1)
'Message box
MsgBox ("Staff: " & strCriteria & vbNewLine & "Date: " & strDate & vbNewLine & "Course: " & strCourse & vbNewLine & "No. Selected staff: " & StaffMembers.ItemsSelected.Count)
strSQL = "UPDATE Training_Record" _
& "SET Date_Taken = (" & strDate & ")" _
& "WHERE Staff_ID IN (" & strCriteria & ") AND Course_ID = (" & strCourse & ")"
DoCmd.RunSQL strSQL
End If
Set db = Nothing
End Sub
TL;DR I can't make a SQL UPDATE query run in VBA
I've got a feeling that it's an error in syntax somewhere, but I can't find where. Any ideas/advice would be much appreciated, thanks.
I think you are simply missing spaces at the end of the lines
You old query print out
UPDATE Training_RecordSET Date_Taken = ()WHERE Staff_ID IN () AND Course_ID = ()
as you can see there will be a name collision before keywords SET and WHERE
therefore change your strSQL to
strSQL = "UPDATE Training_Record " _
& "SET Date_Taken = (" & strDate & ") " _
& "WHERE Staff_ID IN (" & strCriteria & ") AND Course_ID = (" & strCourse & ")"
which prints out as (with no values provided)
UPDATE Training_Record SET Date_Taken = () WHERE Staff_ID IN () AND Course_ID = ()
which in terms of SQL syntax is correct
If I were you I would also check the data types of columns in your Training_Record table
Usually (and this applies to Type-mismatch error),
for dates you wrap the variable or value on both sides with #
example & "SET Date_Taken = (#" & strDate & "#) ...
for strings you use single quotes '
example WHERE Operator_Name = ('" & operName & "') ...
for numerical values you do not need to use anything but casting to provide the correct data type
My guess:
strSQL = "UPDATE Training_Record" _
& "SET Date_Taken = (#" & Format(strDate, "mm\/dd\/yyyy") & "#)" _
& "WHERE Staff_ID IN (" & strCriteria & ") AND Course_ID = (" & strCourse & ")"
If staff_ID is a string:
strSQL = "UPDATE Training_Record" _
& "SET Date_Taken = (#" & Format(strDate, "mm\/dd\/yyyy") & "#)" _
& "WHERE Staff_ID IN ('" & strCriteria & "') AND Course_ID = (" & strCourse & ")"
Can anyone help as I am struggling to finish the end result:
I got an unbound mainform, got an bound subform, got two tables Masterplant and PlantTransaction.
When I edit a record it shows on the mainform and when I save the record it must duplicate an existing record in the subform, which works, but the trick is that the Opening Hours in the new record must become my Closing Hours of the previous record, everything works it's just the Opening Hours does not show from the Closing hours previous record and the TransactionID is a number field that must auto increment with a different TransactionID number. Any help will be appreciated, thanks in advance!!!
Code below:
Private Sub cmdSave_Click()
Dim strSQL As String
Dim rst As DAO.Recordset
If IsNull(txtOpeningHRS) Then
Set rst = Me.RecordsetClone
If rst.RecordCount > 0 Then
If Me.NewRecord Then
rst.MoveLast
Else
rst.Bookmark = Me.Bookmark
rst.MovePrevious
End If
txtOpeningHRS = rst!CloseHrs
End If
End If
If IsNull(Me.TransactionID) Or Me.TransactionID = 0 Then
Me.TransactionID = Nz(DMax("TransactionID", "PlantTransaction") + 1, 1234)
End If
strSQL = "INSERT INTO PlantTransaction(TransactionID, [Plant Number], Opening_Hours,
[TransactionDate], [FuelConsumption], [Hour Meter Replaced], Comments, [Hours Worked]) & _
strSQL & "VALUES(" & Me.txtTranID & ",'" & Me.txtPlantNo & "','" & Me.txtOpeningHRS & "',#" &
Me.txtTransDate & "#,'" & Me.txtFuelConsFuelHr & "','" & Me.txtHrMtrRep & "','" & Me.txtComments
& "','" & Me.txtHrsWorked & "');"
CurrentDb.Execute strSQL
Me.PlantTransactionQuery.Form.Requery
cmdNew_Click
End Sub
Set TransactionID to be an AutoNumber data type, this will automatically increment it.
You can also try replacing:
CurrentDb.Execute strSQL
Me.PlantTransactionQuery.Form.Requery
with:
CurrentDb.Execute strSQL
Me!PlantTransactionQuery.Form.RowSource = "Select * from PlantTransaction"
Me.PlantTransactionQuery.Form.Refresh