在Access/VBA中构建SQL字符串
有时,我不得不在VBA中构建一个SQL字符串,并使用在Access/VBA中构建SQL字符串,sql,ms-access,vba,Sql,Ms Access,Vba,有时,我不得不在VBA中构建一个SQL字符串,并使用Docmd.RunSql()执行它。我总是通过将变量连接到字符串中来构建这些字符串,例如: Dim mysqlstring as String mysqlstring = "INSERT INTO MyTable (Field1, Field2, Field3 ...) VALUES (" mysqlstring = mysqlstring + Me.TextMyField1 + ", " 'parameter comments mysqlst
Docmd.RunSql()
执行它。我总是通过将变量连接到字符串中来构建这些字符串,例如:
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似乎没有一元串联运算符(如+=),虽然这看起来并不理想,但至少我可以对每个参数进行注释并独立更改它们。它比一个怪物连接的字符串更容易阅读和更改。但构建SQL字符串似乎仍然是一种糟糕的方式。我有一个大约有50个参数在工作,所以有50行mysqlstring=mysqlstring+…
。不可爱
顺便说一句,这排除了使用行连续体来格式化字符串的可能性,因为存在一个(提示:小于50)。另外,VBA不允许您在行继续之后添加注释,grr
直到最近,我还认为这是构建这些字符串的唯一方法。但最近我看到了一种不同的模式,在我发布答案的字符串(如)中注入参数,我想知道VBA是否有与parameters.AddWithValue()
等效的方法,或者这是否比字符串串联方法更好。所以我认为这应该有自己的问题。也许我在这里遗漏了什么
请一些Access专家澄清在Access/VBA中构建SQL字符串的最佳实践是什么。我将使用上述方法,每个参数都在单独的一行上,很好调试和添加
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
然而,如果您确实不喜欢这种方式,那么您可以查看参数查询。灵活性稍差,但在某些情况下稍快
或者另一种方法是定义一个公共函数,用于插入到该表中,并将值作为参数传递给它
然而,我会坚持你所得到的,但是如果VBA能够理解=+那就太好了。除了@astander所说的,你可以创建一个querydef(带参数)并将其保存为数据库的一部分 e、 g 假设您使用名称
myTableInsert
保存了它,您可以编写如下代码
dim qd as QueryDef
set qd = CurrentDB.QueryDefs("myTableInsert")
qd.Parameters("dtBegin").Value = myTextFieldHavingBeginDate
qd.Parameters("dtEnd").Value = myTextFieldHavingEndDate
qd.Execute
注意:我没有测试这段代码。但是,我猜应该是这样。希望这能为您提供足够的信息以开始使用。我过去做过的一件事是创建一个系统,用于解析SQL代码以查找参数并将参数存储在表中。我会在Access之外编写MySQL查询。然后,我所要做的就是从Access打开文件,每次我想运行它时,它都可以随时更新
这是一个非常复杂的过程,但如果你感兴趣的话,我很乐意在下周回去工作时挖掘代码。我有一个时间表应用程序,带有一个相当复杂的未绑定劳动交易输入表单。有很多数据验证、速率计算等代码。我决定使用以下内容创建SQL插入/更新字段 变量strSQLInsert、strSQLValues、strSQLUpdate是表单级字符串 以下的许多行:
Call CreateSQLString("[transJobCategoryBillingTypesID]", lngJobCategoryBillingTypesID)
其次是:
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
请注意,中线删除了前导“,”。lngTrans是自动编号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
Sub-CreateSQLString(strFieldName作为字符串,varFieldValue作为变量,可选blnZeroAsNull作为布尔值)
'调用CreateSQLString(“[]”,)
Dim strFieldValue作为字符串,OutputValue作为变量
关于错误转到tagError
'如果0(零)应该为null
如果不IsMissing(blnZeroAsNull)且blnZeroAsNull=True且VARFELDVALUE=0,则
OutputValue=“Null”
'如果字段为空,则长度为零或“”
ElseIf IsNull(varFieldValue)或Len(varFieldValue)=0或varFieldValue=“””,则
OutputValue=“Null”
其他的
OutputValue=varFieldValue
如果结束
'请注意,Insert和update字符串都会更新,因为我们可能需要Insert逻辑来进行插入
'更新主事务时缺少自动生成的事务
“这是一个插页
strSQLInsert=strSQLInsert&“,”和strFieldName
strSQLValues=strSQLValues&“,”和OutputValue
这是一个更新
strSQLUpdate=strSQLUpdate&“,”&strFieldName&“=”&OutputValue
错误转到0
出口接头
标记错误:
MsgBox“Error”和Err.Number&(“&Err.Description&”)在VBA文档表单的CreateSQLString过程中
出口接头
端接头
我看到其他海报都在使用Execute方法。DoCmd.RunSQL的问题是它可以忽略错误。以下任一项都将显示查询收到的任何错误消息。如果使用DAO,则使用Currentdb。执行strSQL,dbfailonerror。。对于ADO,请使用CurrentProject.Connection.Execute strCommand、LNGRECORDSAFInfected、adCmdText,然后可以删除docmd.setwarnings行
如果要使用docmd.setwarnings,请确保在任何错误处理代码中也使用True语句。否则,以后可能会发生奇怪的事情,尤其是在您使用应用程序时。例如,如果关闭对象,您将不再收到“是否希望保存更改”消息。这可能意味着不需要的更改、删除或添加将保存到MDB中
此外,两种方法的性能也可能有显著差异。一次发布声明currentdb.execute花费了两秒钟,而docmd.runsql花费了八秒钟。正如其他人所说的那样,首先使用参数可能更好。然而 一、 同样,我们也错过了一个连接操作符,因为我们已经习惯了PHP中的。在一些情况下,我编写了一个函数来实现这一点,尽管不是专门用于连接SQL字符串的。下面是我用于为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
还有一个我称之为的例子:
AppendQueryString strOutput, "InventoryID=" & frm!InventoryID, vbNullstring
AppendQueryString strOutput, "Author=" & URLEncode(frm!Author)
…等等
现在,为了构造SQLWHERE子句
AppendQueryString strOutput, "InventoryID=" & frm!InventoryID, vbNullstring
AppendQueryString strOutput, "Author=" & URLEncode(frm!Author)
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
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
tblInventory.InventoryID=10036 AND tblInventory.OtherAuthors Like "*Einstein*"
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
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