Экранирование 'в Access SQL - PullRequest
       29

Экранирование 'в Access SQL

21 голосов
/ 14 октября 2008

Я пытаюсь сделать поиск домена в VBA с чем-то вроде этого:

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

Это работает нормально, пока txtVillage не станет чем-то похожим на залив Диллона, когда апостроф считается одинарной кавычкой, и я получаю ошибку времени выполнения.

Я написал тривиальную функцию, которая экранирует одинарные кавычки - она ​​заменяет «» на «». Кажется, это происходит довольно часто, но я не могу найти ссылки на встроенную функцию, которая делает то же самое. Я что-то пропустил?

Ответы [ 10 ]

19 голосов
/ 14 октября 2008

Функция «Заменить» должна помочь. На основе вашего кода выше:

DLookup("island", "villages", "village = '" & Replace(txtVillage, "'", "''") & "'")
3 голосов
/ 14 октября 2008

Хотя сокращенные доменные функции, такие как DLookup, заманчивы, они имеют свои недостатки. Эквивалент Jet SQL - это что-то вроде

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

Если у вас есть более одного подходящего кандидата, он выберет «первый», определение «первый» зависит от реализации (движка SQL) и не определено для движка Jet / ACE IIRC. Вы знаете, какой из них будет первым? Если вы не держитесь подальше от DLookup :)

[Для интереса ответом для Jet / ACE будет либо минимальное значение, основанное на индексе clusterd в момент последнего сжатия файла базы данных, либо первое (допустимое время) вставленное значение, если база данных никогда не была уплотнена. Кластерный индекс, в свою очередь, определяется ключом PRIAMRY, если он присутствует, в противном случае - УНИКАЛЬНОЕ ограничение или индекс, определенный для столбцов NOT NULL, в противном случае - первая (действительное время) вставленная строка. Что если в столбцах NOT NULL определено более одного ограничения или индекса UNIQUE, какое из них будет использоваться для кластеризации? Понятия не имею! Надеюсь, вы поняли, что «первое» определить нелегко, даже если вы знаете, как!]

Я также видел совет от Microsoft, чтобы избежать использования агрегатных функций домена с точки зрения оптимизации:

Информация о производительности запросов в базе данных Access http://support.microsoft.com/kb/209126

«Избегайте использования агрегатных функций домена, таких как функция DLookup ... ядро ​​базы данных Jet не может оптимизировать запросы, использующие агрегатные функции домена»

Если вы решите переписать с использованием запроса, вы можете воспользоваться синтаксисом PARAMETERS или предпочитаете синтаксис Jet 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
       );

Таким образом, вы можете использовать собственную функциональность движка - или, по крайней мере, функции его поставщиков данных - для экранирования всех символов (не просто двойных и одинарных кавычек) по мере необходимости.

3 голосов
/ 14 октября 2008

Это хуже, чем вы думаете. Подумайте, что произойдет, если кто-то введет значение, подобное этому, и вы ничего не избежали:

'); DROP TABLE [YourTable]

Не очень.

Причина, по которой нет встроенной функции для простого экранирования, заключается в том, что правильный способ справиться с этим - использовать параметры запроса. Для запроса стиля Ole / Access вы должны установить его в качестве строки запроса:

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

А затем установите параметр отдельно. Я не знаю, как вы можете установить значение параметра из VBA.

1 голос
/ 18 июня 2013

Но тогда, это должно быть так (с еще одной двойной кавычкой):

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) & "';"
1 голос
/ 04 января 2009

Параметризованные запросы, такие как предложенный Джоэлем Кохорном, являются подходящим способом вместо конкатенации в строке запроса. Во-первых - избегает определенных рисков безопасности, во-вторых - я вполне уверен, что это уходит в руки двигателя, и вам не нужно об этом беспокоиться.

1 голос
/ 14 октября 2008

Я полагаю, что для доступа можно использовать Chr $ (34) и счастливо иметь одинарные кавычки / апострофы внутри.
например,

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

Хотя тогда вам придется убежать от chr $ (34) (")

Вы можете использовать функцию замены.

Dim escapedString as String

escapedString = Replace(nonescapedString, "'", "''")
0 голосов
/ 14 июня 2013

Мое решение намного проще. Первоначально я использовал это выражение SQL для создания набора записей ADO:

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

Когда у myString был апостроф, как у Int'l Electrics, моя программа остановилась. Использование двойных кавычек решило проблему.

sSQL="SELECT * FROM tblTranslation WHERE fldEnglish="" & myString & "";"
0 голосов
/ 05 апреля 2013

заключите скобки вокруг критериев, в которых может быть апостроф.

ТАК, как:

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

Возможно, они должны быть вне одинарных кавычек или просто рядом с txtVillage, например:

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

Но если вы найдете правильную комбинацию, она позаботится об апострофе.

Кит B

0 голосов
/ 25 февраля 2010

Для тех, у кого проблемы с одинарными кавычками и функцией Заменить, эта строка может сохранить ваш день

Replace(result, "'", "''", , , vbBinaryCompare)
0 голосов
/ 14 октября 2008

Кстати, вот моя функция 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
...