2009-06-19 5 views
2
set recordsetname = databasename.openrecordset(SQLString) 
    if recordsetname.bof <> true and recordsetname.eof <> true then 
    'do something 
    end if 

2 вопроса:Почему чрезвычайно изредка будет один из кислородных конвертеров/ВФ быть верным для новой непустой записей

  1. выше тест может оценить ложь неправильно, но только крайне редко (I» у меня был один скрытый в моем коде, и он провалился сегодня, я считаю, что впервые за 5 лет ежедневного использования - вот как я его нашел). Почему очень редко одно из bof/eof истинно для непустого набора записей. Кажется настолько редким, что я удивляюсь, почему это происходит вообще.

  2. Является ли это несложный замена:

    if recordsetname.bof <> true or recordsetname.eof <> true then 
    

Редактировать, чтобы добавить детали код:

Клиенты имеют заказов, каждый заказ начинается с BeginOrder пункта и заканчиваться EndOrder и между ними находятся элементы в заказе.

SQL, является:

' ids are autoincrement long integers ' 
SQLString = "select * from Orders where type = OrderBegin or type = OrderEnd"   

Dim OrderOpen as Boolean 
OrderOpen = False 

Set rs = db.Openrecordset(SQLString) 
If rs.bof <> True And rs.eof <> True Then 
    myrec.movelast 
    If rs.fields("type").value = BeginOrder Then 
     OrderOpen = True 
    End If 
End If 

If OrderOpen F False Then 
    'code here to add new BeginOrder Item to Orders table ' 
End If 

ShowOrderHistory 'displays the customer's Order history ' 

В этом случае, который выглядит это это

BeginOrder 
Item a 
Item b 
... 
Item n 
EndOrder 

BeginOrder 
Item a 
Item b 
... 
Item n 
EndOrder 

BeginOrder 
Item a 
item b 
... 
Item m 

BeginOrder  <----should not be there as previous order still open 
+0

Что находится в вашем SQLSTRING? – NotMe

+0

Это просто простой выбор на одной таблице, который в случае неудачи сделал/должен был вернуть около десятка записей. – jjb

+0

«один из bof/eof be true» - вы имеете в виду xor («побитное сравнение двух выражений с использованием эксклюзивного или логического»), то есть одно верно, а другое - false? – onedaywhen

ответ

0

Узор Я всегда использовал это:

Set rs = db.OpenRecordset(...) 

Do while Not rs.EOF 

    ' Rest of your code here. 

    rs.MoveNext 
Loop 

Я никогда не видел этого терпеть неудачу (все же!). Это описано здесь: How to: Detect the Limits of a DAO Recordset

В качестве альтернативы могут быть интересны ловушки VBA Аллена Брауна: Working with Recordsets.

+0

благодарит Митча, я считаю, что ваш ответ подразумевает, что он никогда не верен для непустого набора записей (так как нет movefirst), и это также подразумевает, что eof никогда не будет истинным или петля не будет введена, так что это то же самое, что и мой, который, как я думал, никогда не потерпит неудачу, но, похоже, имеет. – jjb

+0

Можете ли вы сузить точные обстоятельства? Я никогда не видел этого с DAO (2.7 +) –

+0

Митч, я не гений по логике, так что исправьте меня, если я ошибаюсь. Пусть Bof - T1 и «NOT bof» F1 и eof T2 и «NOT eof» F2. Таким образом, мое условие, которое оказалось неудачным, - это (F1 и F2). Аллен Браун защищает «Not (T1 AND T2)», который включает в себя 3 возможности (F1 AND F2), (F1 и T1) и (T1 и F2). Поэтому он полагает, что либо bof, либо eof может встречаться в непустом наборе записей. Кстати, я считаю, что «NOT (T1 AND T2)» эквивалентно (F1 ИЛИ F2). Это верно? – jjb

3

В документации четко сказано, что, если вы откроете Recordset, который не имеет записей:

  • BOF будет истинным
  • EOF будет истинным
  • RecordCount будет 0

Для непустого Recordset, ни BOF, так и EOF верны, пока вы не перейдете за первую или последнюю запись.

Может быть, кто-то еще мог добавить/удалить запись в одну из таблиц в наборе записей, который вы только открываете и меняете набор результатов?
Это может быть результат гонки.

Вместо использования BOF или EOF, вы можете проверить на Recordcount: это всегда 0 если записи пусты.
Если набор записей не пуст, он, как правило, возвращает 1 сразу после открытия набора записей; Recordcount не является дорогостоящей операцией в этом случае.
Единственный способ действительно вернуть номер, чтобы указать номер MoveLast, прежде чем звонить Recordcount, чтобы заставить все записи быть загружены.

Обычно, если мне нужно перебирать в результирующем только для чтения моды:

Dim db as DAO.Database 
Dim rs as DAO.RecordSet 

Set db = CurrentDB() 
Set rs = db.OpenRecordSet("...", dbOpenForwardOnly) 
If Not (rs Is Nothing) Then 
    With rs 
     Do While Not .EOF 
      ' Do stuff ' 
      .MoveNext 
     Loop 
     .Close 
    End With 
    Set rs = Nothing 
