1

I am trying to have a query written in the Microsoft Access Query designer see the selection my VBA code is making in a table.

Essentially I have the following VBA loop, it goes down the customer column in the table TBL_ForQB and executes the query "QB_Make_Model" if the customer is different a different query runs and the loop stops.

Main Problem:

How can I make the "QB_Make_Model" see the customer the VBA code is on, currently with my code it just inserts info from all the customer.

QB_Make_Model Query:

INSERT INTO InvoiceLine ( InvoiceLineDesc, FQSaveToCache )
SELECT DISTINCT t.Make_Model, 1
FROM TBL_ForQB AS t;

VBA Loop:

Dim dbs As Database
Set dbs = CurrentDb

Dim rst As Recordset
Set rst = dbs.OpenRecordset("TBL_ForQB")

Dim cust As String
Stop

rst.MoveFirst

Dim fcust As String
fcust = rst!Customer
MsgBox rst!Customer

Do Until rst.EOF
    cust = rst!Customer
    If cust = fcust Then
        DoCmd.SetWarnings False
        MsgBox "Same Customer"
        DoCmd.OpenQuery "QB_Make_Model"
    Else
        DoCmd.OpenQuery "QB_Invoice_PK"
        MsgBox "Diffeent Customer, I have Stopped and Sent to QB!"
        'fcust = rst!Customer
        'DoCmd.OpenQuery "QB_Make_Model_PK"
        'DoCmd.OpenQuery "QB_Invoice_PK"

    End If
    rst.MoveNext
Loop

NEW ISSUE

@Parfait answer seemed to work correctly, the issue now is this:

Say there are two of the same Customer records in the table "TBL_ForQB" using the new parameter the query "QB_Make_Model" matches the customer name and VBA executes it. The problem is it sends all the rows in the Make_Model column of the "TBL_ForQB" that match the customer name. And does it as many times as there are Customers with the same name.

For ex:

I have a customer named "Customer1" with 2 records each of which include one Make_Model record (each) in the table "TBL_ForQB". The new VBA code will run and execute the Query "QB_Make_Model", which will match the Customer parameter but insert both records of "QB_Make_Model" for every time there is a customer record.

