Private Sub Form_Close()
Dim sSQL, stringSQL As String
Dim rst As DAO.Recordset
sSQL = "SELECT BarCode, [Goods Name] FROM tblInventory WHERE BarCode='" & Me.ID & "'"
Set rst = CurrentDb.OpenRecordset(sSQL)
If rst.EOF Then
stringSQL = "INSERT INTO tblInventory(BarCode,[Goods Name],Unit,[Unit Price],[Initial Stock],[Current Stock],[Exit Item]) values('" & Me.ID & "','" & Me.GoodsName & "','" & Me.Unit & "'," & Replace(Format(Me.Price, "0.00"), ",", ".") & "," & Me.Amount & "," & Me.Amount & ",0)"
DoCmd.SetWarnings False
DoCmd.RunSQL [stringSQL]
DoCmd.SetWarnings True
Else
stringSQL = "UPDATE tblInventory SET [Current Stock]=[Current Stock]+" & Me.Amount & " WHERE BarCode='" & Me.ID & "'"
DoCmd.SetWarnings False
DoCmd.RunSQL (stringSQL)
DoCmd.SetWarnings True
End If
rst.Close
End Sub
Firstly, note that this:
Dim sSQL, stringSQL As String
Results in sSQL being defined as a Variant, not a String; which, although will not cause your code to fail (since a Variant can hold data of any type), it will be memory inefficient.
Instead, you should use:
Dim sSQL As String, stringSQL As String
Or, perhaps more readable:
Dim sSQL As String
Dim stringSQL As String
Secondly, when invoking a function independently of any other expression, you should not surround the arguments with parentheses of any type.
In your code, on line 11 you have:
DoCmd.RunSQL [stringSQL]
And on line 16 you have:
DoCmd.RunSQL (stringSQL)
Both of these should be changed to:
DoCmd.RunSQL stringSQL
Or, just supply the SQL string directly, e.g.:
DoCmd.SetWarnings False
DoCmd.RunSQL "UPDATE tblInventory SET [Current Stock]=[Current Stock]+" & Me.Amount & " WHERE BarCode='" & Me.ID & "'"
DoCmd.SetWarnings True
Also, since you are only using the recordset to test whether a record exists, you could simplify this to a DLookup call, e.g.:
DLookup("BarCode","tblInventory","BarCode=Forms![YourForm]!ID")
And test whether or not this returns Null using IsNull:
If IsNull(DLookup("BarCode", "tblInventory", "BarCode=Forms![YourForm]!ID")) Then
...
Else
...
End If
Finally, it is much better practice to use a parameterised query in place of concatenating values within a SQL statement.
Using parameters offers two key advantages:
Protects against SQL injection.
Automatically handles SQL data types.
For example, consider the following code:
Private Sub Form_Close()
If IsNull(DLookup("BarCode", "tblInventory", "BarCode=Forms![YourForm]!ID")) Then
With CurrentDb.CreateQueryDef _
( _
"", _
"insert into tblInventory(BarCode,[Goods Name],Unit,[Unit Price],[Initial Stock],[Current Stock],[Exit Item]) " & _
"values(#id, #goodsname, #unit, #unitprice, #initstock, #stock, 0)" _
)
.Parameters(0) = Me.ID
.Parameters(1) = Me.GoodsName
.Parameters(2) = Me.Unit
.Parameters(3) = Replace(Format(Me.Price, "0.00"), ",", ".")
.Parameters(4) = Me.Amount
.Parameters(5) = Me.Amount
.Execute
End With
Else
With CurrentDb.CreateQueryDef _
( _
"", _
"update tblInventory set [Current Stock]=[Current Stock]+#amount where BarCode=#id" _
)
.Parameters(0) = Me.Amount
.Parameters(1) = Me.ID
.Execute
End With
End If
End Sub
Try manually to run the SQL with some values.
You probably need to use either parameters or to concatenate the variables properly, for example using my function CSql.
Related
I want to read a linked table and update the local one.
Importing new entries works.
When I try to update an existing one it throws an exception
runtime error 3073
Sub UpdateBLPNR()
With CurrentDb
Set tdf = .CreateTableDef("ext_BEL_PLZ")
tdf.Connect = "ODBC;DSN=EasyProd PPS;DataDirectory=PATH;SERVER=NotTheServer;Compression= ;DefaultType=FoxPro;Rows=False;Language=OEM;AdvantageLocking=ON;Locking=Record;MemoBlockSize=64;MaxTableCloseCache=5;ServerTypes=6;TrimTrailingSpaces=False;EncryptionType=RC4;FIPS=False"
tdf.SourceTableName = "BEL_PLZ"
.TableDefs.Append tdf
.TableDefs.Refresh
End With
Dim SQLUpdate As String
Dim SQLInsert As String
SQLUpdate = "UPDATE BEL_PLZ " & _
"INNER JOIN ext_BEL_PLZ " & _
"ON(BEL_PLZ.NR = ext_BEL_PLZ.NR) " & _
"SET BEL_PLZ.BEZ = ext_BEL_PLZ.BEZ "
SQLInsert = "INSERT INTO BEL_PLZ (NR,BEZ) " & _
"SELECT NR,BEZ FROM ext_BEL_PLZ t " & _
"WHERE NOT EXISTS(SELECT 1 FROM BEL_PLZ s " & _
"WHERE t.NR = s.NR) "
DoCmd.SetWarnings False
DoCmd.RunSQL (SQLUpdate)
DoCmd.RunSQL (SQLInsert)
DoCmd.SetWarnings True
DoCmd.DeleteObject acTable, "ext_BEL_PLZ"
End Sub
Already figured out that Access might have some problems using a linked table to update a local one but I can't figure out a workaround.
(SQLInsert is working, SQLUpdate is not)
This is my final and working solution (thanks to ComputerVersteher)
Sub UpdateBLPNR()
'Define Variables
Dim SQLUpdate As String
Dim SQLInsert As String
Dim qdf As DAO.QueryDef
'Create temporary table and update entries
With CurrentDb
Set tdf = .CreateTableDef("ext_BEL_PLZ")
tdf.Connect = "ODBC;DSN=EasyProd PPS;DataDirectory=PATH;SERVER=NotTheServer;Compression= ;DefaultType=FoxPro;Rows=False;Language=OEM;AdvantageLocking=ON;Locking=Record;MemoBlockSize=64;MaxTableCloseCache=5;ServerTypes=6;TrimTrailingSpaces=False;EncryptionType=RC4;FIPS=False"
tdf.SourceTableName = "BEL_PLZ"
.TableDefs.Append tdf
.TableDefs.Refresh
With .OpenRecordset("SELECT ext_BEL_PLZ.NR, ext_BEL_PLZ.BEZ " & _
"FROM ext_BEL_PLZ INNER JOIN BEL_PLZ ON BEL_PLZ.NR = ext_BEL_PLZ.NR", dbOpenSnapshot)
Set qdf = .Parent.CreateQueryDef("")
Do Until .EOF
qdf.sql = "PARAMETERS paraBEZ Text ( 255 ), paraNr Text ( 255 );" & _
"Update BEL_PLZ Set BEL_PLZ.BEZ = [paraBEZ] " & _
"Where BEL_PLZ.NR = [paraNr]"
qdf.Parameters("paraBez") = .Fields("BEZ").Value
qdf.Parameters("paraNr") = .Fields("NR").Value
qdf.Execute dbFailOnError
.MoveNext
Loop
End With
End With
'Run SQL Query (Insert)
SQLInsert = "INSERT INTO BEL_PLZ (NR,BEZ) " & _
"SELECT NR,BEZ FROM ext_BEL_PLZ t " & _
"WHERE NOT EXISTS(SELECT 1 FROM BEL_PLZ s " & _
"WHERE t.NR = s.NR) "
DoCmd.SetWarnings False
DoCmd.RunSQL (SQLInsert)
DoCmd.SetWarnings True
'Drop temporary table
DoCmd.DeleteObject acTable, "ext_BEL_PLZ"
End Sub
Create a recordset from read only table to get values.
Dim qdf As DAO.QueryDef
With CurrentDb
With .OpenRecordset("SELECT ext_BEL_PLZ.NR, ext_BEL_PLZ.BEZ " & _
"FROM ext_BEL_PLZ INNER JOIN BEL_PLZ ON BEL_PLZ.NR = ext_BEL_PLZ.NR", dbOpenSnapshot)
Set qdf = .Parent.CreateQueryDef(vbNullString)
qdf.SQL = "PARAMETERS paraBEZ Text ( 255 ), paraNr Long;" & _
"Update BEL_PLZ Set BEL_PLZ.BEZ = [paraBEZ] " & _
"Where BEL_PLZ.NR = [paraNr]"
Do Until .EOF
qdf.Parameters("paraBez") = .Fields("BEZ").Value
qdf.Parameters("paraNr") = .Fields("NR").Value
qdf.Execute dbFailOnError
.MoveNext
Loop
End With
End With
You can't do that.
Linked tables on other data sources than Access itself require a primary key to support updates.
When linking through the GUI, Access does allow you to specify an alternate key that uniquely identifies rows if there is no primary key, but if there is one that should be your primary key.
I have a Combo Box (cbo1) that list available Items. When I select an item in cbo1, I would like it change a checkbox to True (or Yes).
cbo1 gets data from tblLOG where Box (checkbox) is NO Query
I've tried using
UPDATE tblLOG
Set Box = True
WHERE Serial = cboSerial
Actual Code.
Private Sub cbo1_Change()
Dim strSQL As String
Dim i As Integer
Dim Msg As String
Dim Assm As String
Assm = cbo1.Value
'Exit this sub if the combo box is cleared
Msg = "Make Update" & vbCr & vbCr
i = MsgBox(Msg, vbQuestion + vbYesNo, "UPDATE VALUE?")
If i = vbYes Then
strSQL = "UPDATE tblLOG " _
& "SET Box= True " _
& "WHERE Serial = Assm;"
CurrentDb.Execute strSQL, dbFailOnError
Response = acDataErrAdded
End If
End Sub
My Results are
Run-time error '3061': Too few parameters. Expected 1.
The reason for your error is because you are not evaluating your VBA variable Assm, but rather concatenating the string "Assm" to your SQL query.
strSQL = "UPDATE tblLOG " _
& "SET Box= True " _
& "WHERE Serial = Assm;"
If you were to Debug.Print the variable strSQL to the console, you would see the string:
"UPDATE tblLOG SET Box= True WHERE Serial = Assm;"
However, since Assm is not a string in the SQL query (i.e. it is not surrounded by single or double quotes), it is interpreted as a parameter whose value hasn't been supplied when the SQL query is subsequently executed.
To solve this, you could concatenate the evaluated value of the Assm variable, e.g.:
strSQL = "UPDATE tblLOG " _
& "SET Box= True " _
& "WHERE Serial = '" & Assm & "';"
This assumes that Serial is a text field - if this is not the case, remove the single quotes from the above.
Your entire code could be condensed somewhat to:
Private Sub cbo1_Change()
If MsgBox("Make Update", vbQuestion + vbYesNo, "UPDATE VALUE?") = vbYes Then
CurrentDb.Execute "update tbllog set box = true where serial = '" & cbo1 & "';", dbFailOnError
Response = acDataErrAdded
End If
End Sub
Though, this is still open to SQL injection, and so a better practice is to parameterise the query, e.g.:
With CurrentDb.CreateQueryDef("", "update tbllog t set t.box = true where t.serial = myserial;")
.Parameters!myserial = cbo1
.Execute
End With
I try to create a query to Count items and having three WHERE conditions but there is no result when I run the code, not even an error one. What am I doing wrong?
Private Sub Command5_Click()
Dim db As DAO.Database
Set db = CurrentDb
Dim qdf As DAO.QueryDef
Dim qryMajorDesignReview As String
Dim tblMainReportLOI As String
qryMajorDesignReview = "SELECT Count(tblLOI.loiActivities) As MajorDesignReview, INTO tblMainReportLOI FROM tblLOI " & _
"WHERE tblLOI.loiActivities='PSG Major design review for new or existing facilities' " & _
"AND Format([loiDate], ""yyyy"")=[Forms]![frmMonthlyDivisionReports]![txtYear] " & _
"AND Format([loiDate], ""mmmm"")=[Forms]![frmMonthlyDivisionReports]![txtMonth]; "
On Error Resume Next
DoCmd.DeleteObject acTable, "tblMainReportLOI"
Err.Clear
CurrentDb.Execute qryMajorDesignReview
If Err.Number <> 0 Then
strError = Err.Description
End If
On Error GoTo 0
End Sub
Remove the comma before INTO. Also, concatenate variables. References to form controls are variables. Can use apostrophe instead of doubled quotes in Format(). Could use Year() function instead of Format.
qryMajorDesignReview = "SELECT Count(tblLOI.loiActivities) As MajorDesignReview INTO tblMainReportLOI FROM tblLOI " & _
"WHERE tblLOI.loiActivities='PSG Major design review for new or existing facilities' " & _
"AND Year([loiDate])=" & [Forms]![frmMonthlyDivisionReports]![txtYear] & _
" AND Format([loiDate], 'mmmm')='" & [Forms]![frmMonthlyDivisionReports]![txtMonth] & "'"
rs2.FindFirst "[aniin] ='" & strTemp & "'"
aniin being an alias from the SQL within the function.
also tried ...
rs2.FindFirst (niin = newdata)
is my attempt to isolate the field name niin from the record value in the form from the one in the strSQL2. All my attempts have failed. I am trying to make sure that what the user typed in does match the list from the SQL string.
Private Function IsPartOfAEL(newdata) As Boolean
On Error GoTo ErrTrap
Dim db2 As DAO.Database
Dim rs2 As DAO.Recordset
Dim strTemp As String
strSQL2 = "SELECT tbl_ael_parts.master_ael_id, tbl_master_niin.niin as aniin " & vbCrLf & _
"FROM tbl_master_niin INNER JOIN tbl_ael_parts ON tbl_master_niin.master_niin_id = tbl_ael_parts.master_niin_id " & vbCrLf & _
"WHERE (((tbl_ael_parts.master_ael_id)= " & Forms!frm_qry_niin_local!master_ael_id & "));"
Set db2 = CurrentDb
Set rs2 = db2.OpenRecordset(strSQL2)
strTemp = newdata
If rs2.RecordCount <> 0 Then
rs2.FindFirst "[aniin] ='" & strTemp & "'"
If rs2.NoMatch Then
IsPartOfAEL = False
Else
IsPartOfAEL = True
End If
Else
MsgBox "Query Returned Zero Records", vbCritical
Exit Function
End If
rs.Close
Set rs2 = Nothing
Set db2 = Nothing
ExitHere:
Exit Function
ErrTrap:
MsgBox Err.description
Resume ExitHere
End Function
First: You should never include a constant like vbCrLf when building a query string. The query parser doesn't care if there's a linefeed, and in fact this can sometimes cause issues.
Your code seems to do nothing more that verify whether the value in newdata exists in the tbl_ael_parts and is associated with the value master_ael_id value currently showing on frm_qry_niin_local. If so, then just use DCount, or use this for your query:
strSQL2 = "SELECT tbl_ael_parts.master_ael_id INNER JOIN tbl_ael_parts ON
tbl_master_niin.master_niin_id = tbl_ael_parts.master_niin_id WHERE (((tbl_ael_parts.master_ael_id)=
" & Forms!frm_qry_niin_local!master_ael_id & ") AND niin=" & newdata & ");"
Dim rst As DAO.Recordset
Set rst = currentdb.OPenrecordset(strsql2)
If (rst.EOF and rst.BOF) Then
' no records returned
Else
' records found
End If
If niin is a Text field:
strSQL2 = "SELECT tbl_ael_parts.master_ael_id INNER JOIN tbl_ael_parts ON
tbl_master_niin.master_niin_id = tbl_ael_parts.master_niin_id WHERE (((tbl_ael_parts.master_ael_id)=
" & Forms!frm_qry_niin_local!master_ael_id & ") AND (niin='" & newdata & "'));"
If both niin and master_ael_id are Text fields:
strSQL2 = "SELECT tbl_ael_parts.master_ael_id INNER JOIN tbl_ael_parts ON
tbl_master_niin.master_niin_id = tbl_ael_parts.master_niin_id WHERE (((tbl_ael_parts.master_ael_id)=
'" & Forms!frm_qry_niin_local!master_ael_id & "') AND (niin='" & newdata & "'));"
Good day guys, I have a question. When I try to use this piece of code in my program which will add a supplier to the database, I encounter data type mismatch error. As far as I know, the status of the supplier creates the error.
How would I store the values of the radio buttons named radActive and radInactive in the database? Should I use Boolean or a String? I am using Microsoft Access as my database and the field of Status is set to Yes/No.
Here's the code.
Public Sub SupplierInsertData()
Dim conn As OleDb.OleDbConnection
Dim cmd As OleDb.OleDbCommand
Dim SupplierType As String
Dim Status As Boolean
'Check for supplier type
If frmDatabaseSupplier.radLocal.Checked = True Then
SupplierType = "Local"
ElseIf frmDatabaseSupplier.radForeign.Checked = True Then
SupplierType = "Foreign"
End If
'Check for supplier status
If frmDatabaseSupplier.radActive.Checked = True Then
Status = True
ElseIf frmDatabaseSupplier.radInactive.Checked = True Then
Status = False
End If
'For inserting of data in the database.
Dim cmdString As String = "INSERT INTO Supplier(SupplierLastName, SupplierFirstName, SupplierMiddleInitial, " & _
"SupplierCompany, SupplierType, SupplierStreetAddress, SupplierCity, SupplierContactNumber, SupplierEmail, " & _
"Status)" & _
"VALUES('" & frmDatabaseSupplier.txtSupplierLastName.Text & "','" & frmDatabaseSupplier.txtSupplierFirstName.Text & "','" & frmDatabaseSupplier.txtSupplierMiddleInitial.Text & "','" _
& frmDatabaseSupplier.txtSupplierCompany.Text & "','" & SupplierType & "', '" & frmDatabaseSupplier.txtSupplierStreetAddress.Text & "','" & frmDatabaseSupplier.txtSupplierCity.Text & "','" _
& frmDatabaseSupplier.txtSupplierContactNumber.Text & "','" & frmDatabaseSupplier.txtSupplierEmail.Text & "','" & Status & "')"
conn = New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\ProjectAnalysisSystem.accdb")
cmd = New OleDb.OleDbCommand(cmdString, conn)
conn.Open()
cmd.ExecuteNonQuery()
conn.Close()
End Sub
Thank you!
Try to change the last part of your code.
You should use parameters to pass the values of your textbox or vars to the database engine.
And don't forget to encapsulate the disposable objects like OleDbConnection in a using statement.
Dim cmdString As String = "INSERT INTO Supplier(SupplierLastName, SupplierFirstName, SupplierMiddleInitial, " & _
"SupplierCompany, SupplierType, SupplierStreetAddress, SupplierCity, SupplierContactNumber, SupplierEmail, " & _
"Status)" & _
"VALUES(#supplierName, #supplierFirst, #supplierMiddle, #supplierCo, #supplierType, #supplierStreet, #supplierCity, " & _
"#supplierContact, #supplierMail, #status)"
Using conn As New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\ProjectAnalysisSystem.accdb")
Dim cmd As OleDbCommand = New OleDb.OleDbCommand(cmdString, conn))
cmd.Parameters.AddWithValue("#supplierName", frmDatabaseSupplier.txtSupplierLastName.Text)
cmd.Parameters.AddWithValue("#supplierFirst", frmDatabaseSupplier.txtSupplierFirstName.Text)
cmd.Parameters.AddWithValue("#supplierMiddle", frmDatabaseSupplier.txtSupplierMiddleInitial.Text)
cmd.Parameters.AddWithValue("#supplierCo", frmDatabaseSupplier.txtSupplierCompany.Text )
cmd.Parameters.AddWithValue("#supplierType", SupplierType)
cmd.Parameters.AddWithValue("#supplierStreet", frmDatabaseSupplier.txtSupplierStreetAddress.Text)
cmd.Parameters.AddWithValue("#supplierCity", frmDatabaseSupplier.txtSupplierCity.Text)
cmd.Parameters.AddWithValue("#supplierContact", frmDatabaseSupplier.txtSupplierContactNumber.Text)
cmd.Parameters.AddWithValue("#supplierMail", frmDatabaseSupplier.txtSupplierEmail.Text)
cmd.Parameters.AddWithValue("#status", Status) '<- Here the status var is correctly identified as a boolean, not as a string
conn.Open()
cmd.ExecuteNonQuery()
End Using
You have a data type mismatch error because your INSERT statement attempts to store a string value for the Status field whose data type is Yes/No.
This isn't really a VB.Net problem. You would get the very same error from Access' db engine if you were attempting the same thing from VBA. This is the output from the VBA procedure below.
INSERT INTO Supplier (Status)
VALUES('True')
Error -2147217913 (Data type mismatch in criteria expression.)
The procedure ...
Public Sub Ju_chan()
Dim cmdString As String
Dim Status As Boolean
Dim strMsg As String
On Error GoTo ErrorHandler
Status = True
cmdString = "INSERT INTO Supplier (Status)" & vbCrLf & _
"VALUES('" & Status & "')"
Debug.Print cmdString
CurrentProject.Connection.Execute cmdString
ExitHere:
On Error GoTo 0
Exit Sub
ErrorHandler:
strMsg = "Error " & Err.Number & " (" & Err.Description _
& ")"
Debug.Print strMsg
GoTo ExitHere
End Sub
Please understand this is not intended to steer you away from using parameters. I only wanted to clarify why you're getting that error.