End If 
Set db = Nothing 

Если мне не нужно перебирать записи, но просто проверить, если что-то было возвращено:

Set rs = db.OpenRecordSet("...", dbOpenForwardOnly) 
If Not (rs Is Nothing) Then 
    With rs 
     If .RecordCount > 0 Then 
      ' We have a result ' 
     Else 
      ' Empty resultset ' 
     End If 
     .Close 
    End With 
    Set rs = Nothing 
End If 
Set db = Nothing 

Это довольно оборонительно, и вам приходится приспосабливаться к вашим обстоятельствам, но он работает правильно каждый раз.

Что касается вашего 2 вопроса, тестирование (BOF Или EOF) после открытия записей должны быть более надежными, чем версия And, хотя я бы использовать Recordcount сам.

Редактировать после вашего пересмотренного вопроса:

Из кусочка коды вы добавили на ваш вопрос, я вижу несколько вопросов, главный из которых, что ваш SQL заявление отсутствует и ORDER BY положения.
Проблема заключается в том, что вы ожидаете, что набор результатов будет в Begin Order, а затем в последовательности End Order, но ваш SQL-запрос не гарантирует этого.
В большинстве случаев, так как вы используете автоинкрементный как ID, ядро ​​базы данных будет возвращать данные в этом естественном порядке, но нет никакой гарантии, что:

  • Это всегда будет происходить таким образом
  • Что исходные данные были сохранены в ожидаемой последовательности, что привело к идентификаторам, которые находятся в «неправильном» порядке.

Итак, всякий раз, когда у вас есть ожидания относительно последовательности набора результатов, вы должны явно заказать его.

Я хотел бы также реорганизовать этот бит кода:

' ids are autoincrement long integers ' 
SQLString = "select * from Orders where type = OrderBegin or type = OrderEnd"   

Dim OrderOpen as Boolean 
OrderOpen = False 

Set rs = db.Openrecordset(SQLString) 
If rs.bof <> True And rs.eof <> True Then 
    myrec.movelast 
    If rs.fields("type").value = BeginOrder Then 
     OrderOpen = True 
    End If 
End If 

В отдельную функцию аналогично:

' Returns true if the given CustID has a Open Order, ' 
' false if they are all closed.' 
Public Function IsOrderOpen(CustID as Long) As Boolean 
    Dim result as Boolean 
    result = False 

    Dim sql as String 
    ' Here I assume that the Orders table has a OrderDateTime field that ' 
    ' allows us to sort the order in the proper chronological sequence ' 
    ' To avoid loading the complete recordset, we sort the results in a way ' 
    ' that will return the last used order type as the first record.' 
    sql = sql & "SELECT Type " 
    sql = sql & "FROM Orders " 
    sql = sql & "WHERE ((type = OrderBegin) OR (type = OrderEnd)) " 
    sql = sql & "  AND (CustID=" & CustID & ")" 
    sql = sql & "ORDER BY OrderDateTime DESC, Type DESC;" 

    Dim db as DAO.Database 
    Dim rs as DAO.Recordset 
    Set db = CurrentDB() 
    Set rs = db.Openrecordset(sql, dbOpenForwardOnly) 

    If Not (rs Is Nothing) Then 
     If rs.RecordCount > 0 Then 
      result = (rs!type = BeginOrder) 
     End If 
     rs.Close 
    End If 

    Set rs = Nothing 
    Set db = Nothing 

    IsOrderOpen = result 
End Function 

Это сделало бы все это немного более надежным.

+0

Большое спасибо за это – jjb

+0

Рено, вы, вероятно, не поверите мне, но есть «порядок по ID» "в SQL. Причина, по которой я говорю, это то, что для меня основная проблема заключается в том, может ли непустой набор записей открыть с указателем, указывающим на любой из них или на eof, и я просто хочу исключить вариант, который, возможно, записи были возвращены в неправильном порядке. Проблема в том, что если это не так, я не вижу ответа в моем коде, чтобы это произошло. Я googled это и наткнулся на 1 или 2 других старых примерах, где это, похоже, случилось с другими. Я также запускал 800 000 симуляторов набора записей, и это не произошло однажды. – jjb

+0

Я действительно просто надеялся, что смогу закрыть эту ошибку с объяснением, что это вызвано выражением rs.bof <> true и rs.eof < > true , оценивая значение false, когда присутствовали актуальные записи. Тогда я мог спать легче! – jjb

0

Это DAO, верно? Я больше человек ADO, но у меня есть обстоятельства (dynaset?), Где вам нужно ориентироваться в EOF, чтобы оценить окончательное количество строк. Может ли это быть в этом состоянии, что EOF истинно, BOF является ложным (потому что он еще не был перемещен), но как только BOF перемещается, это верно (очевидно), и EOF остается правдой. Предположительно, начальное состояние, когда ожидаются нулевые строки, - это , предположительно, чтобы быть мгновенным, но один раз в пять лет, связанный с инцидентом, связанным с уродством, означает, что вы захватили его в действительно раннем начальном состоянии?