See the issue?

  • Do you get any error log. If so, please post that. – Bussller Jan 29 '19 at 14:40
  • No error log, I just want my query to see what customer the VBA loop is currently on and only execute the query task on that customer, not the whole list –  Jan 29 '19 at 14:44
  • I can't answer specifically because it's been forever since I've done it, but you need to add a WHERE clause in your query and then you need to pass your fcust to the query as a parameter. Something sorta like what they're doing here: https://stackoverflow.com/a/24535025/2174085. Hopefully someone can post the specific code necessary, or maybe you can figure it out yourself. Sorry, that's the best I can do right now! – Johnny Bones Jan 29 '19 at 14:57
  • @RussellB any suggestions? –  Jan 29 '19 at 15:09
  • You should not select the customers by name but by [primary key](https://en.wikipedia.org/wiki/Primary_key). Every table must have one. In Access usually a Autonumber. Then instead of using a textbox for the customer selection, use a [ComboBox that looks up this primary key](https://www.techonthenet.com/access/comboboxes/bind_index2013.php). – Olivier Jacot-Descombes Jan 30 '19 at 13:29

3 Answers3

2

You can try to modify your query to accept a parameter, and pass that parameter using DoCmd.SetParameter.

Modified query with a parameter:

PARAMETERS pCustomer CHAR(255);
INSERT INTO InvoiceLine ( InvoiceLineDesc, FQSaveToCache )
SELECT DISTINCT t.Make_Model, 1
FROM TBL_ForQB AS t
WHERE Customer = pCustomer;

Modified VBA to pass the parameter:

Dim dbs As Database
Set dbs = CurrentDb

Dim rst As Recordset
Set rst = dbs.OpenRecordset("TBL_ForQB")

Dim cust As String
Stop

rst.MoveFirst

Dim fcust As String
fcust = rst!Customer
MsgBox rst!Customer

Do Until rst.EOF
    cust = rst!Customer
    If cust = fcust Then
        DoCmd.SetWarnings False
        MsgBox "Same Customer"
        DoCmd.SetParameter "pCustomer", cust
        DoCmd.OpenQuery "QB_Make_Model"
    Else
        DoCmd.OpenQuery "QB_Invoice_PK"
        MsgBox "Diffeent Customer, I have Stopped and Sent to QB!"
        'fcust = rst!Customer
        'DoCmd.OpenQuery "QB_Make_Model_PK"
        'DoCmd.OpenQuery "QB_Invoice_PK"

    End If
    rst.MoveNext
Loop

You can read more about using parameters in VBA in this answer. I recommend the DAO approach over an approach relying on DoCmd statements.

Erik A
  • 31,639
  • 12
  • 42
  • 67
  • This is an interesting approach, but now I am getting an error saying "The object doesn't contain the Automation object 'customer-test1'. –  Jan 29 '19 at 15:31
  • I don't have a clue what that is. You haven't shared anything about an object called _customer-test1_. – Erik A Jan 29 '19 at 15:37
  • “Customer-test1” is the name of the first customer from the table “TBL_ForQB”. –  Jan 29 '19 at 15:38
  • Oh, try the current edit in that case (the query has been adjusted to define the parameter type) – Erik A Jan 29 '19 at 15:42
  • 1
    Shouldn't it be `PARAMETERS pCustomer Text(255); – Olivier Jacot-Descombes Jan 29 '19 at 15:46
  • @Olivier Per [this doc page](https://learn.microsoft.com/en-us/office/client-developer/access/desktop-database-reference/equivalent-ansi-sql-data-types), `CHAR` is the normal type for character data, and `TEXT(n)` is a synonym. Both are okay and should work. I've noted incompatibilities when mixing synonyms in the parameters declaration, though, so I tend to try to avoid them. – Erik A Jan 29 '19 at 15:51
  • @ErikvonAsmuth The same error is still coming up , and the debugger is highlighting the line " DoCmd.SetParameter "pCustomer", cust " –  Jan 29 '19 at 16:08
  • Seems improbable, I've used code like this in many places. Are you sure you've included `Dim cust As String` in the same sub/function? Else this won't work – Erik A Jan 29 '19 at 16:26
0

Since you cannot pass the customer as parameter to DoCmd.OpenQuery, you will need another approach, like opening a Report or a Form in DataSheet View

Dim filter AS String

filter = "Customer=""" & fcust & """" 'Assuming String type
DoCmd.OpenForm "frmMakeModel", View:=acFormDS, WhereCondition:=filter, DataMode:=acFormReadOnly

Or if Customer is a Long id:

filter = "Customer=" & fcust 'Assuming Long type

The Form's or Report's Record Source must then be an appropriate query containing a Customer column in the SELECT list.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
  • 1
    The query is an action query, I don't think the _WhereCondition_ argument works for that. Also, you can use `DoCmd.SetParameter` with `DoCmd.OpenQuery` to use parameters (either in the query itself or the _WhereCondition_ argument) – Erik A Jan 29 '19 at 15:08
  • @ErikvonAsmuth can you elaborate on what you are suggesting? How can this be done? –  Jan 29 '19 at 15:11
  • 1
    @AndrewG I've posted an alternate answer, I could improve it if you'd post your table design to explicitly state parameter type. – Erik A Jan 29 '19 at 15:20
  • @ErikvonAsmuth, Can `DoCmd.OpenQuery` to execute an action query? Btw. this is almost the same question as [How can I make this loop work for a table with multiple customers?](https://stackoverflow.com/questions/54410530/how-can-i-make-this-loop-work-for-a-table-with-multiple-customers/54410622#54410622) where table and query details are missing. – Olivier Jacot-Descombes Jan 29 '19 at 15:31
  • 1
    @OlivierJacot-Descombes Yes, if you choose `acViewNormal` and specify an action query, `DoCmd.OpenQuery` will execute the action query and not visibly open it. It will show a prompt unless that's suppressed by `DoCmd.SetWarnings False` (like it is in this case) – Erik A Jan 29 '19 at 15:39
  • Good to know! The [documentation](https://learn.microsoft.com/en-us/office/vba/api/access.docmd.openquery) seems not to be correct then. It says: "You can use the OpenQuery method to open a select or crosstab query...". – Olivier Jacot-Descombes Jan 29 '19 at 15:41
0

Consider also the QueryDefs approach for passing the customer name parameter to action query, requiring no DoCmd calls including DoCmd.SetWarnings.

SQL (using PARAMETERS with added column for Customer)

PARAMETERS C_Param TEXT(255), P_Param LONG;
INSERT INTO InvoiceLine (InvoiceLineDesc, FQSaveToCache )
SELECT DISTINCT t.Make_Model, 1
FROM TBL_ForQB AS t
WHERE Customer = C_Param
AND ProjectID = P_Param;

Also, you may want to maintain Customer column (ideally its ID) in the InvoiceLine table which can be populated by same parameter.

VBA

Dim dbs As Database
Dim qdef As QueryDef                  ' NEW OBJECT
Dim rst As Recordset
Dim cust As String, fcust As String

Set dbs = CurrentDb
Set qdef = CurrentDb.QueryDefs("QB_Make_Model")
Set rst = dbs.OpenRecordset("TBL_ForQB")

rst.MoveFirst    
fcust = rst!Customer
MsgBox rst!Customer

Do Until rst.EOF
    cust = rst!Customer
    If cust = fcust Then        
        MsgBox "Same Customer"
        qdef!C_Param = cust 
        qdef!C_Param = rst!ProjectID 
        qdef.Execute dbFailOnError
    Else
        dbs.Execute "QB_Invoice_PK"
        MsgBox "Different Customer, I have Stopped and Sent to QB!"
    End If
    rst.MoveNext
Loop

rst.Close 
Set rst = Nothing: Set qdef = Nothing: Set dbs = Nothing
Parfait
  • 104,375
  • 17
  • 94
  • 125
  • This is a good reason why you should use *CustomerIDs* (unique identifiers) and not customer name. Is there not such an ID in *TBL_ForQB*? – Parfait Jan 29 '19 at 20:09
  • Well its a bit more complicated than that actually and I would greatly appreciate your help, basically there are three columns I care about in TBL_ForQB: 'ProjectID' , 'Customer' and 'Make_Model' , but the way TBL_ForQB is set up there can be multiple rows of very similar data. –  Jan 29 '19 at 20:46
  • Is it possible to have the query and vba only focus on the row the VBA code is currently on? Perhaps setting some sort of parameters for it to only strictly read row by row from the table? –  Jan 29 '19 at 20:52
  • Why not use *Customer* name AND *ProjectID* or *Make_Model*? Whatever makes unique records? BTW - this is table/database design issue. One should usually ever use integer IDs when relating tables and not ever string values/proper names of data points. – Parfait Jan 29 '19 at 20:55
  • I will consider that, how can I modify the code, to make sure there is one Make_Model used in the INSERT query per Customer and ProjectID? –  Jan 29 '19 at 21:02
  • See what I mean? –  Jan 29 '19 at 21:08
  • Your [other question](https://stackoverflow.com/q/54428429/1422451) was more clearer. See updated SQL and VBA passing both *ProjectID* and *Customer* as parameters into query. – Parfait Jan 29 '19 at 21:20