Другое событие NullPointerException
возникает, когда объявляется массив объектов, а затем сразу же пытается разыменовать его внутри.
String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Этот конкретный NPE можно избежать, если порядок сравнения отменяется ; а именно, использовать .equals
для гарантированного непустого объекта.
Все элементы внутри массива инициализируются их общим начальным значением ; для любого типа массива объектов, это означает, что все элементы null
.
Вы должны инициализировать элементы в массиве перед доступом или разыменованием их.
String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Функция "Замены" должна добиться цели. На основе Вашего кода выше:
DLookup("island", "villages", "village = '" & Replace(txtVillage, "'", "''") & "'")
Это хуже, чем Вы думаете. Думайте о том, что произошло бы, если бы кто-то ввел значение как это, и Вы ни из чего не вышли:
'); DROP TABLE [YourTable]
Не симпатичный.
причина там не создана в функции для простого выхода из апострофа, то, потому что корректный способ обработать это состоит в том, чтобы использовать параметры запроса. Поскольку Ole/Access разрабатывает запрос, Вы установили это как свою строку запроса:
DLookup("island", "village", "village = ? ")
И затем установленный параметр отдельно. Я не знаю, как Вы идете об установке значения параметра от vba, все же.
Хотя краткие функции домена, такие как DLookup заманчивы, у них есть свои недостатки. Эквивалентный Струйный SQL - что-то как
SELECT FIRST(island)
FROM villages
WHERE village = ?;
, Если у Вас будет больше чем один кандидат соответствия, то он выберет 'первый', определением 'первых' является реализация (механизм SQL) зависимый и неопределенный для механизма Струи/ACE IIRC. Вы знаете, какой был бы первым? Если Вы don’t тогда избегаете DLookup:)
[Для интереса, ответ для Струи/ACE или будет минимальным значением на основе кластеризованного индекса в то время, когда файл базы данных был в последний раз уплотнен или первое (допустимое время) вставленное значение, если база данных никогда не уплотнялась. Кластерный индекс в свою очередь определяется КЛЮЧОМ PRIAMRY, если процент иначе ограничение UNIQUE или индекс определил на столбцах NOT NULL, иначе первое (допустимое время) вставленная строка. Что, если бы существует больше чем одно ограничение UNIQUE или индекс, определенный на столбцах NOT NULL, какой использовался бы для кластеризации? Я понятия не имею! Я полагаю, что Вы получаете идею, которую 'сначала' не легко определить, даже когда Вы знаете как!]
я также видел совет от Microsoft для избегания использования доменных агрегатных функций с точки зрения оптимизации:
информация о производительности запросов в базе данных Access http://support.microsoft.com/kb/209126
"Избегает использования доменных агрегатных функций, таких как функция DLookup... Струйный механизм базы данных не может оптимизировать запросы, которые используют доменные агрегатные функции"
, Если Вы принимаете решение переписать использование запроса, можно тогда использовать в своих интересах синтаксис ПАРАМЕТРОВ, или можно предпочесть Струйные 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
);
Этот способ, которым можно использовать собственную функциональность механизма - или по крайней мере тот из ее поставщиков данных - для выхода из всех символов (не просто дважды - и одинарные кавычки) по мере необходимости.
Я полагаю, что доступ может использовать Chr$ (34) и счастливо иметь единственные кавычки/апострофы внутри.
, например,
DLookup("island", "villages", "village = " & chr$(34) & nonEscapedString & chr$(34))
, Хотя тогда необходимо было бы выйти из chr$ (34) (")
, можно использовать функцию Замены.
Dim escapedString as String
escapedString = Replace(nonescapedString, "'", "''")
Параметрические запросы, такие как предложенный Joel Coehoorn являются способом пойти, вместо того, чтобы делать конкатенацию в строке запроса. Сначала - избегает определенных угроз безопасности, вторых - я довольно уверен, что это берет выход в собственные руки механизма, и Вы не должны волноваться об этом.
Между прочим, вот моя функция 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, эта строка может спасти ваш день ^o^
Replace(result, "'", "''", , , vbBinaryCompare)