逃逸';在Access SQL中
我尝试在vba中使用以下内容进行域查找:逃逸';在Access SQL中,sql,vba,ms-access,escaping,Sql,Vba,Ms Access,Escaping,我尝试在vba中使用以下内容进行域查找: DLookup("island", "villages", "village = '" & txtVillage & "'") 在txtVillage类似于Dillon's Bay之前,这一切都很好,当撇号被视为一个单引号时,我得到了一个运行时错误 我编写了一个不需要单引号的简单函数,它用“.”替换“.”。这似乎是经常出现的问题,但我找不到任何对具有相同功能的内置函数的引用。我错过什么了吗?比你想象的更糟。想一想如果有人输入这样的值,而
DLookup("island", "villages", "village = '" & txtVillage & "'")
在txtVillage类似于Dillon's Bay之前,这一切都很好,当撇号被视为一个单引号时,我得到了一个运行时错误
我编写了一个不需要单引号的简单函数,它用“.”替换“.”。这似乎是经常出现的问题,但我找不到任何对具有相同功能的内置函数的引用。我错过什么了吗?比你想象的更糟。想一想如果有人输入这样的值,而您没有逃过任何惩罚,会发生什么:
'); DROP TABLE [YourTable]
不漂亮
没有简单转义撇号的内置函数的原因是,正确的处理方法是使用查询参数。对于Ole/Access样式的查询,您可以将其设置为查询字符串:
DLookup("island", "village", "village = ? ")
然后分别设置参数。不过,我不知道如何从vba设置参数值。顺便说一句,这是我的EscapeQuotes函数
Public Function EscapeQuotes(s As String) As String
If s = "" Then
EscapeQuotes = ""
ElseIf Left(s, 1) = "'" Then
EscapeQuotes = "''" & EscapeQuotes(Mid(s, 2))
Else
EscapeQuotes = Left(s, 1) & EscapeQuotes(Mid(s, 2))
End If
End Function
“Replace”函数应该可以做到这一点。根据上述代码:
DLookup("island", "villages", "village = '" & Replace(txtVillage, "'", "''") & "'")
我相信access可以使用Chr$(34)并且很高兴在里面有单引号/撇号。
乙二醇 尽管如此,你还是要逃过chr$(34)(“”) 您可以使用Replace函数
Dim escapedString as String
escapedString = Replace(nonescapedString, "'", "''")
虽然像DLookup这样的速记域函数很吸引人,但它们也有缺点
SELECT FIRST(island)
FROM villages
WHERE village = ?;
如果您有多个匹配的候选项,它将选择“第一个”,对于Jet/ACE引擎IIRC,“第一个”的定义依赖于实现(SQL引擎),并且未定义。您知道哪一个将是第一个吗?如果您不这样做,请避开DLookup:)
[出于兴趣,Jet/ACE的答案将是基于上次压缩数据库文件时的clusterd索引的最小值或第一个(有效时间)如果数据库从未压缩过,则插入值。如果存在唯一约束或在非空列上定义的索引,则聚集索引依次由PRIAMRY键确定,否则为第一个(有效时间)插入的行。如果在非空列上定义了多个唯一约束或索引,那么哪一个将用于群集?我不知道!我相信您会认为“第一个”不容易确定,即使您知道如何确定!]
我还看到了Microsoft的建议,即从优化的角度避免使用域聚合函数:
有关Access数据库中查询性能的信息
“避免使用域聚合函数,例如DLookup函数。。。Jet数据库引擎无法优化使用域聚合函数的查询“
如果您选择使用查询重新编写,则可以利用参数语法,或者您可能更喜欢Jet 4.0/ACE过程语法,例如
CREATE PROCEDURE GetUniqueIslandName
(
:village_name VARCHAR(60)
)
AS
SELECT V1.island_name
FROM Villages AS V1
WHERE V1.village_name = :village_name
AND EXISTS
(
SELECT V2.village_name
FROM Villages AS V2
WHERE V2.village_name = V1.village_name
GROUP
BY V2.village_name
HAVING COUNT(*) = 1
);
通过这种方式,您可以使用引擎自己的功能——或者至少是它的数据提供程序的功能——来转义所有字符(而不仅仅是双引号和单引号)必要时。像Joel Coehoorn建议的参数化查询是一种方法,而不是在查询字符串中进行串联。首先-避免某些安全风险,其次-我合理地确定它需要转义到引擎自己手中,您不必担心这一点。对于那些在单引号和d替换功能,此行可能会节省您的时间^o^
Replace(result, "'", "''", , , vbBinaryCompare)
在可能有撇号的条件周围放上括号 比如:
DLookup("island", "villages", "village = '[" & txtVillage & "]'")
它们可能需要在单引号之外,或者在TXT村庄附近,如:
DLookup("island", "villages", "village = '" & [txtVillage] & "'")
但是如果你找到了正确的组合,它将处理撇号
Keith B我的解决方案更简单。最初,我使用此SQL表达式创建ADO记录集:
Dim sSQL as String
sSQL="SELECT * FROM tblTranslation WHERE fldEnglish='" & myString & "';"
当myString
中有一个撇号时,就像国际电气公司一样,我的程序就会停止。使用双引号解决了这个问题
sSQL="SELECT * FROM tblTranslation WHERE fldEnglish="" & myString & "";"
但是,它应该是这样的(每个都有一个双引号): 或者我更喜欢: 创建一个函数来转义单引号,因为带“[]”的“转义”将不允许字符串中包含这些字符
Public Function fncSQLStr(varStr As Variant) As String
If IsNull(varStr) Then
fncSQLStr = ""
Else
fncSQLStr = Replace(Trim(varStr), "'", "''")
End If
End Function
我将此函数用于所有SQL查询,如SELECT、INSERT和UPDATE(以及WHERE子句中的…)
或
这就是我真正想要的。我不太使用vba,而且我觉得帮助文件也没有多大帮助!干杯。请注意,旧版本的Access(即Access 97)中似乎不存在Replace()。Replace()是在Access 2000中引入的。@David W.Fenton:只要添加一个注释来消除您对Access 2000使用的歧义,如果您同意的话:)替换()函数是在VBA6中引入的。VBA6是从Access2000开始引入Access UI的。Access数据库引擎SQL不支持“替换”函数,无论是本机还是通过Jet Expression Services。在SQL中使用replace()仅在使用Access UI时有效(尽管我承认我不知道如何使用),否则将显示语法错误…因此,最好避免使用Replace()在持久化数据库对象中,例如查询/视图/过程,尤其是验证规则和检查约束。如何单独设置参数?使用准备好的语句。请参阅或。那篇文章是关于SQL Server的,但我怀疑它可能也适用于Access。是的,因此,您现在有了双引号,而不是撇号问题-问题:-/
sSQL = "SELECT * FROM tblTranslation WHERE fldEnglish=""" & myString & """;"
Public Function fncSQLStr(varStr As Variant) As String
If IsNull(varStr) Then
fncSQLStr = ""
Else
fncSQLStr = Replace(Trim(varStr), "'", "''")
End If
End Function
strSQL = "INSERT INTO tbl" &
" (fld1, fld2)" & _
" VALUES ('" & fncSQLStr(str1) & "', '" & fncSQLStr(Me.tfFld2.Value) & "');"
strSQL = "UPDATE tbl" & _
" SET fld1='" & fncSQLStr(str1) & "', fld2='" & fncSQLStr(Me.tfFld2.Value) & "'" & _
" WHERE fld3='" & fncSQLStr(str3) & "';"