+0

Нельзя считать, что учетная запись набора записей DAO не может быть точным. Если вам нужен точный счет, вы делаете .MoveLast. Но это не означает, что * не * взять указатель записи за конец набора записей, так что это не должно иметь никакого отношения к нему. –

+0

«Но это делает * не * берет указатель записи за конец набора записей» - да, да, для этого вы должны вызвать малоизвестный метод .MovePastEOF, который проходит мимо конца набора записей, где вы окажитесь в Гранд-отеле Гильберта, где все усилители перейдут на 11. – onedaywhen

+0

. Вы дойдете до последней записи, и когда вы на последней записи, вы не EOF. Если вы затем выпустили MoveNext, это сделает EOF истинным. Итак, я не совсем понимаю, почему вы освещаете мою точку зрения, поскольку это явно верно. –

1

Ответ @Renaud Bompuis достаточно хорош. Позвольте мне подчеркнуть, что DAO Recordcount никогда не равен нулю для непустого набора записей, и это единственное, что я когда-либо испытывал при определении того, вернул ли записи набор записей. Я использую .EOF для прокрутки записей, но не начинайте выполнять записи до тех пор, пока я не проверил, если будут возвращены записи.

+0

Похоже, что testcount - это путь для набора дао. Только один вопрос, вы думаете, что это возможно или вы когда-либо видели случай, когда набор записей dao был открыт с указателем, указывающим на bof или eof, когда набор записей не пуст? – jjb

+0

Я не тестирую BOF и EOF с наборами записей КОГДА-ЛИБО, поэтому нет, я никогда этого не видел. Я хочу сказать, что вы беспокоитесь о НЕПРАВИЛЬНОЙ ВЕЩИ и, таким образом, ошибаетесь. Во-вторых, вы тестируете два свойства, когда вы можете получить одну и ту же информацию от тестирования. Похоже, для меня это совершенно бесполезно - потеряйте BOF и EOF как методы тестирования для пустого набора записей DAO. –

+0

Спасибо, Дэвид. Я считаю, что это вызывало особую ошибку, которая меня беспокоила. Я возлагал свои надежды на оценку (rs.bof <> true AND rs.eof <> true), которая была «неправильной». Кстати, когда я планирую перенести переход с Jet на SQL-сервер на каком-то этапе, мне нужно будет перейти от DAO к ADO, и я не хочу вводить тесты, которые являются специфичными для DAO, где я могу помочь. Насколько я понимаю, значение recordcount для пустого набора записей ADO может отличаться от эквивалента DAO. Поэтому я, вероятно, займусь с NOT (rs.bof и rs.eof), чтобы код был более широко применим? – jjb

0

Here's a possible solution

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

1

я иногда попадались точно такой же ошибка доступа (было это сегодня в Access 2007, связанного с SQL сервера заднего конца) где оператор

если rst.bof и rst.eof

вычисляет false, несмотря на то, что первое представляет пустой набор записей. Когда это произошло, началось VBA, и отладчик в непосредственной панели показал, что действительно rst.bof был true, а rst.eof был прав, так что это похоже на миллисекунду, а затем исправлено, но после того, как вы проверили логику.

+0

Вы читали другие ответы? Тестирование .Recordcount = 0 для пустого набора записей DAO является более надежным и простым.Кроме того, вы можете рассмотреть разницу между TRUE и NOT FALSE. Дайте FALSE равным 0 во всех булевых представлениях, тестирование для NOT FALSE всегда будет работать более надежно, чем тестирование для TRUE. –

+0

Dan, Ваша ситуация похожа, но другая. Mine было где «bof <> true, а eof <> true» оценивалось как false, когда набор не был пустым. Это когда-либо случалось со мной, когда я использовал логическое И, а не ИЛИ в выражении, которое я разместил. Все еще наши ситуации выглядят взаимосвязанными. Это мы или доступ! DWF: Это очень интересное наблюдение и указано, что «если rs.bof» более кратким, чем «если rs.bof <> false», я бы предположил, что этого не так много. В моем собственном случае я получил привычку (без уважительной причины) писать «bof <> true», а не «bof = false». Может быть, мне нужно это изменить. – jjb

+0

Мое мнение, что это ошибка в доступе, когда асинхронный процесс возвращает управление нашему VBA-коду, прежде чем он правильно установит bof и eof. Я думаю, причина в том, что некоторые конструкции, например, если rst.bof <> false и rst.eof <> FALSE могут работать, когда другие, например, если не rst.eof, это то, что этот код скомпилирован по-разному и может изменить время. Хотя тест bof/eof «должен» работать, мой опыт в том, что он, хотя и редко, склонен к неудаче. Я заменил все мои пустые тесты набора записей, если rst.recordcount <= 0 (за Allen Browne), и это работает для DAO. – Dan

 Смежные вопросы

  • Нет связанных вопросов^_^