0

私はいくつかの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

実行すると、ボックスがポップアップして 0 と表示されます。[OK] をクリックすると、もう一度繰り返されます。これは、resProdID 配列に 2 つの項目があるためです。

しかし、クエリ「qry_findID_vba」を開くと、期待どおりに1行が表示されます。

VBA がこの行を返さないのはなぜですか? 私は何か悪いことをしましたか?

4

2 に答える 2

1

まず、本当に QueryDef パラメータを使用する必要があります。それらには多くの利点があります。

  • 不正な入力と SQL インジェクションに対するセーフティ ネット。
  • パラメータ値が変更されるたびにクエリ SQL テキストを再定義する必要はありません。
  • それらは、VBA をクエリ テキストから独立させます。これは単純なクエリですが、SQL を変更するためだけに VBA コードを変更する必要がない場合は、より複雑なクエリが役立ちます。
  • それらはタイプ セーフを提供します。VBA で型指定された変数を使用でき、クエリがデータ型エラーで失敗しないようにすることができます。
  • それらは再利用できます。たとえば、パラメーター化されたクエリをフォームにバインドしたり、直接実行したりできます。
  • 最後になりましたが、VBA で使用すると、見栄えがよくなり、見栄えがよくなります。

あなたの状況は、まさにパラメーター化された QueryDefs の目的です。

qry_findID_vbaAccessのクエリ テキストを次のように変更します。

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

テーブル内の実際のデータ型に従って、パラメーターのデータ型を置き換えます。

次に、ループに入っているときは、固定変数を何度も再定義しないでください。ループ内で定義する必要はまったくありませんdbsrst

最後のポイント、RecordCountプロパティはあなたが思うようには機能しません。docs からの引用、強調鉱山:

このプロパティを使用して、RecordCountアクセスされた Recordset または TableDef オブジェクトのレコード数を確認します。RecordCount プロパティは、すべてのレコードがアクセスされるまで、 ダイナセット、スナップショット、または前方スクロール タイプのRecordset オブジェクトに含まれるレコードの数を示しません。 [...] 最後のレコードへのアクセスを強制するには、 Recordset オブジェクトで メソッドを使用します。MoveLast

を呼び出す代わりに、プロパティMoveLastを確認することもでき.EOFます。false の場合、少なくとも 1 つのレコードが利用可能です。

このような 1 回限りのクエリ結果については、スナップショット タイプの Recordset を使用することをお勧めします。QueryDefを呼び出すときに使用する型を定義できます。OpenRecordset

今:

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

Withヘルパーrst変数を維持するために使用することに注意してください。

于 2012-10-01T14:56:38.923 に答える
1

このコードのメッセージボックスは正しいカウントですか? 代わりに使えますか?(注、実際には実行していないので、わずかな構文エラーに注意してください。)

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 

また、すべてを新しいフォームにコピーし、データベースを圧縮して修復してみてください...

于 2012-10-01T14:05:08.460 に答える