2008-10-14 99 views
17

我试图做一个域查找在VBA像这样的东西:在Access逃逸“SQL

DLookup("island", "villages", "village = '" & txtVillage & "'") 

这工作得很好,直到txtVillage是像狄龙湾,当撇号被认为是一个单引号,我得到一个运行时错误。

我已经写了一个简单的函数来转义单引号 - 它用“''”替换“'”。这似乎是相当常见的事情,但我找不到任何对内置函数的引用。我错过了什么吗?

回答

15

“替换”功能应该做的伎俩。基于上述代码:

DLookup("island", "villages", "village = '" & Replace(txtVillage, "'", "''") & "'") 
3

这比你想象的要糟糕。想想看,如果有人输入这样的值会发生什么,并且你还没有逃脱任何事情:

'); DROP TABLE [YourTable] 

不漂亮。

没有内置函数来简单地转义撇号的原因是正确的方式来处理这是使用查询参数。对于Ole/Access样式查询,您可以将其设置为查询字符串:

DLookup("island", "village", "village = ? ") 

然后单独设置参数。不过,我不知道如何设置vba的参数值。

+0

究竟如何设置的paremeter seperately? – StockB 2013-11-29 20:00:01

+0

使用准备好的语句。请参阅http://stackoverflow.com/questions/6572448/msaccess-prepared-statements或http://technet.microsoft.com/en-us/library/aa905910(v=sql.80).aspx。那篇文章是关于SQL Server的,但我怀疑它也可能适用于Access。 – 2014-04-16 00:45:03

0

顺便说一句,这是我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 
+0

出了什么问题:EscapeQuotes = Replace(s,“'”,“''”)? – 2008-10-14 03:21:43

+0

这就是我真正要求的。我不使用vb​​a太多,我找不到帮助文件非常有帮助! 欢呼声。 – inglesp 2008-10-14 03:26:10

1

我相信访问可以使用CHR $(34),并愉快地里面有单引号/撇号。

DLookup("island", "villages", "village = " & chr$(34) & nonEscapedString & chr$(34)) 

虽然那么你不得不逃离CHR $(34)(“)

可以使用替换功能。

Dim escapedString as String 

escapedString = Replace(nonescapedString, "'", "''") 
3

虽然速记域功能如DLookup是诱人的,他们有它们的缺点,等价的Jet SQL就像

SELECT FIRST(island) 
FROM villages 
WHERE village = ?; 

如果你有多个匹配的候选者,它会选择'第一','first'的定义是依赖于实现(SQL引擎),而对于Jet/ACE引擎IIRC则是未定义的。你知道哪一个会是第一个吗?如果你不那么避开DLookup :)

[对于感兴趣的问题,Jet/ACE的答案可以是基于数据库文件上次压缩时的clusterd索引的最小值,如果数据库从未压缩,则插入值。如果在非空列上定义了UNIQUE约束或索引,否则聚集索引由PRIAMRY KEY决定,否则为第一个(有效时间)插入行。如果在NOT NULL列上定义了多个UNIQUE约束或索引,那么将使用哪一个约束或索引进行群集呢?我不知道!我相信你会明白'第一'不容易确定,即使你知道如何!]

我也从微软看到建议避免使用从一个角度优化点域聚合函数:

Access数据库 http://support.microsoft.com/kb/209126

有关查询性能的信息“避免使用域聚合函数,例如DLookup函数... Jet数据库引擎无法优化使用域聚合函数的查询“

如果您选择使用查询重写,则可以利用PARAMETERS语法,或者您可能更喜欢耶t 4.0/ACE PROCEDURE语法例如像

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 
     ); 

这样你就可以利用发动机本身的功能 - 或者至少是它的数据提供者 - 逃避所有字符(不只是双精度和单引号)是必要的。

0

参数化查询(如Joel Coehoorn建议的)是要走的路,而不是在查询字符串中进行串联。首先 - 避免某些安全风险,其次 - 我相当肯定地确定它需要转入引擎自己的手中,您不必担心这一点。

0

另外,具有单引号麻烦谁和替换功能,此行可以节约你的时间^ O ^左右可能有一个撇号在它的标准

Replace(result, "'", "''", , , vbBinaryCompare) 
0

放支架。

类似:

DLookup("island", "villages", "village = '[" & txtVillage & "]'") 

他们可能需要单引号txtVillage之外或者只是周围像:

DLookup("island", "villages", "village = '" & [txtVillage] & "'") 

但是,如果你找到正确的组合,很会照顾的撇号。

Keith B

-1

我的解决方案非常简单。本来,我用这个SQL表达式来创建ADO记录:

Dim sSQL as String 
sSQL="SELECT * FROM tblTranslation WHERE fldEnglish='" & myString & "';" 

myString曾在它撇号,像国际电工,我的程序将停止。用双引号解决了这个问题。

sSQL="SELECT * FROM tblTranslation WHERE fldEnglish="" & myString & "";" 
1

但后来,它应该是这样的(多一个双引号每个):

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子句中......)

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) & "';"