For reasons I cannot see I get the following error message:
Compile error: Method or data member not found
when I use the following:
Private Sub cmd_Add_Click()
Dim strSQL As String
strSQL = " INSERT INTO BERTHAGE " _
& "(BOAT, LOCATION, BERTH_WEEK, BERTH_YEAR, BERTHED) VALUES " _
& Me.Add_Boat & "','" _
& Me.LOCATION & "','" _
& Me.txt_week & "','" _
& Me.txt_year & "','" _
& Me.In_Port & "');"
cmd_Clear_Click
End Sub
Once I click OK and use the refresh button the entry is put into the database, but each time I do an entry I have to go to the same process.
I would like to figure out what method or data is missing?
I should add that there is an outnumber primary key field on this table (Berth_ID), and each time I use the cmd_Add button a new ID number is created for the new record. This includes creating a new ID number for the new record that triggers the error.
Here is all the VBA associated with this form
Private Sub Form_Load()
DoCmd.RunCommand acCmdRecordsGoToLast
End Sub
Private Sub LOCATION_Change()
Me.txt_Cur_Flo = Me.LOCATION.Column(1)
Me.txt_Cur_Doc = Me.LOCATION.Column(2)
Me.txt_Cur_Ori = Me.LOCATION.Column(3)
End Sub
Private Sub cmd_Add_Click()
Dim strSQL As String
strSQL = " INSERT INTO BERTHAGE " _
& "(BOAT, LOCATION, BERTH_WEEK, BERTH_YEAR, BERTHED) VALUES " _
& Me.Add_Boat & "','" _
& Me.LOCATION & "','" _
& Me.txt_week & "','" _
& Me.txt_year & "','" _
& Me.In_Port & "');"
cmd_Clear_Click
End Sub
Private Sub cmd_Clear_Click()
Me.Add_Boat = ""
Me.LOCATION = ""
Me.txt_Cur_Flo = ""
Me.txt_Cur_Doc = ""
Me.txt_Cur_Ori = ""
Me.Add_Boat.SetFocus
End Sub
Private Sub cmd_Close_Click()
DoCmd.Close
End Sub
Consider the best practice of parameterization and not string concatenation of SQL mixed with VBA variables. Due to missing quotes, the compiler attempts to reference a column name and not its literal value. Instead, consider parameterization with defined types which is supported with Access SQL using QueryDefs. Notice below, SQL and VBA are complete separate.
SQL (save as stored query)
PARAMETERS prmBoat TEXT, prmLoc INT, prmBerthed INT;
INSERT INTO BERTHAGE (BOAT, LOCATION, BERTHED)
VALUES(prmBoat, prmLoc, prmBerthed)
VBA
Dim db As Database
Dim qdef As QueryDef
Dim strSQL As String
Set db = CurrentDb
Set qdef = db.QueryDefs("mySavedParamQuery")
' BIND PARAM VALUES
qdef!prmBoat = Me.Add_Boat
qdef!prmLoc = Me.LOCATION
qdef!prmBerthed = Me.In_Port
' EXECUTE ACTION QUERY
qdef.Execute
Set qdef = Nothing
Set db = Nothing
Even better, save your query with form controls intact and simply call OpenQuery:
SQL (save as stored query)
INSERT INTO BERTHAGE(BOAT, LOCATION, BERTHED)
VALUES(Forms!myForm!Add_Boat, Forms!myForm!LOCATION, Forms!myForm!In_Port)
VBA
Private Sub cmd_Add_Click()
Dim strSQL As String
DoCmd.SetWarnings False ' TURN OFF APPEND PROMPTS
DoCmd.OpenQuery "mySavedActionQuery"
DoCmd.SetWarnings True ' RESET WARNINGS
Call cmd_Clear_Click
End Sub
Missing opening parenthesis after VALUES. Also missing apostrophe in front of Me.Add_Boat. These special characters must always be in pairs, an even number by counting.
If Berth_Week and Berth_Year are number fields (and should be), don't use apostrophe delimiters.
If In_Port is a Yes/No field, don't use apostrophe delimiters.
The issue appears to be that I was doubling up the inputs into the 'week' and 'year' field. this was happening (I believe) because those text box fields were already accessing the week and year information directly from the default value on the BERTHAGE table. Essentially I went through each input and would run it individually waiting for the error to occur. Once it occurred I took it out of the INSERT INFO statement. With the removal of week and year, everything is working. That was a painful exercise, and still not complete, but I am back to a function form/DB so I'll take the small victories when they occur.
Private Sub cmd_Add_Click()
Dim strSQL As String
CurrentDb.Execute " INSERT INTO BERTHAGE " & "(BOAT, LOCATION, BERTHED) VALUES ('" & Me.Add_Boat & "'," _
& Me.New_Loc & "," _
& Me.In_Port & ");"
cmd_Clear_Click
DoCmd.Requery
End Sub`
I have the following code and it works just fine:
Dim result As Integer
result = 20
DoCmd.RunSQL "INSERT INTO ReportingTable (BUDGETPER1) VALUES (" & result & ");"
I don't really want to hardcode the 20 but rather populate using a SELECT statement:
select PD01 from SetVariables WHERE VariableType = 'HEADCOUNT' and BusinessUnit = 511
(the result of this SELECT statement is 20, I have tested it and it is fine)
What would be the easiest way of achieving this? I understand that in this specific example I would be able to achieve the desired result using Dlookup but I need to get my head around the concept of defining a variable with a select statement.
You can use a SELECT query to determine the data to be inserted into your table:
Sub sInsertData()
Dim db As DAO.Database
Dim strSQL As String
Set db = DBEngine(0)(0)
strSQL = "INSERT INTO ReportingTable (BUDGETPER1) " _
& " SELECT PD01 FROM SetVariables " _
& " WHERE VariableType='headcount' AND BusinessUnit=511;"
db.Execute strSQL
Set db = Nothing
End Sub
You could also then replace "headcount" and "511" with other values as required.
Regards,
Is their a way to use a declared VBA variable in a SELECT Sql statement as follows (I have a table called myTable and i want to set the referenced field by passing the declared string myVar) :
e.g passVar("English")
NB: Am using Microsoft Access
Private Function passVar(myVar as string)
Dim db As Database
Dim qdf As DAO.QueryDef
Dim stmnt As String
Set db = CurrentDb()
Set qdf = db.QueryDefs("SelectSubjectQuery")
stmnt = "SELECT [myTable].[myVar] = " &Chr$(34) & myVar & Chr$(34) & _
//other SQL statements go here
qdf.SQL = stmnt
End Function
Each time i run the query a dialog box appears asking for the value of mytable.myvar instead of passing myvar i.e Eglish as the referenced field on myTable.
Yes, build the SQL statement as a string like this:
stmnt = "SELECT " & [myTable] & "." & [myVar] & " = " &Chr$(34) & myVar & Chr$(34) & _
VBA should then fill in the names for MyTable and MyVar when the code is run and the string is built.
stmnt = "SELECT [myTable]." & myVar & _
Got it to working by writing as above (no need for the equals sign as the string is passed through the function). Thanks for the insight #rcfmonarch
I keep getting a run time error '2465' when running a query via VBA in Access.
Error: Microsoft Access can't find the field '|1' referred to in your expression
I can't seem to find where this issue is occuring. Below is the VBA code that I'm currently using to requery a form.
Dim Test As String
Test = "*" & Combo161.Value
Dim strSQL As String
Dim strWhere As String
strWhere = (Chr(34) + Test + (Chr(34)))
'MsgBox (strWhere)
strSQL = "SELECT * FROM Test_Query WHERE TestID " & strWhere
'MsgBox (strSQL)
[Form_Test (subform)].RecordSource = strSQL
[Form_Test (subform)].Requery
The TestID had a field formatting of text, rather than a number. Does this matter at all?
I have just fixed this error. I was referencing the subform's source object, rather than its name given in the form properties.
I had the same error. What I missing was the double quotes around a string. This error is a bit misleading. Check the syntax etc and you will find the issue was related to comma or double quotes etc.
Try:
Dim Test As String
Test = "*" & Combo161.Value
Dim strSQL As String
Dim strWhere As String
strWhere = (Chr(34) & Test & (Chr(34)))
'MsgBox (strWhere)
strSQL = "SELECT * FROM Test_Query WHERE TestID Like " & strWhere
'To test
'Debug.print strSQL
If this is a subform, then:
Me.[Form_Test (subform)].Form.RecordSource = strSQL
''Not needed when changing record source
''Me.[Form_Test (subform)].Form.Requery
You did not have an equals sign / Like and the concatenator in VBA is &, not +, using + can lead to problems with nulls, but in this case, I reckon the problen is the missing Like, that is
TestID Like "*something"
You can control the contents of a subform with a combo and a link field:
Occasionally, I have had to build a SQL string in VBA and execute it with Docmd.RunSql(). I have always built these strings by concatenating variables into the string, e.g:
Dim mysqlstring as String
mysqlstring = "INSERT INTO MyTable (Field1, Field2, Field3 ...) VALUES ("
mysqlstring = mysqlstring + Me.TextMyField1 + ", " 'parameter comments
mysqlstring = mysqlstring + Me.TextMyField2 + ", "
mysqlstring = mysqlstring + Me.TextMyField3 + ", "
...
mysqlstring = mysqlstring + ");"
Docmd.RunSql mysqlstring
VBA doesn't seem to have a unary concatenation operator (like +=) and while this doesn't look ideal, at least I can comment each of my parameters and change them independently. It makes it easier to read and to change than one monster concatenated string. But it still seems like a terrible way to build SQL strings. I have one with about 50 parameters at work, so 50 lines of mysqlstring = mysqlstring +.... Not cute.
Incidentally, that rules out the use of line-continuations to format the string, as there is a limit on the number of line-continuations you can use on a single string (hint: less than 50). Also, VBA doesn't let you put a comment after the line-continuation, grr!
Up until recently, I thought this was the only way to build these strings. But recently I have seen a different pattern, injecting the parameters in the string like this question (VB.NET) that I posted an answer on, and wondered if there was an equivalent of Parameters.AddWithValue() for VBA, or if that would even be any better than the string concatenation approach. So I figured that this deserves its own question. Maybe there's something I'm missing here.
Can some of the Access experts please clarify what are the best practices for building SQL strings in Access/VBA.
I have a timesheet app with a reasonably complex unbound labour transaction entry form. There is a lot of data validation, rate calculation and other code. I decided to use the following to create my SQL Insert/Update fields.
The variables strSQLInsert, strSQLValues, strSQLUpdate are form level strings.
Many lines of the following:
Call CreateSQLString("[transJobCategoryBillingTypesID]", lngJobCategoryBillingTypesID)
followed by:
If lngTransID = 0 Then
strSQL = "INSERT into Transactions (" & Mid(strSQLInsert, 3) & ") VALUES (" & Mid(strSQLValues, 3) & ")"
Else
strSQL = "UPDATE Transactions SET " & Mid(strSQLUpdate, 3) & " WHERE transID=" & lngTransID & ";"
End If
conn.Open
conn.Execute strSQL, lngRecordsAffected, adCmdText
Note that the Mid lines remove the leading ", ". lngTrans is the value of the autonumber primamy kay.
Sub CreateSQLString(strFieldName As String, varFieldValue As Variant, Optional blnZeroAsNull As Boolean)
' Call CreateSQLString("[<fieldName>]", <fieldValue>)
Dim strFieldValue As String, OutputValue As Variant
On Error GoTo tagError
' if 0 (zero) is supposed to be null
If Not IsMissing(blnZeroAsNull) And blnZeroAsNull = True And varFieldValue = 0 Then
OutputValue = "Null"
' if field is null, zero length or ''
ElseIf IsNull(varFieldValue) Or Len(varFieldValue) = 0 Or varFieldValue = "''" Then
OutputValue = "Null"
Else
OutputValue = varFieldValue
End If
' Note that both Insert and update strings are updated as we may need the insert logic for inserting
' missing auto generated transactions when updating the main transaction
' This is an insert
strSQLInsert = strSQLInsert & ", " & strFieldName
strSQLValues = strSQLValues & ", " & OutputValue
' This is an update
strSQLUpdate = strSQLUpdate & ", " & strFieldName & " = " & OutputValue
On Error GoTo 0
Exit Sub
tagError:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure CreateSQLString of VBA Document Form_LabourEntry"
Exit Sub
End Sub
I see that the other posters are all using the Execute method. The problem with DoCmd.RunSQL is that it can ignore errors. Either of the following will display any error messages received by the query. If using DAO, use Currentdb.Execute strSQL,dbfailonerror.. For ADO use CurrentProject.Connection.Execute strCommand, lngRecordsAffected, adCmdText You can then remove the docmd.setwarnings lines.
If you're going to use docmd.setwarnings make very sure you put the True statement in any error handling code as well. Otherwise weird things may happen later on especially while you are working on the app. For example you will no longer get the "Do you wish to save your changes" message if you close an object. This may mean that unwanted changes, deletions or additions will be saved to your MDB.
Also performance can be significantly different between the two methods. One posting stated currentdb.execute took two seconds while docmd.runsql took eight seconds. As always YMMV.
Adding to what #astander has said, you could create a querydef (with parameters) and save it as part of the database.
e.g.
Parameters dtBegin DateTime, dtEnd DateTime;
INSERT into myTable (datebegin, dateend) values (dtBegin, dtEnd)
Assume, you saved it with a name myTableInsert, you could write the code as below
dim qd as QueryDef
set qd = CurrentDB.QueryDefs("myTableInsert")
qd.Parameters("dtBegin").Value = myTextFieldHavingBeginDate
qd.Parameters("dtEnd").Value = myTextFieldHavingEndDate
qd.Execute
Note: I have not tested this piece of code. But, I am guessing this should be it.
Hope this gives you enough info to get started.
Private Sub Command0_Click()
Dim rec As Recordset2
Dim sql As String
Dim queryD As QueryDef
'create a temp query def.
Set queryD = CurrentDb.CreateQueryDef("", "SELECT * FROM [Table] WHERE Val = #Val")
'set param vals
queryD.Parameters("#Val").Value = "T"
'execute query def
Set rec = queryD.OpenRecordset
End Sub
As others have said, it's probably better to utilize parameters in the first place. However, ...
I, too, have missed a concatenation operator, having become accustomed to .= in PHP. In a few cases, I've written a function to do it, though not specific to concatenating SQL strings. Here's the code for one I use for creating a query string for an HTTP GET:
Public Sub AppendQueryString(strInput As String, _
ByVal strAppend As String, Optional ByVal strOperator As String = "&")
strAppend = StringReplace(strAppend, "&", "&")
strInput = strInput & strOperator & strAppend
End Sub
And an example of where I've called it:
AppendQueryString strOutput, "InventoryID=" & frm!InventoryID, vbNullstring
AppendQueryString strOutput, "Author=" & URLEncode(frm!Author)
...and so forth.
Now, for constructing SQL WHERE clauses, you might consider something like that as a wrapper around Application.BuildCriteria:
Public Sub ConcatenateWhere(ByRef strWhere As String, _
strField As String, intDataType As Integer, ByVal varValue As Variant)
If Len(strWhere) > 0 Then
strWhere = strWhere & " AND "
End If
strWhere = strWhere & Application.BuildCriteria(strField, _
intDataType, varValue)
End Sub
You would then call that as:
Dim strWhere As String
ConcatenateWhere strWhere,"tblInventory.InventoryID", dbLong, 10036
ConcatenateWhere strWhere,"tblInventory.OtherAuthors", dbText, "*Einstein*"
Debug.Print strWhere
strSQL = "SELECT tblInventory.* FROM tblInventory"
strSQL = strSQL & " WHERE " & strWhere
...and the Debug.Print would output this string:
tblInventory.InventoryID=10036 AND tblInventory.OtherAuthors Like "*Einstein*"
Variations on that might be more useful to you, i.e., you might want to have an optional concatenation operator (so you could have OR), but I'd likely do that by constructing a succession of WHERE strings and concatenating them with OR line by line in code, since you'd likely want to place your parentheses carefully to make sure the AND/OR priority is properly executed.
Now, none of this really addresses the concatenation of VALUES for an INSERT statement, but I question how often you're actually inserting literal values in an Access app. Unless you're using an unbound form for inserting records, you will be using a form to insert records, and thus no SQL statement at all. So, for VALUES clauses, it seems that in an Access app you shouldn't need this very often. If you are finding yourself needing to write VALUES clauses like this, I'd suggest you're not using Access properly.
That said, you could use something like this:
Public Sub ConcatenateValues(ByRef strValues As String, _
intDatatype As Integer, varValue As Variant)
Dim strValue As String
If Len(strValues) > 0 Then
strValues = strValues & ", "
End If
Select Case intDatatype
Case dbChar, dbMemo, dbText
' you might want to change this to escape internal double/single quotes
strValue = Chr(34) & varValue & Chr(34)
Case dbDate, dbTime
strValue = "#" & varValue & "#"
Case dbGUID
' this is only a guess
strValues = Chr(34) & StringFromGUID(varValue) & Chr(34)
Case dbBinary, dbLongBinary, dbVarBinary
' numeric?
Case dbTimeStamp
' text? numeric?
Case Else
' dbBigInt , dbBoolean, dbByte, dbCurrency, dbDecimal,
' dbDouble, dbFloat, dbInteger, dbLong, dbNumeric, dbSingle
strValue = varValue
End Select
strValues = strValues & strValue
End Sub
...which would concatenate your values list, and then you could concatenate into your whole SQL string (between the parens of the VALUES() clause).
But as others have said, it's probably better to utilize parameters in the first place.
FWIW, I use a slightly different format, using Access's line break character "_". I also use the concatenation operator "&". The main reason is for readability:
Dim db as Database: Set db = Current Db
Dim sql$
sql= "INSERT INTO MyTable (Field1, Field2, Field3 ...Fieldn) " & _
"VALUES (" & _
Me.TextMyField1 & _
"," & Me.TextMyField2 & _
"," & Me.TextMyField3 & _
...
"," & Me.TextMyFieldn & _
");"
db.Execute s
Set db = nothing
I would use the approach above, with each parameter on a separate line it is nice and easy to debug and add to.
If however you really did not like that way then you could look at a parameter query. Slightly less flexible but in some cases slightly quicker.
Or another way would be to define a public function for inserting into that table and pass the values to it as parameters.
I however would stick with what you have got but it would be nice if VBA would understand =+
One of the things I've done in the past is create a system for parsing SQL code to find parameters and storing the parameters in a table. I would write my MySQL queries outside of Access. Then all I had to do was open the file from Access and it would be ready to be updated on the fly each time I wanted to run it.
It was a really complicated process, but I'd be happy to dig up the code next week when I get back to work if you're interested.