Friend of Kim
Friend of Kim

Reputation: 860

Access VBA: Query returns no rows

I've written some VBA:

For x = LBound(resProdID) To UBound(resProdID)
    CurrentDb.QueryDefs("qry_findID_vba").SQL = "" & _
    "SELECT tbl_products.ProdID " & _
    "FROM tbl_products " & _
    "WHERE (tbl_products.Size = " & resSize(x) & " " & _
    "AND tbl_products.SupplID = '" & Forms.frm_suppliers.SupplID & "')"

    Dim dbs As DAO.Database
    Dim rst As DAO.Recordset

    Set dbs = CurrentDb()
    Set rst = dbs.OpenRecordset("qry_findID_vba")

    MsgBox rst.RecordCount

    If rst.RecordCount <> 0 Then
        rst.MoveLast
        rst.MoveFirst

        newProdID(x) = rst.Fields(0).Value
        MsgBox "This never fires"
     End If

    rst.Close
    Set rst = Nothing
    dbs.Close
    Set dbs = Nothing
Next x

What happens when I run it, is that a box pops up saying 0. I click Ok, and it repeats one more time. This is because I have two items in my resProdID-array.

However, if I open the query "qry_findID_vba" normally, it shows one row, like I expected.

Why doesn't VBA return this row? Have I done anything wrong?

Upvotes: 0

Views: 6591

Answers (2)

Tomalak
Tomalak

Reputation: 338128

First off, you really should use QueryDef parameters. They provide a number of benefits:

  • A safety net against malformed input and SQL injection.
  • You don't need to redefine the query SQL text every time a parameter value changes.
  • They make your VBA independent of the query text. This is a simple query, but more complex ones benefit if you don't have to change your VBA code just to change the SQL.
  • They provide type safety - you can use typed variables in VBA and be sure that the query cannot fail with data type errors.
  • They can be re-used - parameterized queries can be bound to forms, or executed directly, for example.
  • Last but not least, it looks much nicer and clearer when used in VBA.

Your situation is exactly what parameterized QueryDefs are for.

Change the query text of qry_findID_vba in Access to:

PARAMETERS [ProductSize] Text (255), [SupplID] Number;
SELECT ProdID
FROM tbl_products
WHERE [tbl_products].[Size] = [ProductSize] AND [tbl_products].[SupplID] = [SupplID];

Replace the parameter data types according to your actual data types in the table.

Next, when you're in a loop, don't re-define fixed variables again and again. dbs and rst don't need to be defined inside the loop at all.

Last point, the RecordCount property does not work the way you think. Quote from the docs, emphasis mine:

Use the RecordCount property to find out how many records in a Recordset or TableDef object have been accessed. The RecordCount property doesn't indicate how many records are contained in a dynaset–, snapshot–, or forward–only–type Recordset object until all records have been accessed. [...] To force the last record to be accessed, use the MoveLast method on the Recordset object.

Instead of calling MoveLast, you can also check the .EOF property. If it is false, at least one record is available.

For one-off query results like this one, I would recommend using the snapshot type Recordset. You can define which type you want to use when you call OpenRecordset on the QueryDef.

Now:

Dim qry_findID_vba As DAO.QueryDef 
Set qry_findID_vba = CurrentDb().QueryDefs("qry_findID_vba")

qry_findID_vba.Parameters("SupplID") = Forms.frm_suppliers.SupplID

For x = LBound(resProdID) To UBound(resProdID)
    qry_findID_vba.Parameters("ProductSize") = resSize(x)

    With qry_findID_vba.OpenRecordset(dbOpenSnapshot)
        If Not .EOF Then 
            newProdID(x) = .Fields("ProdID").Value 
        End If
    End With
Next x

Note that I use With to save maintaining a helper rst variable.

Upvotes: 1

Lynn Crumbling
Lynn Crumbling

Reputation: 13357

Does this code messagebox the correct count? Can you use it instead? (Note, I haven't actually run it, so watch out for slight syntax errors.)

For x = LBound(resProdID) To UBound(resProdID) 
    Dim sql as String
    Dim rst As DAO.Recordset 
    sql = "Select tbl_products.ProdID FROM tbl_products " & _
          "WHERE (tbl_products.Size = " & resSize(x) & " " & _
          "AND tbl_products.SupplID = '" & Forms.frm_suppliers.SupplID & "')" 
    Set rst = dbs.OpenRecordset(sql)
    if not rst.eof then 
        MsgBox rst.fields("ProdID")    
    else
        Msgbox "None found!"
    end if
    rst.Close 
    Set rst = Nothing 
Next x 

Also, try copying everything to a new form, and compacting and repairing the database ...

Upvotes: 1

Related Questions