2008-10-14 100 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) & "';"